diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2e5577f --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +data/ + +Debug/ + +x64/ + +meta/ + +web/ + +*.php + +*.png + +\.htaccess + +*.db + +include/ diff --git a/Descriptor.h b/Descriptor.h new file mode 100644 index 0000000..44e0012 --- /dev/null +++ b/Descriptor.h @@ -0,0 +1,406 @@ +#pragma once +#include +#include +#include + +#include //in which we store our feature vectors +#include //for sorting + +using namespace std; +using namespace Magick; + +namespace fs = boost::filesystem; + +//Virtual base class +//Holds definitions for all common functions of descriptors, +//but should be overloaded by a child class +class Descriptor { +public: + virtual bitset<64> feature(Image* img) = 0; + + //Interpret the bitsets as integers and calculate their distance. + virtual unsigned long long distance(bitset<64> a, bitset<64> b) { + return abs(((long long)a.to_ullong() - (long long)b.to_ullong())); + }; + virtual string ToString() = 0; + virtual fs::path ToPath() { + return fs::path(this->ToString()); + } + + //should return true if a > b + virtual bool bigger(bitset<64> a, bitset<64> b) { + return true; + } + + double* CalculateDCT(Image* img) { + double pi = 3.14159265359; + img->type(GrayscaleType); + img->filterType(LanczosFilter); //fast! + img->resize(Geometry(8, 8)); //64 pixels + ssize_t n = 8; + ssize_t m = 8; + Pixels view(*img); + int numpixels = (int)(n*m); + int chan = (int)img->channels(); //should be 1, just intensity + const Quantum *p = view.getConst(0, 0, n, m); //entire image + bitset<64> retval(0); + int N = n*m; + Image* newimg = new Image(Geometry(n, m), Color("white")); + newimg->type(GrayscaleType); + Pixels conview(*newimg); + Quantum *c = conview.get(0, 0, n, m); //entire converted image + + double converted[64]; + double* q = converted; + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + double sum = 0; + int k = (j*m) + i; + const Quantum *p_s = view.getConst(0, 0, n, m); //entire image + for (ssize_t x = 0; x < m; x++) { + for (ssize_t y = 0; y < n; y++) { + int n = (x*m) + y; + double pixel = ((double)p_s[0] / QuantumRange); //rescaled from 0 to 1 + //cout << "pixel: " << pixel << endl; + sum += pixel * std::cos((pi / N)*(n + 0.5)*k); + p_s = p_s + chan; + } + } + q[0] = sum; + /*if (p[0] != 0) + retval |= bitset<64>(1); //XOR + retval <<= 1;*/ + q = q++; + p = p + chan; + + } + } + for (int i = 0; i < 64; i++) { + c[0] = converted[i] * 255.0; + c++; + } + newimg->write("Out.png"); + return converted; + } +}; + +//Average color of the image. +//the least significant 24 bits of the feature represent +//the color intensity of the average color in RGB +//with 8 bits per color. +class averageColor : public Descriptor { +public: + bitset<64> feature(Image* img) { + ssize_t n = img->columns(); + ssize_t m = img->rows(); + Pixels view(*img); + const Quantum *p = view.getConst(0, 0, n, m); //entire image + unsigned long long red = 0, green = 0, blue = 0; + float numpixels = (float)(n*m); + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + //LTR scanning + red += p[0]; + green += p[1]; + blue += p[2]; + p = p + 3; + } + } + //get the color values.. implicit cast to int + int r = ((red/numpixels) / QuantumRange) * 255; + int g = ((green/numpixels) / QuantumRange) * 255; + int b = ((blue/numpixels) / QuantumRange) * 255; + //now store all this into a bitset.. assuming 8 bits per color, if everything went correctly.. which we should check.. probably.. + bitset<64> retval(r); + retval <<= 8; + retval |= bitset<64>(g); + retval <<= 8; + retval |= bitset<64>(b); + return retval; + } + unsigned long long distance(bitset<64> a, bitset<64> b) { + //do some bit shifting magic to get ints back + int red_a = (a >> 16).to_ulong(); + int green_a = (a << (64-16) >> (64-8)).to_ulong(); + int blue_a = (a << (64-8) >> (64-8)).to_ulong(); + int red_b = (b >> 16).to_ulong(); + int green_b = (b << (64 - 16) >> (64 - 8)).to_ulong(); + int blue_b = (b << (64 - 8) >> (64 - 8)).to_ulong(); + return abs(red_a - red_b) + abs(green_a - green_b) + abs(blue_a - blue_b); + }; + string ToString() { + return "averageColor"; + } +}; + +//Counts the total number of colors +//and stores it in bit representation. +//Upper limit 16777216 +//Only uses least significant 24 bits +class numColors : public Descriptor { +public: + bitset<64> feature(Image* img) { + return bitset<64>(img->totalColors()-1); + } + string ToString() { + return "numColors"; + } +}; + +//Median descriptor. See relevant literature. +//Stores a map of the image (LTR scanned) with 1 iff +//higher than median and 0 otherwise. +class median : public Descriptor { +public: + bitset<64> feature(Image* img) { + img->type(GrayscaleType); + img->filterType(LanczosFilter); //fast resizing, should have minimal impact on accuracy + img->resize(Geometry(8, 8, 0, 0)); //64 pixels + ssize_t n = 8; + ssize_t m = 8; + Pixels view(*img); + float intensity = 0; + int numpixels = (int)(n*m); + + const Quantum *p = view.getConst(0, 0, n, m); //entire image + int* intensities = new int[numpixels]; + int index = 0; + int chan = (int)img->channels(); //should be 1, for a grayscale img + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + //LTR scanning + intensities[index] = p[0]; + p = p + chan; + index++; + } + } + //Calculate median: + sort(intensities, intensities + numpixels); + //We know where the median is going to be: + intensity = (float)(intensities[31] + intensities[32]) / 2; + bitset<64> retval(0); + const Quantum *q = view.getConst(0, 0, n, m); //entire image + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + retval <<= 1; + if (q[0] > intensity) + retval |= bitset<64>(1); + q = q + img->channels(); + } + } + return retval; + } + + //biterror + unsigned long long distance(bitset<64> a, bitset<64> b) { + int biterror = 0; + for (int i = 0; i < 64; i++) { + if (a[i] != b[i]) biterror++; + } + return biterror; + } + string ToString() { + return "median"; + } +}; + +//Sobel descriptor +//Calculates average intensity of the image with +//sobel convolution applied in both directions +class sobel : public Descriptor { +public: + bitset<64> feature(Image* img) { + //TODO: Some preprocessing for this? + //img->reduceNoise(4.0); + img->type(GrayscaleType); + + //Apply sobel convolution + img->convolve(3, sobelX); + img->convolve(3, sobelY); + + ssize_t n = img->rows(); + ssize_t m = img->columns(); + + Pixels view(*img); + const Quantum *p = view.getConst(0, 0, m, n); //entire image + unsigned long long intensity = 0; + int chan = (int)img->channels(); + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + //LTR scanning + intensity += p[0]; + //cout << p[0] << " "; + p = p + chan; + } + //cout << endl; + } + int scaledIntensity = ((float)(intensity / (n*m)) / QuantumRange) * 255; + return bitset<64>(scaledIntensity); + } + string ToString() { + return "sobel"; + } +private: + const double sobelX[9] = { 1, 0, -1, 2, 0, -2, 1, 0, -1 }; + const double sobelY[9] = { 1, 2, 1, 0, 0, 0, -1, -2, -1 }; +}; + +//Peason code +//Creates a map of the 8*8 image which has 1 +//iff the pixel is higher than the next pixel, +//0 otherwise +class pearson : public Descriptor { +public: + bitset<64> feature(Image* img) { + img->type(GrayscaleType); + img->filterType(LanczosFilter); //fast! + img->resize(Geometry(8, 8)); //64 pixels + ssize_t n = 8; + ssize_t m = 8; + Pixels view(*img); + int intensity = 0; + int numpixels = (int)(n*m); + int chan = (int)img->channels(); + const Quantum *p = view.getConst(0, 0, n, m); //entire image + bitset<64> retval(0); + int prev = p[0]; //so we always start with a 0 + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + //LTR scanning + //NOTE: Scanning order might be quite relevant for this descriptor + int cur = p[0]; + if(prev < cur) retval |= bitset<64>(1); //XOR + prev = cur; + + p = p + chan; + retval <<= 1; + } + } + return retval; + } + unsigned long long distance(bitset<64> a, bitset<64> b) { + int biterror = 0; + for (int i = 0; i < 64; i++) { + if (a[i] != b[i]) biterror++; + } + return biterror; + }; + string ToString() { + return "pearson"; + } +}; + +//Uses an adaptive thresholding algorithm on an 8*8 +//images. Re-calculates the threshold for each 2*2 +//neighbourhood and stores it in a LTR map +class threshold : public Descriptor { +public: + bitset<64> feature(Image* img) { + img->type(GrayscaleType); + img->filterType(LanczosFilter); //fast! + img->resize(Geometry(8, 8)); //64 pixels + img->adaptiveThreshold(2, 2); //Thresholding in a moving 2*2 neighborhood + ssize_t n = 8; + ssize_t m = 8; + Pixels view(*img); + int numpixels = (int)(n*m); + int chan = (int)img->channels(); + const Quantum *p = view.getConst(0, 0, n, m); //entire image + bitset<64> retval(0); + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + //LTR scanning + //cout << p[0] << " "; + if(p[0] != 0) + retval |= bitset<64>(1); //XOR + retval <<= 1; + p = p + chan; + + } + //cout << endl; + } + //cout << "----" << endl << endl; + return retval; + } + unsigned long long distance(bitset<64> a, bitset<64> b) { + int biterror = 0; + for (int i = 0; i < 64; i++) { + if (a[i] != b[i]) biterror++; + } + return biterror; + }; + string ToString() { + return "threshold"; + } +}; + +//Uses an adaptive thresholding algorithm on an 8*8 +//images. Re-calculates the threshold for each 2*2 +//neighbourhood and stores it in a LTR map +class DCTPearson: public Descriptor { +public: + bitset<64> feature(Image* img) { + img->type(GrayscaleType); + img->filterType(LanczosFilter); //fast! + img->resize(Geometry(8, 8)); //64 pixels + ssize_t n = 8; + ssize_t m = 8; + Pixels view(*img); + int numpixels = (int)(n*m); + int chan = (int)img->channels(); //should be 1, just intensity + const Quantum *p = view.getConst(0, 0, n, m); //entire image + bitset<64> retval(0); + int N = n*m; + /*Image* converted = new Image(Geometry(n, m), Color("white")); + Pixels conview(*converted); + const Quantum *q = conview.getConst(0, 0, n, m); //entire converted image*/ + + double* converted = CalculateDCT(img); + /*double* q = converted; + for (ssize_t j = 0; j < m; j++) { + for (ssize_t i = 0; i < n; i++) { + double sum = 0; + int k = (j*m) + i; + const Quantum *p_s = view.getConst(0, 0, n, m); //entire image + for (ssize_t x = 0; x < m; x++) { + for (ssize_t y = 0; y < n; y++) { + int n = (x*m) + y; + double pixel = ((double)p_s[0] / QuantumRange); //rescaled from 0 to 1 + //cout << "pixel: " << pixel << endl; + sum += pixel * std::cos((pi/N)*(n+0.5)*k); + p_s = p_s + chan; + } + } + q[0] = sum; + q = q++; + p = p + chan; + + } + //cout << endl; + }*/ + double prev = 0; + for (int i = 0; i < 64; i++) { + if (converted[i] > prev) { + retval |= bitset<64>(1); //XOR + //cout << "1"; + } + //else cout << "0"; + retval <<= 1; + prev = converted[i]; + } + //cout << "----" << endl << endl; + return retval; + } + unsigned long long distance(bitset<64> a, bitset<64> b) { + int biterror = 0; + for (int i = 0; i < 64; i++) { + if (a[i] != b[i]) biterror++; + } + return biterror; + }; + string ToString() { + return "Discrete Cosine Transform"; + } +private: + double pi = 3.14159265359; +}; \ No newline at end of file diff --git a/DescriptorManager.cpp b/DescriptorManager.cpp new file mode 100644 index 0000000..6c7cec8 --- /dev/null +++ b/DescriptorManager.cpp @@ -0,0 +1,142 @@ +#include "DescriptorManager.h" + +//Default constructor, don't use this +DescriptorManager::DescriptorManager() { + img_path = "data"; //default value +} + +//Sets image path and defines the image descriptors. +DescriptorManager::DescriptorManager(const fs::path & image_path) { + img_path = image_path; + + //Manual definitions.. SAD! + descriptor_types[6] = new DCTPearson(); + descriptor_types[5] = new threshold(); + descriptor_types[4] = new pearson(); + descriptor_types[3] = new sobel(); + descriptor_types[2] = new median(); + descriptor_types[1] = new numColors(); + descriptor_types[0] = new averageColor(); +} + +//No need to call destructor.. yet? +DescriptorManager::~DescriptorManager() { + //Do some clean-up? + //Realistically, when this gets destroyed the application is done anyway. +} + + +//Loads all images and determines the feature vectors +bool DescriptorManager::loadDescriptors() { + if (!fs::exists(img_path)) return false; + fs::directory_iterator end_itr; //last file in dir + map images; //image cache + fs::ifstream ifs; + fs::ofstream ofs; + for (int i = 0; i < numDescriptors; i++) { + //cout << "waddup " << i << endl; + //folder to store descriptors; create if not exists + fs::path descriptorBase("meta" / descriptor_types[i]->ToPath()); + if (!fs::is_directory(descriptorBase)) + if (fs::create_directory(descriptorBase)) {} + //cout << descriptorBase << " created." << endl; + + //foreach image + for (fs::directory_iterator itr(img_path); itr != end_itr; ++itr) { + fs::path featurePath(descriptorBase / itr->path().stem()); + //string image_name = featurePath.filename().generic_string(); + string image_name = itr->path().filename().generic_string(); + if (fs::exists(featurePath)) { //feature already calculated + ifs.open(featurePath, fs::fstream::binary); //in binary mode + unsigned long long n; + ifs.read(reinterpret_cast(&n), sizeof(n)); + ifs.close(); + + bitset<64> b1(n); + descriptors[i][image_name] = b1; + } + else { //feature not yet calculated + Image* image; //only load image from disk if not loaded before + if (images.count(image_name)) { //if image exists in map + image = images[image_name]; + } + else { + image = new Image; + image->read(itr->path().string()); + images[image_name] = image; + } + //cout << "Calculating " << image_name << endl; + bitset<64> b1 = descriptor_types[i]->feature(image); + //descriptor_types[i]->distance(b1, b1); + descriptors[i][image_name] = b1; + + unsigned long long n = b1.to_ullong(); + ofs.open(featurePath, fs::fstream::binary); //in binary mode; only open file after calculations have been done + ofs.write(reinterpret_cast(&n), sizeof(n)); + ofs.close(); + } + } + } + //cout << "ma qualle ide!" << endl; + /*for (map::iterator it = images.begin(); it != images.end(); ++it) { + cout << "sup?" << endl; + delete it->second; //free willy + }*/ + return true; +} + +//essentially insertion sort into a map +void DescriptorManager::similarImages(string image_name, int method, int numImages) { + bitset<64> target; + if (descriptors[method].count(image_name)) { //if image exists in map + target = descriptors[method][image_name]; + } + else { + Image* image = new Image; + image->read(image_name); //assuming http url + target = descriptor_types[method]->feature(image); + } //TODO: Add support for uploaded images + + //first we need all distances to this image.. and insert them in a sorted way + multiset > distances; //multiset is probably not needed, but who knows.. + for (map>::iterator it = descriptors[method].begin(); it != descriptors[method].end(); ++it) { + //cout << "ho " << endl; + unsigned long long d = descriptor_types[method]->distance(target, it->second); + pair p(d, it->first); + distances.insert(p); //pairs are compared by their first element.. + } + + int i = 0; + for (std::multiset>::iterator it = distances.begin(); it != distances.end() && i < numImages; ++it) { + //cout << "hey " << endl; + if (true || it->second != image_name) { + cout << it->second << endl; + i++; + } + } + + +} + +//outputs the gathered data to iostream +//can be called directly or is called by its overload +//assumes a < numDescriptors +void DescriptorManager::outputMap(int a) { + if (a != 6) return; + cout << "Outputting map " << descriptor_types[a]->ToString() << endl; + map> a_map = descriptors[a]; + if (a_map.begin() == a_map.end()) { + cout << "------------------------" << endl << "No data found" << endl << endl; + } + + for (map>::iterator it = a_map.begin(); it != a_map.end(); ++it) { + cout << it->first << " => " << it->second << " (" << it->second.to_ullong() << ")" << endl; + } +} + +//calls its buddy function to output all data to iostream +void DescriptorManager::outputMap() { + for (int i = 0; i < numDescriptors; i++) { + outputMap(i); + } +} \ No newline at end of file diff --git a/DescriptorManager.h b/DescriptorManager.h new file mode 100644 index 0000000..cc6b842 --- /dev/null +++ b/DescriptorManager.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "Descriptor.h" + +using namespace std; +using namespace Magick; + +//ENUM_STRING(descriptorss, (totalColors)(averageColor)(numDescriptors)) + +namespace fs = boost::filesystem; + +//Manager class for +class DescriptorManager { +public: + DescriptorManager(); + DescriptorManager(const fs::path & image_path); + ~DescriptorManager(); + bool loadDescriptors(); + void similarImages(string image_name, int method, int numImages); + void outputMap(int a); + void outputMap(); +private: + static const int numDescriptors = 7; //TODO: automagically update this? + map> descriptors[numDescriptors]; //array of maps that will hold the descriptors + fs::path img_path; //where the images are + Descriptor* descriptor_types[numDescriptors]; +}; + diff --git a/Enumstrings.h b/Enumstrings.h new file mode 100644 index 0000000..c03fec0 --- /dev/null +++ b/Enumstrings.h @@ -0,0 +1,27 @@ +// Have enum names be convertible to strings +// From https://stackoverflow.com/a/5094430 +// by James McNellis +// with slight adjustments +// Retrieved 14-10-2017 +#include + +#define X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE(r, data, elem) \ + case elem : return BOOST_PP_STRINGIZE(elem); + +#define ENUM_STRING(name, enumerators) \ + enum name { \ + BOOST_PP_SEQ_ENUM(enumerators) \ + }; \ + \ + inline const char* ToString(name v) \ + { \ + switch (v) \ + { \ + BOOST_PP_SEQ_FOR_EACH( \ + X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE, \ + name, \ + enumerators \ + ) \ + default: return "[Unknown " BOOST_PP_STRINGIZE(name) "]"; \ + } \ + } \ No newline at end of file diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..2968576 --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,16 @@ +JPEG descriptors - DCT +Color Layout Descriptor CLD - related to jpeg/mpeg... +Different scanning methods.. Zigzag scanning? Might matter! +Median descriptor -> Pearson code? up/down -> Local average +Color Histogram information ... Binning.. derived code +Invariance - some SIFT derived descriptor? +Combined descriptors + +Experiments + -Clear goals! -> finding near copies. dont expect too much. + -Big test! automated + -Finding near copies + -Transformations per image (scaling, cropping, text, rotation, noise, contrast, brightness, JPEG compression) + -Combinations of transformations + -Modify images -> test for invariance + -Keyword matching unlikely to work diff --git a/SmallImageDescriptors.sln b/SmallImageDescriptors.sln new file mode 100644 index 0000000..0f6ab72 --- /dev/null +++ b/SmallImageDescriptors.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SmallImageDescriptors", "SmallImageDescriptors.vcxproj", "{757D5AAF-32EE-484D-AD0D-B80A212A8870}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Debug|x64.ActiveCfg = Debug|x64 + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Debug|x64.Build.0 = Debug|x64 + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Debug|x86.ActiveCfg = Debug|Win32 + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Debug|x86.Build.0 = Debug|Win32 + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Release|x64.ActiveCfg = Release|x64 + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Release|x64.Build.0 = Release|x64 + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Release|x86.ActiveCfg = Release|Win32 + {757D5AAF-32EE-484D-AD0D-B80A212A8870}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/SmallImageDescriptors.vcxproj b/SmallImageDescriptors.vcxproj new file mode 100644 index 0000000..8d7fd72 --- /dev/null +++ b/SmallImageDescriptors.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {757D5AAF-32EE-484D-AD0D-B80A212A8870} + Win32Proj + SmallImageDescriptors + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + $(SolutionDir)\include;$(IncludePath) + $(SolutionDir)\lib;$(LibraryPath) + + + false + + + false + $(SolutionDir)\include;C:\Program Files\boost;$(IncludePath) + $(SolutionDir)\lib;C:\Program Files\boost\libs;C:\Program Files\boost\stage\lib64;$(LibraryPath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + CORE_RL_Magick++_.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + CORE_RL_Magick++_.lib;%(AdditionalDependencies) + + + copy "$(TargetPath)" "$(SolutionDir)" + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SmallImageDescriptors.vcxproj.filters b/SmallImageDescriptors.vcxproj.filters new file mode 100644 index 0000000..efc2e5a --- /dev/null +++ b/SmallImageDescriptors.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..a79f204 --- /dev/null +++ b/main.cpp @@ -0,0 +1,50 @@ +/*#include +#include +#include +#include + +#include +#include */ + +#include "DescriptorManager.h" +#include +#include +using namespace std; +using namespace Magick; + +//Methods: +//5 threshold +//4 pearson +//3 sobel +//2 median +//1 numColors +//0 averageColor + + +int main(int argc, char **argv) { + string imagename = "im71.jpg"; + int method = 2; + int count = 100; + if (argc > 2) { + method = atoi(argv[2]); + imagename = argv[1]; + } + if (argc > 3) { + count = atoi(argv[3]); + } + + else { + cout << "Usage: " << endl << argv[0] << " [fileName] [methodIndex]" << endl; + cout << "Continuing.." << endl; + } + InitializeMagick(*argv); + DescriptorManager* manager = new DescriptorManager("data"); + //cout << "Loading descriptiors.."; + manager->loadDescriptors(); + //cout << "done!" << endl << "Calculating distances.." << endl; + manager->similarImages(imagename, method, count); + //cout << "done!" << endl << "Outputting map.." << endl; + //manager->outputMap(); + + return 0; +} diff --git a/style.css b/style.css new file mode 100644 index 0000000..a89a50d --- /dev/null +++ b/style.css @@ -0,0 +1,20 @@ +body,html { + margin:0px; + padding: 10px; + background: #e5e5f4; +} + +h1, h2, h3, h4 { + color: #2d4f99; +} + +#queryImage { + float:right; + position:fixed; + right:0px; +} + +#results { + float:left; + list-style-type: none; +} \ No newline at end of file diff --git a/targetver.h b/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include