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 10 add_subdirectory(br-crawl)
11 11 add_subdirectory(br-enroll)
12 12 add_subdirectory(br-gui)
  13 + add_subdirectory(br-search)
13 14 endif()
... ...
app/br-download/br-download.cpp
... ... @@ -61,7 +61,7 @@ static bool processReply(QNetworkReply* reply)
61 61 return false;
62 62  
63 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 65 return true;
66 66 }
67 67  
... ...
app/br-enroll/br-enroll.cpp
... ... @@ -41,7 +41,7 @@ static void help()
41 41  
42 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 46 if (utemplate->algorithmID != 3)
47 47 qFatal("Expected an encoded image.");
... ... @@ -54,7 +54,7 @@ static void enroll_utemplate(br_const_utemplate utemplate)
54 54 const Mat &m = t.m();
55 55 const uint32_t size = m.rows * m.cols * m.elemSize();
56 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 66 Context::initialize(argc, argv, "", false);
67 67 Globals->quiet = true;
68 68 algorithm = Transform::fromAlgorithm("FaceRecognition");
69   - br_iterate_utemplates_file(stdin, enroll_utemplate);
  69 + br_iterate_utemplates_file(stdin, enroll_utemplate, NULL);
70 70 Context::finalize();
71 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 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 1415 qFatal("Logic error: %s did not implement a comparison function or was accessed at an unsupported level of abstraction.", metaObject()->className());
1411 1416 return -std::numeric_limits<float>::max();
... ...
openbr/openbr_plugin.h
... ... @@ -1335,6 +1335,7 @@ public:
1335 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 1336 virtual float compare(const Template &a, const Template &b) const; /*!< \brief Compute the distance between two templates. */
1337 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 1340 protected:
1340 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 282 {
283 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 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 32 static QMutex lock;
33 33 QMutexLocker locker(&lock);
... ... @@ -39,15 +39,15 @@ void br_append_utemplate_contents(FILE *file, const int8_t *imageID, const int8_
39 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 44 while (begin != end) {
45   - callback(begin);
  45 + callback(begin, context);
46 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 52 while (!feof(file)) {
53 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 56 t = (br_utemplate) realloc(t, sizeof(br_universal_template) + t->size);
57 57 if (fread(t+1, 1, t->size, file) != t->size)
58 58 qFatal("Unexepected EOF when reading universal template data.");
59   - callback(t);
  59 + callback(t, context);
60 60 }
61 61  
62 62 free(t);
... ...
openbr/universal_template.h
... ... @@ -34,7 +34,7 @@ struct br_universal_template
34 34 int8_t templateID[16]; /*!< MD5 hash of _data_. */
35 35 int32_t algorithmID; /*!< type of _data_. */
36 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 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 62 * \brief Serialize a br_universal_template to a file.
63 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 68 * \brief br_universal_template iterator callback.
69 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 75 * \brief Iterate over an inplace array of br_universal_template.
75 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 81 * \brief Iterate over br_universal_template in a file.
81 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 86 #ifdef __cplusplus
86 87 }
... ...