diff --git a/.gitmodules b/.gitmodules index 0bb9239..54e1ad2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "husky"] path = husky url = https://github.com/husky-team/husky +[submodule "gqr"] + path = gqr + url = https://github.com/lijinf2/gqr.git diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 4cd78c3..85792ba 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(plsh) add_subdirectory(e2lsh) +add_subdirectory(e2lsh_ir) add_subdirectory(hammingrank) # add_subdirectory(srs) # add_subdirectory(iterative-coslsh) diff --git a/apps/e2lsh_ir/CMakeLists.txt b/apps/e2lsh_ir/CMakeLists.txt new file mode 100644 index 0000000..77ebf35 --- /dev/null +++ b/apps/e2lsh_ir/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories(${PROJECT_SOURCE_DIR}) +include_directories(${PROJECT_SOURCE_DIR}/husky) + +### applications +set(losha husky losha-lib ${HUSKY_EXTERNAL_LIB}) +add_executable(e2lsh_ir e2lsh_ir.cpp ) +target_link_libraries(e2lsh_ir ${losha}) diff --git a/apps/e2lsh_ir/README.md b/apps/e2lsh_ir/README.md new file mode 100644 index 0000000..5702abd --- /dev/null +++ b/apps/e2lsh_ir/README.md @@ -0,0 +1,63 @@ +# Play with E2LSH using small datasets + +We have two small datasets, which are aimed to help you get familiar with the framework. + +The two datasets, one is in .txt format, another is in binary format. The item and query in both format are the same. + +You can set the itemPath and queryPath in `losha/conf/e2lsh.conf`. By default, they are point to `losha/apps/e2lsh/data/item_ss.txt` and `losha/apps/e2lsh/data/query_ss.txt`. + + +## TXT format (default input setting in e2lsh.cpp) + +Query file: `losha/apps/e2lsh/data/item_ss.txt` + +Item file: `losha/apps/e2lsh/data/query_ss.txt` + + +### Using this dataset: + +Change `losha/conf/e2lsh.conf`, set the `itemPath` and `queryPath` correctly. Set `outputPath` correctly (which should be on HDFS). + +Change in `./e2lsh.cpp`: + +- Using `#include "small.hpp"` + +- Comment out `#include "small_binary.hpp"` + +- Using `auto& lineInputFormat ...` + +- Comment out `auto& binaryInputFormat ...` + +- Using `loshaengine ... setItemSMALL, lineInputFormat);` + +- Comment out `loshaengine ... setItemSmallBinary, binaryInputFormat);` + +In `losha/build/` directory, run `make e2lsh`. + + +## Binary format + +Query file: `losha/apps/e2lsh/data/item_ss.bin` + +Item file: `losha/apps/e2lsh/data/query_ss.bin` + + +### Using this dataset: + +Change `losha/conf/e2lsh.conf`, set the `itemPath` and `queryPath` correctly. Set `outputPath` correctly (which should be on HDFS). + +Change in `./e2lsh.cpp`: + +- Comment out `#include "small.hpp"` + +- Using `#include "small_binary.hpp"` + +- Comment out `auto& lineInputFormat ...` + +- Using `auto& binaryInputFormat ...` + +- Comment out `loshaengine ... setItemSMALL, lineInputFormat);` + +- Using `loshaengine ... setItemSmallBinary, binaryInputFormat);` + +In `losha/build/` directory, run `make e2lsh`. diff --git a/apps/e2lsh_ir/data/.gitignore b/apps/e2lsh_ir/data/.gitignore new file mode 100644 index 0000000..68e8520 --- /dev/null +++ b/apps/e2lsh_ir/data/.gitignore @@ -0,0 +1,2 @@ +wb_item +wb_query diff --git a/apps/e2lsh_ir/data/README.md b/apps/e2lsh_ir/data/README.md new file mode 100644 index 0000000..587aede --- /dev/null +++ b/apps/e2lsh_ir/data/README.md @@ -0,0 +1,15 @@ +# Notices + +`wb_item.cpp` and `wb_query.cpp` can generate binary query file and item file. + +The data in both .bin and .txt are same. Except that .bin do not contain any empty space or `\n`. + +## In .txt + +In each line (DV: value in that dimension): + + ID DV DV DV DV DV + +## In .bin + +Each chunk contains 6 integer, the first is the ID, then following 5 DV. diff --git a/apps/e2lsh_ir/data/item_ss.bin b/apps/e2lsh_ir/data/item_ss.bin new file mode 100644 index 0000000..2d5ac4c Binary files /dev/null and b/apps/e2lsh_ir/data/item_ss.bin differ diff --git a/apps/e2lsh_ir/data/item_ss.txt b/apps/e2lsh_ir/data/item_ss.txt new file mode 100644 index 0000000..45f78a2 --- /dev/null +++ b/apps/e2lsh_ir/data/item_ss.txt @@ -0,0 +1,7 @@ +2 0 0 0 0 0 +3 0 0 0 0 1 +4 0 0 0 1 0 +5 0 0 1 0 0 +6 0 1 0 0 0 +7 1 0 0 0 0 +8 1 1 1 1 1 diff --git a/apps/e2lsh_ir/data/query_ss.bin b/apps/e2lsh_ir/data/query_ss.bin new file mode 100644 index 0000000..543ae7c Binary files /dev/null and b/apps/e2lsh_ir/data/query_ss.bin differ diff --git a/apps/e2lsh_ir/data/query_ss.txt b/apps/e2lsh_ir/data/query_ss.txt new file mode 100644 index 0000000..f5a4666 --- /dev/null +++ b/apps/e2lsh_ir/data/query_ss.txt @@ -0,0 +1,2 @@ +0 0 0 0 0 0 +1 0 0 0 0 1 diff --git a/apps/e2lsh_ir/data/wb_item.cpp b/apps/e2lsh_ir/data/wb_item.cpp new file mode 100644 index 0000000..10784b4 --- /dev/null +++ b/apps/e2lsh_ir/data/wb_item.cpp @@ -0,0 +1,32 @@ +#include +#include + +int main() { + + std::ofstream outfile("item_ssb.bin", std::ofstream::binary); + + int x = 0; + int y = 1; + + for (int i = 2; i < 9; i++){ + + outfile.write(reinterpret_cast(&i), sizeof(i)); + std::cout << i << " "; + for (int j = 0; j < 5; j++){ + + if ( (i - j) == 3 ){ + outfile.write(reinterpret_cast(&y), sizeof(y)); + std::cout << y << " "; + }else if (i == 8){ + outfile.write(reinterpret_cast(&y), sizeof(y)); + std::cout << y << " "; + }else{ + outfile.write(reinterpret_cast(&x), sizeof(x)); + std::cout << x << " "; + } + } + std::cout << "\n"; + + } + +} diff --git a/apps/e2lsh_ir/data/wb_query.cpp b/apps/e2lsh_ir/data/wb_query.cpp new file mode 100644 index 0000000..925398d --- /dev/null +++ b/apps/e2lsh_ir/data/wb_query.cpp @@ -0,0 +1,29 @@ +#include +#include + +int main() { + + std::ofstream outfile("query_ssb.bin", std::ofstream::binary); + + int x = 0; + int y = 1; + + for (int i = 0; i < 2; i++){ + + outfile.write(reinterpret_cast(&i), sizeof(i)); + std::cout << i << " "; + for (int j = 0; j < 5; j++){ + + if ( i == 1 && j == 0 ){ + outfile.write(reinterpret_cast(&y), sizeof(y)); + std::cout << y << " "; + }else{ + outfile.write(reinterpret_cast(&x), sizeof(x)); + std::cout << x << " "; + } + } + std::cout << "\n"; + + } + +} diff --git a/apps/e2lsh_ir/e2lsh_ir.cpp b/apps/e2lsh_ir/e2lsh_ir.cpp new file mode 100644 index 0000000..08dccde --- /dev/null +++ b/apps/e2lsh_ir/e2lsh_ir.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2016 Husky Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include "core/engine.hpp" +#include "io/input/inputformat_store.hpp" + +#include "lshcore/lshengine.hpp" +#include "lshcore/e2lshfactory.hpp" + +#include "sift_ir.hpp" + +using namespace husky::losha; +E2LSHFactory factory; +std::once_flag factory_flag; + +void lsh() { + auto start_s = std::chrono::steady_clock::now(); + + // initialization + int band = std::stoi(husky::Context::get_param("band")); + int row = std::stoi(husky::Context::get_param("row")); + int dimension = std::stoi(husky::Context::get_param("dimension")); + int W = std::stoi(husky::Context::get_param("W")); + std::call_once(factory_flag, [&]() { + factory.initialize(band, row, dimension, W); + }); + + auto init_f = std::chrono::steady_clock::now(); + std::chrono::duration d_init = init_f - start_s; + if (husky::Context::get_global_tid() == 0) + husky::LOG_I << "Job init finishes in " + << std::to_string(d_init.count() / 1000.0) + << " seconds" << std::endl; + + // Small Dataset (txt file) + // auto& lineInputFormat = husky::io::InputFormatStore::create_line_inputformat(); + // loshaengine( + // factory, setItemSMALL, lineInputFormat); + + // Small Dataset (binary file) + //auto& binaryInputFormat = + // husky::io::InputFormatStore::create_chunk_inputformat(BytesPerVector); + //loshaengine( + // factory, setItemSmallBinary, binaryInputFormat); + + //IR + auto& binaryInputFormat = + husky::io::InputFormatStore::create_chunk_inputformat(BytesPerVector); + loshaengine( + factory, setItemSIFT1B, binaryInputFormat); + + auto query_f = std::chrono::steady_clock::now(); + std::chrono::duration d_query = query_f - init_f; + if(husky::Context::get_global_tid() == 0) + husky::LOG_I << "Job query finishes in " + << std::to_string( d_query.count() / 1000.0) + << " seconds" << std::endl; + if(husky::Context::get_global_tid() == 0) + husky::LOG_I << "E2LSH finish" << std::endl; +} + +int main(int argc, char ** argv) { + husky::LOG_I << "E2LSH program starts" << std::endl; + std::vector args; + args.push_back("hdfs_namenode"); + args.push_back("hdfs_namenode_port"); + args.push_back("band"); + args.push_back("row"); + args.push_back("dimension"); + args.push_back("queryPath"); // the inputQueryPath + args.push_back("itemPath"); // the inputItemPath + args.push_back("outputPath"); // the outputPath + args.push_back("W"); + if (husky::init_with_args(argc, argv, args)) { + husky::run_job(lsh); + return 0; + } + return 1; +} + diff --git a/apps/e2lsh_ir/e2lsh_ir.hpp b/apps/e2lsh_ir/e2lsh_ir.hpp new file mode 100644 index 0000000..be82433 --- /dev/null +++ b/apps/e2lsh_ir/e2lsh_ir.hpp @@ -0,0 +1,107 @@ +/* + * Copyright 2016 Husky Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include + +#include "core/engine.hpp" +#include "io/hdfs_manager.hpp" + +#include "lshcore/lshbucket.hpp" +#include "lshcore/lshquery.hpp" +#include "lshcore/lshitem.hpp" +using namespace husky::losha; + +template< + typename ItemIdType, + typename ItemElementType, + typename QueryMsg, + typename AnswerMsg +> +class E2LSHQuery : public LSHQuery { +public: + // explicit E2LSHQuery(const typename E2LSHQuery::KeyT& id):LSHQuery(id){} + explicit E2LSHQuery(const typename E2LSHQuery::KeyT& id):LSHQuery(id) {} + void query( + LSHFactory& fty, + const vector& inMsg) override { + this->queryMsg = this->getItemId(); + for (auto& bId : fty.calItemBuckets(this->getQuery())) { + this->sendToBucket(bId); + } + } +}; + +template< + typename ItemIdType, + typename ItemElementType, + typename QueryMsg, + typename AnswerMsg +> +class E2LSHItem : public LSHItem { +public: + // explicit E2LSHItem(const typename E2LSHItem::KeyT& id):LSHItem(id){} + explicit E2LSHItem(const typename E2LSHItem::KeyT& id):LSHItem(id){} + + virtual void answer( + LSHFactory& factory, + const vector& inMsgs) { + + std::unordered_set evaluated; + for (auto& queryId : inMsgs) { + + if (evaluated.find(queryId)!= evaluated.end()) continue; + evaluated.insert(queryId); + + // get broadcasted value + auto& queryVector = + factory.getQueryVector(queryId); + float distance = factory.calDist(queryVector, this->getItemVector()); + + if (distance < 50){ + std::string result; + result += std::to_string(queryId) + " "; + result += std::to_string(this->getItemId()) + " " + std::to_string(distance) + "\n"; + + if (husky::Context::get_param("outputPath") == "localhost"){ + husky::LOG_I << "OUTPUT:" << result; + }else{ + husky::io::HDFS::Write( + husky::Context::get_param("hdfs_namenode"), + husky::Context::get_param("hdfs_namenode_port"), + result, + husky::Context::get_param("outputPath"), + husky::Context::get_global_tid()); + } + } + } + } +}; + +template< + typename ItemIdType, + typename ItemElementType, + typename QueryMsg, + typename AnswerMsg +> +class E2LSHBucket: public LSHBucket { +public: + // explicit E2LSHBucket(const typename E2LSHBucket::KeyT& bId):LSHBucket(bId){} + explicit E2LSHBucket(const typename E2LSHBucket::KeyT& bId):LSHBucket(bId){} +}; diff --git a/apps/e2lsh_ir/sift_ir.hpp b/apps/e2lsh_ir/sift_ir.hpp new file mode 100644 index 0000000..f91904f --- /dev/null +++ b/apps/e2lsh_ir/sift_ir.hpp @@ -0,0 +1,32 @@ +#include "e2lsh_ir.hpp" +// To parse SIFT1B +typedef int ItemIdType; +typedef float ItemElementType; +typedef ItemIdType QueryMsg; +typedef std::pair AnswerMsg; +const int idBytes_sift1b = 4; +const int dimension_sift1b = 128; +const int elementBytes_sift1b = sizeof(ItemElementType); + +// input format: id f1 f2 +void setItemSIFT1B( + boost::string_ref& line, + int & itemId, + std::vector& itemVector) { + + assert(line.size() != 0); + + memcpy(&itemId, &line[0], idBytes_sift1b); + itemVector.resize(dimension_sift1b); + int startIdx = idBytes_sift1b; + for (int i = 0; i < dimension_sift1b; ++i) { + memcpy(&itemVector[i], &line[startIdx], elementBytes_sift1b); + startIdx += elementBytes_sift1b; + } +} + +typedef E2LSHQuery Query1B; +typedef E2LSHItem Item1B; +typedef E2LSHBucket Bucket1B; + +const int BytesPerVector = idBytes_sift1b + dimension_sift1b * elementBytes_sift1b; diff --git a/demo/.gitignore b/demo/.gitignore new file mode 100644 index 0000000..c815d2e --- /dev/null +++ b/demo/.gitignore @@ -0,0 +1,2 @@ +Img2Sift +create_match diff --git a/demo/Img2Sift.cpp b/demo/Img2Sift.cpp new file mode 100644 index 0000000..d1e66c1 --- /dev/null +++ b/demo/Img2Sift.cpp @@ -0,0 +1,188 @@ +/* +* @file SURF_FlannMatcher +* @brief SURF detector + descriptor + FLANN Matcher +* @author A. Huaman +* compile this file with : g++ -std=c++11 Img2Sift.cpp -o Img2Sift `pkg-config opencv --cflags --libs` +*/ +#include +#include +#include +#include +#include +#include +#include +#include "opencv2/core.hpp" +#include "opencv2/features2d.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/imgcodecs.hpp" +#include "opencv2/xfeatures2d.hpp" +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +void readme(); + +int main(int argc, char **argv) { + if (argc < 3) { + readme(); + return -1; + } + + // transfer single image + // ./I2S2B + if (argc == 3) { + Mat img = imread(argv[1], IMREAD_GRAYSCALE); // read image + const char *name = argv[2]; + Mat final_img; + + if (!img.data) { + std::cout << " --(!) Error reading images " << std::endl; + return -1; + } + + cv::Ptr f2d = xfeatures2d::SIFT::create(); // creat SIFT object + + //-- Step 1: Detect the keypoints: + std::vector keypoints; // init keypoint datatype + f2d->detect(img, keypoints); // detect image keypoint + + //-- Step 2: Calculate descriptors (feature vectors) + Mat descriptors; // save keypoint to descriptor + f2d->compute(img, keypoints, descriptors); + + //-- descriptor (Mat) to vector vector float + // http://stackoverflow.com/questions/9790124/converting-a-row-of-cvmat-to-stdvector// + std::vector > SIFTdata; + for (int i = 0; i < descriptors.rows; i++) { + const float *p = descriptors.ptr(i); + std::vector row(p, p + descriptors.cols); + SIFTdata.push_back(row); + } +cout << SIFTdata.size()< + if (argc == 4) { + int totaldata = 0; + int numberOfFile = stoi(argv[1]); + const char *outfilename = argv[3]; + if (numberOfFile > 1000) { + cout << "Currently support only 1000 images."; + return -1; + } + cout << "Total: " << numberOfFile << " file(s) to be generated" << endl; + + // Reading directory + DIR *dir; + struct dirent *ent; + + std::vector filenames; + + int counter = 0; + if ((dir = opendir(argv[2])) != NULL) { + while ((ent = readdir(dir)) != NULL && counter < numberOfFile + 2) { + if (counter == 0 || counter == 1) { + counter++; + continue; + } + filenames.push_back(ent->d_name); + counter++; + } + closedir(dir); + } else { + perror("Error reading directory: "); + return -1; + } + + /*for (auto n : filenames){ + cout << n << endl; + } + cout<< filenames.size() < f2d = xfeatures2d::SIFT::create(); // creat SIFT + // object + + //-- Step 1: Detect the keypoints: + std::vector keypoints; // init keypoint datatype + f2d->detect(img, keypoints); // detect image keypoint + + //-- Step 2: Calculate descriptors (feature vectors) + Mat descriptors; // save keypoint to descriptor + f2d->compute(img, keypoints, descriptors); + + //-- descriptor (Mat) to vector vector float + // http://stackoverflow.com/questions/9790124/converting-a-row-of-cvmat-to-stdvector// + std::vector > SIFTdata; + for (int i = 0; i < descriptors.rows; i++) { + const float *p = descriptors.ptr(i); + std::vector row(p, p + descriptors.cols); + SIFTdata.push_back(row); + totaldata++; + } + + for (int i = 0; i < SIFTdata.size(); i++) { + int id = i * 1000 + counter; + out_file.write((const char *)&id, sizeof(id)); + for (int j = 0; j < SIFTdata[i].size(); j++) { + out_file.write((const char *)&SIFTdata[i][j], sizeof(SIFTdata[i][j])); + } + } + counter++; + cout << "done!" << endl; + } + + cout << "Number of SIFT items: " << totaldata << endl; + return 0; + } +} + +void readme() { + std::cout << " Usage: ./Img2SIFT " << std::endl; + std::cout << " Usage: ./Img2SIFT " << std::endl; +} + +/* Img2SIFT translates an image to grayscale and extract it's key feature as +*SIFT descriptor +** Input: an image file +** Output: cout the result as vector< vector > +** Each inner vector compose of id + 128 feature in datatype float. +** hidden function: mark the output on image with imread display +*/ diff --git a/demo/Readme.md b/demo/Readme.md new file mode 100644 index 0000000..0720222 --- /dev/null +++ b/demo/Readme.md @@ -0,0 +1,168 @@ +# Image retrieval demo using Losha + +## Concept + +With Losha, this demo presents an image retrieval application to utilize distributed fast neighbor search. It can look for the original piece of image within a directory full of images given part of the image that could have been altered and cropped. + +![](https://d2mxuefqeaa7sj.cloudfront.net/s_4059602D3E424BE76E9ADEF542E217E1EE55739753AB83D553C21A1C1D57147B_1512058775305_demo.png) + +## Build + +**Prerequisites** + +- OpenCV (with opencv_contri) 3.3.1 + +Build the two apps, **Img2Sift** and **create_match** with the following: + +```bash +g++ -std=c++11 Img2Sift.cpp -o Img2Sift `pkg-config opencv --cflags --libs` +g++ -std=c++11 create_match.cpp -o create_match `pkg-config opencv --cflags --libs` +``` + +It is also required to make E2LSH_IR app, a modified version of E2LSH with: + +```bash +cd build +make -j{N} E2LSH_IR +``` + + +## Usage + +### Overview +There are three steps to complete the process: + +1. Create Image Binary +2. Run nearest neighbor search (NNS) +3. Match image + +#### Step 1: Create Image Binary +Img2Sift provides functions to extract SIFT from image. +Currently, the number of images in the directory is limited to 1000 images. + + +- To show usage: +``` bash +./Img2Sift --help +``` + +- To generate single file binary (usually the query image): +```bash +./Img2Sift +``` + +- To generate binary for all images within a directory (usually the items) +```bash +./Img2Sift +``` + +#### Step 2: Run NNS +In order to run NNS, we need to update the configuration file for the Data management Paths, due to the large amount of query, please place it on hdfs: + +```txt +# Data management +outputPath= +itemPath=hdfs:/// +queryPath=hdfs:/// +``` + +A good set of parameter for IR can be configured as follow: + +```txt +band=10 +row=20 +W=600 +dimension=128 +maxIteration=1 +``` + +With two terminals run: + +```bash +./Master --conf /path/to/your/conf +``` +```bash +./exec.sh e2lsh_ir --conf /path/to/your/conf +``` + +#### Step 3: Match image +In a distributed environment,pull the output results and concat into a single discription file. +```bash +hadoop fs -get hdfs:// . +cat /* >> +``` + +with the description, we can execute create_match. create_match provides two functions: matching the query image with another single image, or with the entire directory. Both creates a matching-image as result. + + +- To pair two images, run: +```bash +./create_match -two +``` + +- To find the image within the directory: +```bash +./create_match -dir +``` + +## Example + +In this demo folder, a sample is provided with all intermediate files. The folder structure is presented as following: + +```txt + demo/ + ├── results/ + ├── data/ + │ ├── dir/ + │ ├── inter/ +``` + +Within the data folder, we query the `duck.jpg` toward the images within the `dir` folder which contains the original duck image and nine other random images. + +**Step 1 :** +create the binary for query image duck.jpg +```bash +./Img2Sift.cpp duck.jpg nov.duck +``` + +the intermediate files is provided within `data/dir/inter/` +Then, create the binary for the entire directory +```bash +./Img2Sift.cpp 10 dir nov.dir +``` +the intermediate files is provided within `data/dir/inter/` + + +**Step 2 :** +place onto hdfs and run E2LSH_IR + +```bash +#in one terminal +./Master --conf /path/to/conf +``` +```bash +#in another terminal +hdfs -put nov.dir nov.duck / +./exec.sh e2lsh_ir --conf /path/to/conf +hadoop fs -get hdfs://output . +cat output/* >> all.txt +``` +the intermediate file `all.txt` is provided within `data/dir/inter/` + +**Step 3 :** +run create_match +```bash +./create_match -dir duck.jpg dir all.txt +``` + +## Result + +With the contrast and lightening altered duck.jpg, we can correctly find the original image within the directory. + +![](https://d2mxuefqeaa7sj.cloudfront.net/s_4059602D3E424BE76E9ADEF542E217E1EE55739753AB83D553C21A1C1D57147B_1512100429015_dir.jpg) + +## More information & Acknowledgements + +This application is part of the Final Year Project by tcheng and the detailed documentation is available [here](https://tichung.com/static/Yr4_CSCI4999_FYP_report.pdf). +Some other results and performance details can be found here (under construction). +The image here are obtained from the internet under [Creative Common CC0 licence](https://creativecommons.org/publicdomain/zero/1.0/deed) and will remain as it is. diff --git a/demo/create_match.cpp b/demo/create_match.cpp new file mode 100644 index 0000000..a9a13d2 --- /dev/null +++ b/demo/create_match.cpp @@ -0,0 +1,164 @@ +/* +* @file SURF_FlannMatcher +* @brief SURF detector + descriptor + FLANN Matcher +* @author A. Huaman +* compile this file with : g++ -std=c++11 create_match.cpp -o create_match `pkg-config opencv --cflags --libs` +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "opencv2/core.hpp" +#include "opencv2/features2d.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/imgcodecs.hpp" +#include "opencv2/xfeatures2d.hpp" +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +void readme(); + +void twoImageDmatch(char* img1, char* img2, std::vector result) { + Mat img_1 = imread(img1, IMREAD_GRAYSCALE); + Mat img_2 = imread(img2, IMREAD_GRAYSCALE); + Mat one = imread(img1, CV_LOAD_IMAGE_COLOR); + Mat two = imread(img2, CV_LOAD_IMAGE_COLOR); + // cout << "image1: " << img_1 << "\n"; + if (!img_1.data || !img_2.data) { + std::cout << " --(!) Error reading images " << std::endl; + return; + } + + // Reconstruct the input descriptors + cv::Ptr detector = + xfeatures2d::SIFT::create(); // creat SIFT object + + std::vector keypoints_1, keypoints_2; + Mat descriptors_1, descriptors_2; + detector->detectAndCompute(img_1, Mat(), keypoints_1, descriptors_1); + detector->detectAndCompute(img_2, Mat(), keypoints_2, descriptors_2); + + // Read result from file to create matches + + + // Draw matches and save as image + Mat img_matches; + drawMatches(one, keypoints_1, two, keypoints_2, result, img_matches, + Scalar::all(-1), Scalar::all(-1), vector(), + DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); + + imwrite("dir.jpg", img_matches); + // for( int i = 0; i < (int)good_matches.size(); i++ ) + // { printf( "-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n", + // i, good_matches[i].queryIdx, good_matches[i].trainIdx ); } + printf("number of good matches: %d\n", (int)result.size()); + waitKey(0); + return; +} + +void twoImage(char* img1, char* img2, char* result) { + + std::vector good_matches; // matches + ifstream infile; + infile.open(result); + + int query, item; + float distance; + if (infile.is_open()) { + while (!infile.eof()) { + infile >> query >> item >> distance; + DMatch pair = DMatch(query, item, distance); + good_matches.push_back(pair); + // cout << query << " " << item << " : " << distance < fidIndex; + std::map> fidMatch; + + if (infile.is_open()) { + while (!infile.eof()) { + infile >> qid >> iidfid >> distance; + fid = iidfid % 1000; + iid = iidfid / 1000; + DMatch pair = DMatch(qid, iid, distance); + fidMatch[fid].push_back(pair); + // cout << qid << " " << fid << " " << iid << " : " << distance << endl; + } + } + infile.close(); + + int maxid = -1; + int maxcount = -1; + for (auto it = fidMatch.cbegin(); it != fidMatch.cend(); ++it) { + int size = it->second.size(); + if (size > maxcount) { + maxid = it->first; + maxcount = size; + } + } + + // cout << maxid << " " << maxcount << endl; + + std::stringstream ss; // create fileId string + ss << std::setw(3) << std::setfill('0') + << maxid; // NOTE: This should be modified by number of inputs, + // currently support 000-999 + std::string filename = ss.str(); + std::string dirname(dir); + + std::vector selection; + for (int p=0; p(filename.c_str()), selection); + return; +} + +int main(int argc, char** argv) { + if (!strcmp(argv[1], "-two")) { + if (argc != 5) { + std::cout << " Usage: -two " << std::endl; + } + twoImage(argv[2], argv[3], argv[4]); + return 0; + } + + if (!strcmp(argv[1], "-dir")) { + if (argc != 5) { + std::cout << " Usage: -dir " << std::endl; + } + dirsearch(argv[2], argv[3], argv[4]); + return 0; + } + + if (argc != 5) { + readme(); + return -1; + } + + return 0; +} + +void readme() { + std::cout << " Usage: -two " << std::endl; + std::cout << " Usage: -dir " << std::endl; +} \ No newline at end of file diff --git a/demo/data/dir/000.jpg b/demo/data/dir/000.jpg new file mode 100644 index 0000000..4a7312e Binary files /dev/null and b/demo/data/dir/000.jpg differ diff --git a/demo/data/dir/001.jpg b/demo/data/dir/001.jpg new file mode 100644 index 0000000..97055cb Binary files /dev/null and b/demo/data/dir/001.jpg differ diff --git a/demo/data/dir/002.jpg b/demo/data/dir/002.jpg new file mode 100644 index 0000000..cde2de9 Binary files /dev/null and b/demo/data/dir/002.jpg differ diff --git a/demo/data/dir/003.jpg b/demo/data/dir/003.jpg new file mode 100644 index 0000000..8ab1c8e Binary files /dev/null and b/demo/data/dir/003.jpg differ diff --git a/demo/data/dir/004.jpg b/demo/data/dir/004.jpg new file mode 100644 index 0000000..4ae8da1 Binary files /dev/null and b/demo/data/dir/004.jpg differ diff --git a/demo/data/dir/005.jpg b/demo/data/dir/005.jpg new file mode 100644 index 0000000..13f2609 Binary files /dev/null and b/demo/data/dir/005.jpg differ diff --git a/demo/data/dir/006.jpg b/demo/data/dir/006.jpg new file mode 100644 index 0000000..b5b31b0 Binary files /dev/null and b/demo/data/dir/006.jpg differ diff --git a/demo/data/dir/007.jpg b/demo/data/dir/007.jpg new file mode 100644 index 0000000..fb67f2f Binary files /dev/null and b/demo/data/dir/007.jpg differ diff --git a/demo/data/dir/008.jpg b/demo/data/dir/008.jpg new file mode 100644 index 0000000..91f7f1e Binary files /dev/null and b/demo/data/dir/008.jpg differ diff --git a/demo/data/dir/009.jpg b/demo/data/dir/009.jpg new file mode 100644 index 0000000..c890477 Binary files /dev/null and b/demo/data/dir/009.jpg differ diff --git a/demo/data/duck.jpg b/demo/data/duck.jpg new file mode 100644 index 0000000..a31fb36 Binary files /dev/null and b/demo/data/duck.jpg differ diff --git a/demo/data/inter/all.txt b/demo/data/inter/all.txt new file mode 100644 index 0000000..bcb68d4 --- /dev/null +++ b/demo/data/inter/all.txt @@ -0,0 +1,654 @@ +87 2347005 43.977268 +100 2347005 47.381432 +149 2447005 49.426712 +4086 2697005 37.616486 +4036 2777005 30.789608 +1895 5638005 49.959984 +1880 5658005 39.000000 +1860 5688005 36.482872 +1690 5873005 42.883564 +1623 5928005 38.961521 +1601 5948005 43.692104 +1554 5993005 45.376205 +1536 6013005 42.555847 +1486 6088005 45.727455 +1463 6113005 48.352871 +1447 6128005 48.713448 +1445 6133005 48.311489 +1427 6158005 39.230091 +4625 1134005 40.938980 +4147 2616005 40.323689 +3914 2986005 47.095646 +3231 3790005 43.324360 +2904 4222005 46.173584 +2413 4962005 38.832977 +902 6812005 41.916584 +810 6936005 33.674915 +4281 2326005 44.732540 +4038 2770005 48.948952 +3808 3117005 45.923851 +3659 3331005 46.808121 +3407 3619005 45.760246 +66 8353005 49.000000 +4718 842005 34.307434 +2613 4698005 46.551048 +2498 4849005 34.322006 +2301 5121005 38.327538 +2260 5189005 15.362291 +1925 5601005 42.402828 +1852 5701005 37.854988 +1728 5841005 49.487373 +992 6700005 48.938736 +950 6745005 36.318039 +273 7779005 37.215588 +63 8363005 40.074928 +4690 911005 35.256207 +4677 941005 46.872166 +2770 4447005 46.054317 +2485 4863005 40.693981 +2406 4971005 41.496986 +1909 5612005 38.078865 +781 6970005 42.261093 +327 7681005 33.301651 +288 7754005 36.646965 +102 8298005 41.012192 +4214 2503005 49.142651 +3567 3428005 47.560490 +3559 3432005 44.226688 +3322 3698005 49.959984 +2311 5102005 47.138096 +2218 5247005 47.191101 +2014 5531005 40.583248 +1963 5572005 35.156792 +1604 5947005 39.534794 +1231 6396005 47.476311 +1227 6406005 40.607880 +392 7578005 35.369480 +120 8214005 44.158806 +52 8377005 35.213634 +3293 3729005 43.749287 +2484 4864005 39.698868 +2363 5033005 33.436508 +2299 5122005 46.776062 +2104 5400005 48.311489 +1854 5697005 42.555847 +1327 6264005 32.496155 +1330 6267005 38.755646 +1225 6404005 30.757113 +151 8125005 32.233524 +4035 2778005 33.955853 +3286 3735005 44.665424 +3268 3756005 27.946377 +3227 3789005 41.665333 +3179 3843005 43.760712 +2883 4248005 37.403210 +2777 4440005 44.226688 +2596 4715005 44.317039 +2161 5329005 32.588341 +1778 5785005 37.509998 +56 8373005 38.183765 +54 8379005 39.191837 +4801 508005 48.785244 +4707 867005 34.307434 +4239 2448005 22.045408 +4064 2735005 42.083252 +3386 3643005 47.874836 +2862 4290005 40.767635 +2795 4407005 32.480762 +2760 4463005 37.429935 +2721 4513005 48.052055 +2676 4586005 37.735924 +2421 4952005 48.795490 +2353 5052005 44.553337 +2215 5249005 46.658333 +2099 5416005 47.895721 +2008 5534005 47.560490 +626 7131005 37.828560 +119 8220005 34.957115 +43 8400005 49.295029 +4411 1898005 25.865034 +128 3434005 45.122055 +3285 3734005 36.674240 +2552 4779005 39.635841 +2006 5535005 26.419689 +790 6964005 42.225586 +452 7469005 37.107952 +4744 724005 35.777088 +4616 1169005 38.209946 +3918 2972005 46.497311 +3889 3008005 39.949970 +3067 4004005 44.833023 +2644 4640005 48.579830 +2556 4772005 49.969990 +2200 5273005 49.568134 +2041 5499005 16.852299 +1631 5922005 40.804413 +791 6963005 42.918526 +186 8060005 46.540306 +118 8219005 46.776062 +545 1027003 49.618546 +4305 2263005 33.749073 +3865 3042005 45.541191 +2786 4418005 34.496376 +1790 5775005 40.521599 +1433 6150005 32.680271 +740 7009005 48.435524 +345 7642005 40.348480 +110 8253005 42.071369 +4431 1851005 36.810326 +3925 2961005 33.955853 +3799 3139005 40.865635 +3764 3192005 31.464266 +3628 3354005 46.454277 +3144 3879005 29.765753 +2816 4387005 38.470768 +2674 4590005 43.266617 +2201 5270005 40.261642 +2005 5536005 30.430248 +1888 5640005 39.736633 +1591 5956005 36.359318 +1514 6047005 42.778500 +633 7120005 27.910572 +53 8378005 35.510563 +4352 2087005 44.888752 +4329 2163005 24.228083 +3902 2994005 30.643106 +3822 3093005 41.291645 +3625 3361005 46.000000 +2026 5515005 43.588989 +1834 5726005 47.885281 +1833 5727005 48.373547 +1377 6223005 39.585350 +1298 6295005 45.793011 +998 6692005 43.197224 +847 6885005 39.064049 +4655 995005 44.237991 +4127 2654005 48.187134 +3464 3548005 45.420261 +3452 3565005 47.958317 +3237 3783005 49.071377 +3139 3890005 29.765753 +3056 4014005 49.162994 +2871 4276005 47.010635 +2860 4296005 46.368092 +2857 4300005 47.106262 +2431 4940005 41.279533 +1226 6405005 28.513155 +1146 6496005 47.042534 +894 6830005 42.813549 +437 7491005 31.606962 +252 7856005 24.515301 +3927 2960005 33.136082 +3079 3992005 49.081566 +2836 4347005 28.530685 +2407 4970005 45.099888 +2134 5360005 45.155289 +128 8500005 43.543083 +4877 38005 46.529560 +4689 912005 31.224991 +4650 1017005 18.520260 +3805 3123005 47.853943 +3450 3568005 38.483765 +2827 4357005 44.777225 +2582 4731005 37.973675 +2354 5051005 42.626282 +2058 5478005 26.627054 +1328 6263005 33.211445 +1329 6266005 41.916584 +1320 6272005 49.507576 +1248 6378005 46.690472 +951 6746005 31.591139 +112 8759005 41.593269 +4879 75005 38.923000 +4649 1018005 18.411953 +4478 1713005 38.845848 +4405 1910005 32.969685 +4166 2584005 49.193497 +3523 3490005 36.221542 +3504 3510005 35.369480 +2636 4647005 28.982754 +2481 4875005 47.707443 +2357 5044005 38.548672 +2042 5498005 23.216373 +2035 5508005 20.856653 +1504 6056005 49.537865 +870 6862005 39.724049 +809 6937005 44.463467 +190 8040005 33.511192 +4815 469005 38.768543 +3802 3134005 44.877613 +3013 4059005 45.902069 +2147 5348005 49.335587 +1016 6660005 49.638695 +677 7069005 27.147743 +87 8247005 48.918301 +4657 992005 31.527765 +3191 3836005 43.794975 +2780 4429005 45.639896 +2776 4441005 38.105118 +2313 5096005 31.240999 +2149 5345005 47.138096 +1126 6521005 32.000000 +1057 6618005 49.959984 +475 7435005 46.270943 +4535 1474005 46.765373 +4032 2779005 26.267851 +3542 3462005 43.474129 +2949 4140005 41.749252 +2703 4538005 49.749371 +1958 5573005 35.411861 +1672 5892005 22.825424 +1505 6055005 29.444864 +1197 6436005 47.518417 +4761 662005 48.363209 +4747 703005 39.924931 +4612 1185005 38.845848 +2643 4641005 46.872166 +2547 4783005 37.229019 +2348 5063005 38.065731 +2219 5244005 41.036568 +2067 5468005 36.359318 +1732 5834005 38.535698 +427 7517005 47.318073 +3988 2845005 42.813549 +3336 3688005 48.249352 +2511 4836005 40.360870 +2359 5040005 33.704597 +2123 5375005 47.655010 +2082 5444005 44.384682 +529 7295005 42.965103 +68 8350005 43.954521 +3798 3140005 43.829212 +3630 3355005 48.363209 +2778 4439005 41.581245 +2701 4540005 41.170376 +2382 5011005 35.128338 +1056 6613005 28.178005 +662 7092005 48.114449 +259 7841005 42.059483 +544 8072005 46.936127 +131 2093005 46.647614 +4330 2160005 38.910152 +4155 2608005 44.271889 +3943 2919005 31.368774 +2294 5129005 38.183765 +2234 5220005 48.682644 +2109 5394005 35.749126 +1957 5574005 38.052597 +1543 6004005 44.474712 +1538 6011005 30.430248 +1444 6134005 35.930489 +3960 2893005 36.496574 +3612 3383005 46.076023 +3221 3796005 46.173584 +2672 4591005 46.701180 +2453 4911005 38.340580 +2089 5429005 49.142651 +1972 5559005 49.678970 +903 6811005 46.335732 +655 7102005 45.814846 +4162 2603005 48.031239 +3614 3384005 29.832869 +3406 3620005 33.075672 +3294 3728005 46.936127 +1084 6581005 43.554562 +974 6719005 43.428101 +864 6874005 47.801674 +839 6899005 46.065170 +775 6978005 45.077709 +694 7054005 40.311287 +4824 420005 48.877399 +4088 2696005 32.341923 +3769 3184005 42.332020 +3621 3368005 46.162754 +3437 3582005 43.737854 +2741 4485005 49.709152 +2083 5442005 44.395947 +1955 5569005 49.729267 +128 795003 48.062458 +4257 2398005 48.826221 +4254 2419005 49.709152 +2283 5149005 38.535698 +1493 6076005 45.387222 +512 7356005 41.773197 +490 7399005 46.658333 +122 8595005 42.743420 +4632 1097005 27.018513 +4504 1634005 45.276924 +3877 3027005 35.369480 +3781 3160005 36.152454 +3399 3626005 36.193924 +2902 4228005 49.769470 +2881 4261005 48.805737 +2529 4820005 44.654228 +648 7111005 21.954498 +618 7135005 31.796227 +302 7734005 46.054317 +282 7759005 36.755951 +4330 2160001 38.910152 +2099 5416001 47.895721 +2014 5531001 40.583248 +2005 5536001 30.430248 +1925 5601001 42.402828 +1852 5701001 37.854988 +1834 5726001 47.885281 +4625 1134001 40.938980 +3960 2893001 36.496574 +3799 3139001 40.865635 +3294 3728001 46.936127 +3231 3790001 43.324360 +3144 3879001 29.765753 +2674 4590001 43.266617 +2201 5270001 40.261642 +2109 5394001 35.749126 +1888 5640001 39.736633 +1444 6134001 35.930489 +974 6719001 43.428101 +864 6874001 47.801674 +810 6936001 33.674915 +633 7120001 27.910572 +490 7399001 46.658333 +4650 1017001 18.520260 +87 2347001 43.977268 +100 2347001 47.381432 +3437 3582001 43.737854 +2871 4276001 47.010635 +2498 4849001 34.322006 +2359 5040001 33.704597 +2348 5063001 38.065731 +2161 5329001 32.588341 +1909 5612001 38.078865 +1604 5947001 39.534794 +781 6970001 42.261093 +427 7517001 47.318073 +4504 1634001 45.276924 +149 2447001 49.426712 +4239 2448001 22.045408 +3918 2972001 46.497311 +2636 4647001 28.982754 +2552 4779001 39.635841 +2357 5044001 38.548672 +950 6745001 36.318039 +63 8363001 40.074928 +43 8400001 49.295029 +4707 867001 34.307434 +4038 2770001 48.948952 +3988 2845001 42.813549 +3659 3331001 46.808121 +3559 3432001 44.226688 +3399 3626001 36.193924 +3067 4004001 44.833023 +2881 4261001 48.805737 +2836 4347001 28.530685 +1554 5993001 45.376205 +1538 6011001 30.430248 +273 7779001 37.215588 +148 245004 44.888752 +4824 420001 48.877399 +4655 995001 44.237991 +3322 3698001 49.959984 +3013 4059001 45.902069 +2862 4290001 40.767635 +2860 4296001 46.368092 +2676 4586001 37.735924 +2484 4864001 39.698868 +2006 5535001 26.419689 +775 6978001 45.077709 +677 7069001 27.147743 +288 7754001 36.646965 +190 8040001 33.511192 +4677 941001 46.872166 +3268 3756001 27.946377 +2582 4731001 37.973675 +2299 5122001 46.776062 +1958 5573001 35.411861 +1197 6436001 47.518417 +1146 6496001 47.042534 +1126 6521001 32.000000 +327 7681001 33.301651 +102 8298001 41.012192 +53 8378001 35.510563 +4088 2696001 32.341923 +3889 3008001 39.949970 +128 3434001 45.122055 +2294 5129001 38.183765 +2215 5249001 46.658333 +1790 5775001 40.521599 +1505 6055001 29.444864 +1225 6404001 30.757113 +1057 6618001 49.959984 +992 6700001 48.938736 +809 6937001 44.463467 +68 8350001 43.954521 +122 8595001 42.743420 +4086 2697001 37.616486 +3139 3890001 29.765753 +2827 4357001 44.777225 +2511 4836001 40.360870 +1504 6056001 49.537865 +1445 6133001 48.311489 +1330 6267001 38.755646 +847 6885001 39.064049 +694 7054001 40.311287 +2721 4513001 48.052055 +2596 4715001 44.317039 +2453 4911001 38.340580 +2147 5348001 49.335587 +2035 5508001 20.856653 +1690 5873001 42.883564 +282 7759001 36.755951 +4612 1185001 38.845848 +131 2093001 46.647614 +3625 3361001 46.000000 +3523 3490001 36.221542 +2786 4418001 34.496376 +1860 5688001 36.482872 +1728 5841001 49.487373 +1536 6013001 42.555847 +1463 6113001 48.352871 +54 8379001 39.191837 +4535 1474001 46.765373 +4411 1898001 25.865034 +4127 2654001 48.187134 +3542 3462001 43.474129 +3504 3510001 35.369480 +2643 4641001 46.872166 +2613 4698001 46.551048 +2406 4971001 41.496986 +1957 5574001 38.052597 +1880 5658001 39.000000 +1493 6076001 45.387222 +1226 6405001 28.513155 +662 7092001 48.114449 +648 7111001 21.954498 +186 8060001 46.540306 +87 8247001 48.918301 +56 8373001 38.183765 +4877 38001 46.529560 +4718 842001 34.307434 +4352 2087001 44.888752 +4162 2603001 48.031239 +4032 2779001 26.267851 +3621 3368001 46.162754 +2701 4540001 41.170376 +1972 5559001 49.678970 +1895 5638001 49.959984 +1601 5948001 43.692104 +1377 6223001 39.585350 +1248 6378001 46.690472 +259 7841001 42.059483 +112 8759001 41.593269 +4478 1713001 38.845848 +4214 2503001 49.142651 +3877 3027001 35.369480 +3612 3383001 46.076023 +2083 5442001 44.395947 +1854 5697001 42.555847 +1732 5834001 38.535698 +1514 6047001 42.778500 +1327 6264001 32.496155 +110 8253001 42.071369 +128 8500001 43.543083 +4761 662001 48.363209 +3798 3140001 43.829212 +3293 3729001 43.749287 +2776 4441001 38.105118 +2547 4783001 37.229019 +2354 5051001 42.626282 +2234 5220001 48.682644 +1672 5892001 22.825424 +903 6811001 46.335732 +437 7491001 31.606962 +4689 912001 31.224991 +4632 1097001 27.018513 +4166 2584001 49.193497 +3221 3796001 46.173584 +2421 4952001 48.795490 +2104 5400001 48.311489 +839 6899001 46.065170 +52 8377001 35.213634 +4879 75001 38.923000 +4815 469001 38.768543 +3227 3789001 41.665333 +2778 4439001 41.581245 +2777 4440001 44.226688 +2760 4463001 37.429935 +2149 5345001 47.138096 +1631 5922001 40.804413 +1623 5928001 38.961521 +1328 6263001 33.211445 +1231 6396001 47.476311 +740 7009001 48.435524 +345 7642001 40.348480 +4747 703001 39.924931 +3822 3093001 41.291645 +2485 4863001 40.693981 +2026 5515001 43.588989 +1778 5785001 37.509998 +1543 6004001 44.474712 +1298 6295001 45.793011 +475 7435001 46.270943 +4801 508001 48.785244 +4405 1910001 32.969685 +4305 2263001 33.749073 +4281 2326001 44.732540 +3902 2994001 30.643106 +3808 3117001 45.923851 +3056 4014001 49.162994 +2301 5121001 38.327538 +2041 5499001 16.852299 +1329 6266001 41.916584 +655 7102001 45.814846 +452 7469001 37.107952 +252 7856001 24.515301 +4744 724001 35.777088 +4690 911001 35.256207 +4155 2608001 44.271889 +3452 3565001 47.958317 +3386 3643001 47.874836 +2857 4300001 47.106262 +2780 4429001 45.639896 +2770 4447001 46.054317 +2672 4591001 46.701180 +1955 5569001 49.729267 +1227 6406001 40.607880 +544 8072001 46.936127 +3764 3192001 31.464266 +3285 3734001 36.674240 +2481 4875001 47.707443 +2407 4970001 45.099888 +2363 5033001 33.436508 +2313 5096001 31.240999 +2219 5244001 41.036568 +951 6746001 31.591139 +529 7295001 42.965103 +302 7734001 46.054317 +119 8220001 34.957115 +4649 1018001 18.411953 +3865 3042001 45.541191 +3406 3620001 33.075672 +3336 3688001 48.249352 +2902 4228001 49.769470 +2883 4248001 37.403210 +2311 5102001 47.138096 +2089 5429001 49.142651 +120 8214001 44.158806 +118 8219001 46.776062 +3628 3354001 46.454277 +2644 4640001 48.579830 +2382 5011001 35.128338 +2082 5444001 44.384682 +2042 5498001 23.216373 +1486 6088001 45.727455 +1447 6128001 48.713448 +1016 6660001 49.638695 +894 6830001 42.813549 +392 7578001 35.369480 +66 8353001 49.000000 +4329 2163001 24.228083 +4257 2398001 48.826221 +3943 2919001 31.368774 +3802 3134001 44.877613 +3630 3355001 48.363209 +2904 4222001 46.173584 +2556 4772001 49.969990 +2413 4962001 38.832977 +2067 5468001 36.359318 +1591 5956001 36.359318 +791 6963001 42.918526 +3614 3384001 29.832869 +2816 4387001 38.470768 +2283 5149001 38.535698 +2134 5360001 45.155289 +2058 5478001 26.627054 +1963 5572001 35.156792 +1833 5727001 48.373547 +1427 6158001 39.230091 +4616 1169001 38.209946 +4431 1851001 36.810326 +4147 2616001 40.323689 +3914 2986001 47.095646 +2949 4140001 41.749252 +2218 5247001 47.191101 +2123 5375001 47.655010 +1433 6150001 32.680271 +4035 2778001 33.955853 +3769 3184001 42.332020 +2529 4820001 44.654228 +2431 4940001 41.279533 +2200 5273001 49.568134 +1056 6613001 28.178005 +790 6964001 42.225586 +626 7131001 37.828560 +618 7135001 31.796227 +149 259004 48.062458 +4064 2735001 42.083252 +3927 2960001 33.136082 +3925 2961001 33.955853 +3407 3619001 45.760246 +3179 3843001 43.760712 +2795 4407001 32.480762 +1320 6272001 49.507576 +998 6692001 43.197224 +902 6812001 41.916584 +870 6862001 39.724049 +151 8125001 32.233524 +4657 992001 31.527765 +4036 2777001 30.789608 +3567 3428001 47.560490 +3286 3735001 44.665424 +3237 3783001 49.071377 +3191 3836001 43.794975 +2741 4485001 49.709152 +2353 5052001 44.553337 +2008 5534001 47.560490 +1084 6581001 43.554562 +512 7356001 41.773197 +4254 2419001 49.709152 +3805 3123001 47.853943 +3781 3160001 36.152454 +3464 3548001 45.420261 +3450 3568001 38.483765 +3079 3992001 49.081566 +2703 4538001 49.749371 +2260 5189001 15.362291 diff --git a/demo/data/inter/dir.fvecs b/demo/data/inter/dir.fvecs new file mode 100644 index 0000000..a7f3e20 Binary files /dev/null and b/demo/data/inter/dir.fvecs differ diff --git a/demo/data/inter/duck.fvecs b/demo/data/inter/duck.fvecs new file mode 100644 index 0000000..491f0af Binary files /dev/null and b/demo/data/inter/duck.fvecs differ diff --git a/demo/results/dir.jpg b/demo/results/dir.jpg new file mode 100644 index 0000000..a98b91f Binary files /dev/null and b/demo/results/dir.jpg differ diff --git a/gqr b/gqr new file mode 160000 index 0000000..ca30a6b --- /dev/null +++ b/gqr @@ -0,0 +1 @@ +Subproject commit ca30a6b75e5d25a94e57592787cc234b683e75fd