Commit 66458eae97a35cd770399d24d620c7f893d49cf6

Authored by Josh Klontz
1 parent 66cb21a5

added partially complete br-search implementation

app/CMakeLists.txt
@@ -10,4 +10,5 @@ if(NOT ${BR_EMBEDDED}) @@ -10,4 +10,5 @@ if(NOT ${BR_EMBEDDED})
10 add_subdirectory(br-crawl) 10 add_subdirectory(br-crawl)
11 add_subdirectory(br-enroll) 11 add_subdirectory(br-enroll)
12 add_subdirectory(br-gui) 12 add_subdirectory(br-gui)
  13 + add_subdirectory(br-search)
13 endif() 14 endif()
app/br-download/br-download.cpp
@@ -61,7 +61,7 @@ static bool processReply(QNetworkReply* reply) @@ -61,7 +61,7 @@ static bool processReply(QNetworkReply* reply)
61 return false; 61 return false;
62 62
63 const QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); 63 const QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
64 - br_append_utemplate_contents(stdout, reinterpret_cast<const int8_t*>(hash.data()), reinterpret_cast<const int8_t*>(hash.data()), 3, data.size(), reinterpret_cast<const int8_t*>(data.data())); 64 + br_append_utemplate_contents(stdout, reinterpret_cast<const int8_t*>(hash.data()), reinterpret_cast<const int8_t*>(hash.data()), 3, data.size(), reinterpret_cast<const unsigned char*>(data.data()));
65 return true; 65 return true;
66 } 66 }
67 67
app/br-enroll/br-enroll.cpp
@@ -41,7 +41,7 @@ static void help() @@ -41,7 +41,7 @@ static void help()
41 41
42 static QSharedPointer<Transform> algorithm; 42 static QSharedPointer<Transform> algorithm;
43 43
44 -static void enroll_utemplate(br_const_utemplate utemplate) 44 +static void enroll_utemplate(br_const_utemplate utemplate, br_callback_context)
45 { 45 {
46 if (utemplate->algorithmID != 3) 46 if (utemplate->algorithmID != 3)
47 qFatal("Expected an encoded image."); 47 qFatal("Expected an encoded image.");
@@ -54,7 +54,7 @@ static void enroll_utemplate(br_const_utemplate utemplate) @@ -54,7 +54,7 @@ static void enroll_utemplate(br_const_utemplate utemplate)
54 const Mat &m = t.m(); 54 const Mat &m = t.m();
55 const uint32_t size = m.rows * m.cols * m.elemSize(); 55 const uint32_t size = m.rows * m.cols * m.elemSize();
56 const QByteArray templateID = QCryptographicHash::hash(QByteArray((const char*) m.data, size), QCryptographicHash::Md5); 56 const QByteArray templateID = QCryptographicHash::hash(QByteArray((const char*) m.data, size), QCryptographicHash::Md5);
57 - br_append_utemplate_contents(stdout, utemplate->imageID, (const int8_t*) templateID.data(), -1, size, (const int8_t*) m.data); 57 + br_append_utemplate_contents(stdout, utemplate->imageID, (const int8_t*) templateID.data(), -1, size, m.data);
58 } 58 }
59 } 59 }
60 60
@@ -66,7 +66,7 @@ int main(int argc, char *argv[]) @@ -66,7 +66,7 @@ int main(int argc, char *argv[])
66 Context::initialize(argc, argv, "", false); 66 Context::initialize(argc, argv, "", false);
67 Globals->quiet = true; 67 Globals->quiet = true;
68 algorithm = Transform::fromAlgorithm("FaceRecognition"); 68 algorithm = Transform::fromAlgorithm("FaceRecognition");
69 - br_iterate_utemplates_file(stdin, enroll_utemplate); 69 + br_iterate_utemplates_file(stdin, enroll_utemplate, NULL);
70 Context::finalize(); 70 Context::finalize();
71 return EXIT_SUCCESS; 71 return EXIT_SUCCESS;
72 } 72 }
app/br-search/CMakeLists.txt 0 → 100644
  1 +add_executable(br-search br-search.cpp ${BR_RESOURCES})
  2 +target_link_libraries(br-search openbr ${BR_THIRDPARTY_LIBS})
  3 +qt5_use_modules(br-search ${QT_DEPENDENCIES})
  4 +install(TARGETS br-search RUNTIME DESTINATION bin)
