#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[7] = new DCTMedian(); 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(); mutators[0] = new Grayscale(); mutators[1] = new Flip(); mutators[2] = new Flop(); mutators[3] = new JPEG(); mutators[4] = new LowQ(); mutators[5] = new Hue(); mutators[6] = new Brighten(); } //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) { if (!itr->path().has_extension()) continue; 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; } //Loads all images and makes and stores the mutations bool DescriptorManager::createMutations() { 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; //foreach mutation for (int i = 0; i < numMutations; i++) { fs::path mutationBase(img_path / mutators[i]->ToPath()); if (!fs::is_directory(mutationBase)) if (fs::create_directory(mutationBase)) {} //foreach image int z = 0; for (fs::directory_iterator itr(img_path); itr != end_itr; ++itr) { fs::path mutPath(mutationBase / itr->path().filename().generic_string()); if (z++ > 50) break; //for quick execution //if (fs::exists(mutPath)) continue; //already exists if (!itr->path().has_extension()) continue; //skip directories Image* image = new Image(itr->path().string()); Image* mutated = mutators[i]->getMutated(image); mutated->write(mutPath.generic_string()); //now calculate all the features for the mutated images as well //foreach descriptor for (int j = 0; j < numDescriptors; j++) { //folder to store descriptors; create if not exists fs::path descriptorBase("meta" / descriptor_types[j]->ToPath() / mutators[i]->ToPath()); //cout << "Doing mutated descriptors for " << descriptorBase << endl; if (!fs::is_directory(descriptorBase)) if (fs::create_directory(descriptorBase)) {} fs::path featurePath(descriptorBase / itr->path().stem()); //cout << featurePath << endl; string image_name = itr->path().filename().generic_string(); if (!fs::exists(featurePath)) { //feature not yet calculated //cout << "Calculating " << image_name << endl; //descriptor_types[i]->distance(b1, b1); //descriptors[i][image_name] = b1; bitset<64> b1 = descriptor_types[j]->feature(mutated); unsigned long long n = b1.to_ullong(); cout << "Writing " << b1 << "(" << n << ")" << " to " << featurePath << endl; 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(); } } delete mutated; delete image; } } 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 //cout << "HEY?!" << endl; //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.. //distances.clear(); //start fresh 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->first << ", " << it->second << ")" << endl; i++; } } } //inserts the descriptors of the mutated versions of the image. //Assumes the distances array is filled with the normal distances void DescriptorManager::insertMutations(string image_name, int method) { fs::ifstream ifs; bitset<64> target; if (descriptors[method].count(image_name)) { //if image exists in map target = descriptors[method][image_name]; } cout << "Finding hits for " << image_name << " which has feature-number " << target.to_ullong() << endl; for (int i = 0; i < numMutations; i++) { fs::path descriptorBase("meta" / descriptor_types[method]->ToPath() / mutators[i]->ToPath()); fs::path imagePath(image_name); fs::path featurePath(descriptorBase / imagePath.stem()); cout << "Finding mutation for this image at: " << featurePath << endl; 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(); cout << "Number: " << n << endl; bitset<64> b1(n); unsigned long long d = descriptor_types[method]->distance(target, b1); pair p(d, mutators[i]->ToString()); distances.insert(p); } else { cout << "data not set properly" << endl; } } cout << "..." << endl; for (int i = 0; i < numMutations; i++) { int j = 0; for (std::multiset>::iterator it = distances.begin(); it != distances.end(); ++it) { //cout << "hey " << endl; if (it->second == mutators[i]->ToString()) { cout << "Hit. On the " << j << "th position: " << endl; cout << "(" << it->first << ", " << it->second << ")" << endl; } j++; } } } //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 != 2) 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); } }