app/br-search/br-search.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2014 Noblis *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QtCore>
  18 +#include <cstdio>
  19 +#include <cstring>
  20 +#include <limits>
  21 +#include <openbr/openbr_plugin.h>
  22 +#include <openbr/universal_template.h>
  23 +
  24 +using namespace br;
  25 +using namespace cv;
  26 +
  27 +static void help()
  28 +{
  29 + printf("br-search URL(s) [args]\n"
  30 + "=======================\n"
  31 + "* __stdin__ - Templates (feature vectors)\n"
  32 + "* __stdout__ - JSON\n"
  33 + "\n"
  34 + "_br-search_ does retrieval by comparing query templates to target gallery(s).\n"
  35 + "The search strategy is implementation defined.\n"
  36 + "\n"
  37 + "For every template read from _stdin_, search writes the top sorted matches as JSON objects to _stdout_ by comparing the query template against gallery URLs.\n"
  38 + "The JSON objects include `AlgorithmID`, `QueryImageID`, `QueryTemplateID`, `TargetImageID`, `TargetTemplateID`, `Score`, and any algorithm-specific metadata fields set during _enroll_. \n"
  39 + "\n"
  40 + "Optional Arguments\n"
  41 + "------------------\n"
  42 + "* -help - Print usage information.\n"
  43 + "* -limit <int> - Maximum number of returns (20 otherwise).\n");
  44 +}
  45 +
  46 +static int limit = 20;
  47 +static float threshold = -std::numeric_limits<float>::max();
  48 +
  49 +struct Result
  50 +{
  51 + int8_t targetImageID[16], targetTemplateID[16], queryImageID[16], queryTemplateID[16];
  52 + int32_t algorithmID;
  53 + float score;
  54 +};
  55 +
  56 +struct TopTargets : QList< QPair<br_const_utemplate, float> >
  57 +{
  58 + br_const_utemplate query;
  59 +
  60 + TopTargets(br_const_utemplate query)
  61 + : query(query) {}
  62 +
  63 + void tryAdd(br_const_utemplate target, float score)
  64 + {
  65 + if ((score < threshold) || ((size() == limit) && (score < last().second)))
  66 + return;
  67 + (void) target;
  68 + }
  69 +
  70 + void print() const
  71 + {
  72 +
  73 + }
  74 +};
  75 +
  76 +struct FaceRecognitionResult : public Result
  77 +{
  78 + int32_t x, y, width, height;
  79 +
  80 + FaceRecognitionResult()
  81 + {
  82 + algorithmID = -1;
  83 + }
  84 +};
  85 +
  86 +struct MappedGallery
  87 +{
  88 + QSharedPointer<QFile> file;
  89 + qint64 size;
  90 + uchar *data;
  91 +
  92 + MappedGallery(QString url)
  93 + {
  94 + if (url.startsWith("file://"))
  95 + url = url.mid(7);
  96 + file.reset(new QFile(url));
  97 + file->open(QFile::ReadOnly);
  98 + size = file->size();
  99 + data = file->map(0, size);
  100 + if (data == NULL)
  101 + qFatal("Unable to map gallery: %s", qPrintable(url));
  102 + }
  103 +};
  104 +
  105 +static QSharedPointer<Distance> distance;
  106 +static QList<MappedGallery> galleries;
  107 +
  108 +static void compare_utemplates(br_const_utemplate target, br_callback_context context)
  109 +{
  110 + TopTargets *topTargets = (TopTargets*) context;
  111 + topTargets->tryAdd(target, distance->compare(target->data, topTargets->query->data, 768));
  112 +}
  113 +
  114 +static void search_utemplate(br_const_utemplate query, br_callback_context)
  115 +{
  116 + TopTargets *topTargets = new TopTargets(query);
  117 + foreach (const MappedGallery &gallery, galleries)
  118 + br_iterate_utemplates(reinterpret_cast<br_const_utemplate>(gallery.data), reinterpret_cast<br_const_utemplate>(gallery.data + gallery.size), compare_utemplates, topTargets);
  119 + topTargets->print();
  120 + delete topTargets;
  121 +}
  122 +
  123 +int main(int argc, char *argv[])
  124 +{
  125 + QStringList urls;
  126 + for (int i=1; i<argc; i++) {
  127 + if (!strcmp(argv[i], "-help" )) { help(); exit(EXIT_SUCCESS); }
  128 + else if (!strcmp(argv[i], "-limit")) limit = atoi(argv[++i]);
  129 + else if (!strcmp(argv[i], "-threshold")) threshold = atof(argv[++i]);
  130 + else urls.append(argv[i]);
  131 + }
  132 +
  133 + Context::initialize(argc, argv, "", false);
  134 +
  135 + foreach (const QString &url, urls)
  136 + galleries.append(MappedGallery(url));
  137 +
  138 + Globals->quiet = true;
  139 + distance = Distance::fromAlgorithm("FaceRecognition");
  140 + br_iterate_utemplates_file(stdin, search_utemplate, NULL);
  141 +
  142 + Context::finalize();
  143 + return EXIT_SUCCESS;
  144 +}
openbr/openbr_plugin.cpp
@@ -1405,7 +1405,12 @@ float Distance::compare(const Template &amp;a, const Template &amp;b) const @@ -1405,7 +1405,12 @@ float Distance::compare(const Template &amp;a, const Template &amp;b) const
1405 return similarity; 1405 return similarity;
1406 } 1406 }
1407 1407
1408 -float Distance::compare(const cv::Mat &, const cv::Mat &) const 1408 +float Distance::compare(const cv::Mat &a, const cv::Mat &b) const
  1409 +{
  1410 + return compare(a.data, b.data, a.rows * a.cols * a.elemSize());
  1411 +}
  1412 +
  1413 +float Distance::compare(const uchar *, const uchar *, size_t) const
1409 { 1414 {
1410 qFatal("Logic error: %s did not implement a comparison function or was accessed at an unsupported level of abstraction.", metaObject()->className()); 1415 qFatal("Logic error: %s did not implement a comparison function or was accessed at an unsupported level of abstraction.", metaObject()->className());
1411 return -std::numeric_limits<float>::max(); 1416 return -std::numeric_limits<float>::max();
openbr/openbr_plugin.h
@@ -1335,6 +1335,7 @@ public: @@ -1335,6 +1335,7 @@ public:
1335 virtual QList<float> compare(const TemplateList &targets, const Template &query) const; /*!< \brief Compute the normalized distance between a template and a template list. */ 1335 virtual QList<float> compare(const TemplateList &targets, const Template &query) const; /*!< \brief Compute the normalized distance between a template and a template list. */
1336 virtual float compare(const Template &a, const Template &b) const; /*!< \brief Compute the distance between two templates. */ 1336 virtual float compare(const Template &a, const Template &b) const; /*!< \brief Compute the distance between two templates. */
1337 virtual float compare(const cv::Mat &a, const cv::Mat &b) const; /*!< \brief Compute the distance between two biometric signatures. */ 1337 virtual float compare(const cv::Mat &a, const cv::Mat &b) const; /*!< \brief Compute the distance between two biometric signatures. */
  1338 + virtual float compare(const uchar *a, const uchar *b, size_t size) const; /*!< \brief Compute the distance between two buffers. */
1338 1339
1339 protected: 1340 protected:
1340 inline Distance *make(const QString &description) { return make(description, this); } /*!< \brief Make a subdistance. */ 1341 inline Distance *make(const QString &description) { return make(description, this); } /*!< \brief Make a subdistance. */
openbr/plugins/distance.cpp
@@ -282,9 +282,9 @@ class ByteL1Distance : public Distance @@ -282,9 +282,9 @@ class ByteL1Distance : public Distance
282 { 282 {
283 Q_OBJECT 283 Q_OBJECT
284 284
285 - float compare(const Mat &a, const Mat &b) const 285 + float compare(const unsigned char *a, const unsigned char *b, size_t size) const
286 { 286 {
287 - return l1(a.data, b.data, a.total()); 287 + return l1(a, b, size);
288 } 288 }
289 }; 289 };
290 290
openbr/universal_template.cpp
@@ -27,7 +27,7 @@ void br_append_utemplate(FILE *file, br_const_utemplate utemplate) @@ -27,7 +27,7 @@ void br_append_utemplate(FILE *file, br_const_utemplate utemplate)
27 br_append_utemplate_contents(file, utemplate->imageID, utemplate->templateID, utemplate->algorithmID, utemplate->size, utemplate->data); 27 br_append_utemplate_contents(file, utemplate->imageID, utemplate->templateID, utemplate->algorithmID, utemplate->size, utemplate->data);
28 } 28 }
29 29
30 -void br_append_utemplate_contents(FILE *file, const int8_t *imageID, const int8_t *templateID, int32_t algorithmID, uint32_t size, const int8_t *data) 30 +void br_append_utemplate_contents(FILE *file, const int8_t *imageID, const int8_t *templateID, int32_t algorithmID, uint32_t size, const unsigned char *data)
31 { 31 {
32 static QMutex lock; 32 static QMutex lock;
33 QMutexLocker locker(&lock); 33 QMutexLocker locker(&lock);
@@ -39,15 +39,15 @@ void br_append_utemplate_contents(FILE *file, const int8_t *imageID, const int8_ @@ -39,15 +39,15 @@ void br_append_utemplate_contents(FILE *file, const int8_t *imageID, const int8_
39 fwrite(data, 1, size, file); 39 fwrite(data, 1, size, file);
40 } 40 }
41 41
42 -void br_iterate_utemplates(br_const_utemplate begin, br_const_utemplate end, br_utemplate_callback callback) 42 +void br_iterate_utemplates(br_const_utemplate begin, br_const_utemplate end, br_utemplate_callback callback, br_callback_context context)
43 { 43 {
44 while (begin != end) { 44 while (begin != end) {
45 - callback(begin); 45 + callback(begin, context);
46 begin = reinterpret_cast<br_const_utemplate>(reinterpret_cast<const char*>(begin) + sizeof(br_const_utemplate) + begin->size); 46 begin = reinterpret_cast<br_const_utemplate>(reinterpret_cast<const char*>(begin) + sizeof(br_const_utemplate) + begin->size);
47 } 47 }
48 } 48 }
49 49
50 -void br_iterate_utemplates_file(FILE *file, br_utemplate_callback callback) 50 +void br_iterate_utemplates_file(FILE *file, br_utemplate_callback callback, br_callback_context context)
51 { 51 {
52 while (!feof(file)) { 52 while (!feof(file)) {
53 br_utemplate t = (br_utemplate) malloc(sizeof(br_universal_template)); 53 br_utemplate t = (br_utemplate) malloc(sizeof(br_universal_template));
@@ -56,7 +56,7 @@ void br_iterate_utemplates_file(FILE *file, br_utemplate_callback callback) @@ -56,7 +56,7 @@ void br_iterate_utemplates_file(FILE *file, br_utemplate_callback callback)
56 t = (br_utemplate) realloc(t, sizeof(br_universal_template) + t->size); 56 t = (br_utemplate) realloc(t, sizeof(br_universal_template) + t->size);
57 if (fread(t+1, 1, t->size, file) != t->size) 57 if (fread(t+1, 1, t->size, file) != t->size)
58 qFatal("Unexepected EOF when reading universal template data."); 58 qFatal("Unexepected EOF when reading universal template data.");
59 - callback(t); 59 + callback(t, context);
60 } 60 }
61 61
62 free(t); 62 free(t);
openbr/universal_template.h
@@ -34,7 +34,7 @@ struct br_universal_template @@ -34,7 +34,7 @@ struct br_universal_template
34 int8_t templateID[16]; /*!< MD5 hash of _data_. */ 34 int8_t templateID[16]; /*!< MD5 hash of _data_. */
35 int32_t algorithmID; /*!< type of _data_. */ 35 int32_t algorithmID; /*!< type of _data_. */
36 uint32_t size; /*!< length of _data_. */ 36 uint32_t size; /*!< length of _data_. */
37 - int8_t data[]; /*!< _size_-byte buffer. */ 37 + unsigned char data[]; /*!< _size_-byte buffer. */
38 }; 38 };
39 39
40 typedef struct br_universal_template *br_utemplate; 40 typedef struct br_universal_template *br_utemplate;
@@ -62,25 +62,26 @@ BR_EXPORT void br_append_utemplate(FILE *file, br_const_utemplate utemplate); @@ -62,25 +62,26 @@ BR_EXPORT void br_append_utemplate(FILE *file, br_const_utemplate utemplate);
62 * \brief Serialize a br_universal_template to a file. 62 * \brief Serialize a br_universal_template to a file.
63 * \see br_append_utemplate 63 * \see br_append_utemplate
64 */ 64 */
65 -BR_EXPORT void br_append_utemplate_contents(FILE *file, const int8_t *imageID, const int8_t *templateID, int32_t algorithmID, uint32_t size, const int8_t *data); 65 +BR_EXPORT void br_append_utemplate_contents(FILE *file, const int8_t *imageID, const int8_t *templateID, int32_t algorithmID, uint32_t size, const unsigned char *data);
66 66
67 /*! 67 /*!
68 * \brief br_universal_template iterator callback. 68 * \brief br_universal_template iterator callback.
69 * \see br_iterate_utemplates 69 * \see br_iterate_utemplates
70 */ 70 */
71 -typedef void (*br_utemplate_callback)(br_const_utemplate); 71 +typedef void *br_callback_context;
  72 +typedef void (*br_utemplate_callback)(br_const_utemplate, br_callback_context);
72 73
73 /*! 74 /*!
74 * \brief Iterate over an inplace array of br_universal_template. 75 * \brief Iterate over an inplace array of br_universal_template.
75 * \see br_iterate_utemplates_file 76 * \see br_iterate_utemplates_file
76 */ 77 */
77 -BR_EXPORT void br_iterate_utemplates(br_const_utemplate begin, br_const_utemplate end, br_utemplate_callback callback); 78 +BR_EXPORT void br_iterate_utemplates(br_const_utemplate begin, br_const_utemplate end, br_utemplate_callback callback, br_callback_context context);
78 79
79 /*! 80 /*!
80 * \brief Iterate over br_universal_template in a file. 81 * \brief Iterate over br_universal_template in a file.
81 * \see br_iterate_utemplates 82 * \see br_iterate_utemplates
82 */ 83 */
83 -BR_EXPORT void br_iterate_utemplates_file(FILE *file, br_utemplate_callback callback); 84 +BR_EXPORT void br_iterate_utemplates_file(FILE *file, br_utemplate_callback callback, br_callback_context context);
84 85
85 #ifdef __cplusplus 86 #ifdef __cplusplus
86 } 87 }