Commit 579dd923923df24348f9e55c730a91e2031d7e93
1 parent
66458eae
progress on br-search
Showing
5 changed files
with
82 additions
and
37 deletions
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 unsigned char*>(data.data())); | |
| 64 | + br_append_utemplate_contents(stdout, reinterpret_cast<const unsigned char*>(hash.data()), reinterpret_cast<const unsigned char*>(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
| ... | ... | @@ -54,7 +54,7 @@ static void enroll_utemplate(br_const_utemplate utemplate, br_callback_context) |
| 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, m.data); | |
| 57 | + br_append_utemplate_contents(stdout, utemplate->imageID, (const unsigned char*) templateID.data(), -1, size, m.data); | |
| 58 | 58 | } |
| 59 | 59 | } |
| 60 | 60 | ... | ... |
app/br-search/br-search.cpp
| ... | ... | @@ -17,12 +17,17 @@ |
| 17 | 17 | #include <QtCore> |
| 18 | 18 | #include <cstdio> |
| 19 | 19 | #include <cstring> |
| 20 | +#include <iomanip> | |
| 21 | +#include <iostream> | |
| 20 | 22 | #include <limits> |
| 23 | +#include <utility> | |
| 24 | +#include <vector> | |
| 21 | 25 | #include <openbr/openbr_plugin.h> |
| 22 | 26 | #include <openbr/universal_template.h> |
| 23 | 27 | |
| 24 | 28 | using namespace br; |
| 25 | 29 | using namespace cv; |
| 30 | +using namespace std; | |
| 26 | 31 | |
| 27 | 32 | static void help() |
| 28 | 33 | { |
| ... | ... | @@ -34,52 +39,94 @@ static void help() |
| 34 | 39 | "_br-search_ does retrieval by comparing query templates to target gallery(s).\n" |
| 35 | 40 | "The search strategy is implementation defined.\n" |
| 36 | 41 | "\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" | |
| 42 | + "For every template read from _stdin_, search writes the top sorted matches a newline-terminated JSON object to _stdout_.\n" | |
| 43 | + "The JSON object will include at least `AlgorithmID`, (query) `ImageID`, (query) `TemplateID`, `Targets` and any algorithm-specific metadata fields set during _enroll_.\n" | |
| 39 | 44 | "\n" |
| 40 | 45 | "Optional Arguments\n" |
| 41 | 46 | "------------------\n" |
| 42 | - "* -help - Print usage information.\n" | |
| 43 | - "* -limit <int> - Maximum number of returns (20 otherwise).\n"); | |
| 47 | + "* -help - Print usage information.\n" | |
| 48 | + "* -limit <int> - Maximum number of returns (20 otherwise).\n" | |
| 49 | + "* -threshold <float> - Minimum similarity score (none otherwise)."); | |
| 44 | 50 | } |
| 45 | 51 | |
| 46 | -static int limit = 20; | |
| 47 | -static float threshold = -std::numeric_limits<float>::max(); | |
| 52 | +static size_t limit = 20; | |
| 53 | +static float threshold = -numeric_limits<float>::max(); | |
| 48 | 54 | |
| 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> > | |
| 55 | +struct SearchResults | |
| 57 | 56 | { |
| 57 | + typedef pair<float, br_const_utemplate> Target; | |
| 58 | + vector<Target> topTargets; | |
| 58 | 59 | br_const_utemplate query; |
| 59 | 60 | |
| 60 | - TopTargets(br_const_utemplate query) | |
| 61 | + SearchResults(br_const_utemplate query) | |
| 61 | 62 | : query(query) {} |
| 62 | 63 | |
| 63 | - void tryAdd(br_const_utemplate target, float score) | |
| 64 | + virtual ~SearchResults() {} | |
| 65 | + | |
| 66 | + void consider(br_const_utemplate target) | |
| 64 | 67 | { |
| 65 | - if ((score < threshold) || ((size() == limit) && (score < last().second))) | |
| 68 | + const float score = compare(target, query); | |
| 69 | + if ((score < threshold) || ((topTargets.size() == limit) && (score < topTargets.front().first))) | |
| 66 | 70 | return; |
| 67 | - (void) target; | |
| 71 | + | |
| 72 | + topTargets.push_back(Target(score, target)); | |
| 73 | + make_heap(topTargets.begin(), topTargets.end()); | |
| 74 | + | |
| 75 | + if (topTargets.size() == limit + 1) | |
| 76 | + pop_heap(topTargets.begin(), topTargets.end()); | |
| 68 | 77 | } |
| 69 | 78 | |
| 70 | - void print() const | |
| 79 | + static void writeMD5asHex(const unsigned char *md5) | |
| 71 | 80 | { |
| 81 | + cout << hex << setfill('0'); | |
| 82 | + for (int i=0; i<16; i++) | |
| 83 | + cout << setw(2) << md5[i]; | |
| 84 | + cout << dec; | |
| 85 | + } | |
| 72 | 86 | |
| 87 | + void print() | |
| 88 | + { | |
| 89 | + sort_heap(topTargets.begin(), topTargets.end()); | |
| 90 | + | |
| 91 | + cout << "{ \"AlgorithmID\"=" << query->algorithmID; | |
| 92 | + cout << ", \"QueryImageID\"="; | |
| 93 | + writeMD5asHex(query->imageID); | |
| 94 | + cout << ", \"QueryTemplateID\"="; | |
| 95 | + writeMD5asHex(query->templateID); | |
| 96 | + printMetadata(query); | |
| 97 | + cout << ", \"Targets\"=[ "; | |
| 98 | + for (int i=topTargets.size()-1; i>=0; i--) { | |
| 99 | + Target &target = topTargets[i]; | |
| 100 | + cout << "{ \"ImageID\"="; | |
| 101 | + writeMD5asHex(target.second->imageID); | |
| 102 | + cout << ", \"TemplateID\"="; | |
| 103 | + writeMD5asHex(target.second->templateID); | |
| 104 | + cout << ", \"Score\"=" << target.first; | |
| 105 | + printMetadata(target.second); | |
| 106 | + cout << " }"; | |
| 107 | + if (i > 0) | |
| 108 | + cout << ", "; | |
| 109 | + } | |
| 110 | + cout << "]}\n" << flush; | |
| 73 | 111 | } |
| 112 | + | |
| 113 | + virtual float compare(br_const_utemplate target, br_const_utemplate query) const = 0; | |
| 114 | + virtual void printMetadata(br_const_utemplate) const { return; } | |
| 74 | 115 | }; |
| 75 | 116 | |
| 76 | -struct FaceRecognitionResult : public Result | |
| 117 | +struct FaceRecognition : public SearchResults | |
| 77 | 118 | { |
| 78 | - int32_t x, y, width, height; | |
| 119 | + QSharedPointer<Distance> algorithm; | |
| 120 | + | |
| 121 | + FaceRecognition(br_const_utemplate query) | |
| 122 | + : SearchResults(query) | |
| 123 | + { | |
| 124 | + algorithm = Distance::fromAlgorithm("FaceRecognition"); | |
| 125 | + } | |
| 79 | 126 | |
| 80 | - FaceRecognitionResult() | |
| 127 | + float compare(br_const_utemplate target, br_const_utemplate query) const | |
| 81 | 128 | { |
| 82 | - algorithmID = -1; | |
| 129 | + return algorithm->compare(target->data, query->data, 768); | |
| 83 | 130 | } |
| 84 | 131 | }; |
| 85 | 132 | |
| ... | ... | @@ -102,22 +149,21 @@ struct MappedGallery |
| 102 | 149 | } |
| 103 | 150 | }; |
| 104 | 151 | |
| 105 | -static QSharedPointer<Distance> distance; | |
| 106 | 152 | static QList<MappedGallery> galleries; |
| 107 | 153 | |
| 108 | 154 | static void compare_utemplates(br_const_utemplate target, br_callback_context context) |
| 109 | 155 | { |
| 110 | - TopTargets *topTargets = (TopTargets*) context; | |
| 111 | - topTargets->tryAdd(target, distance->compare(target->data, topTargets->query->data, 768)); | |
| 156 | + SearchResults *searchResults = (SearchResults*) context; | |
| 157 | + searchResults->consider(target); | |
| 112 | 158 | } |
| 113 | 159 | |
| 114 | 160 | static void search_utemplate(br_const_utemplate query, br_callback_context) |
| 115 | 161 | { |
| 116 | - TopTargets *topTargets = new TopTargets(query); | |
| 162 | + SearchResults *searchResults = new FaceRecognition(query); | |
| 117 | 163 | 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; | |
| 164 | + br_iterate_utemplates(reinterpret_cast<br_const_utemplate>(gallery.data), reinterpret_cast<br_const_utemplate>(gallery.data + gallery.size), compare_utemplates, searchResults); | |
| 165 | + searchResults->print(); | |
| 166 | + delete searchResults; | |
| 121 | 167 | } |
| 122 | 168 | |
| 123 | 169 | int main(int argc, char *argv[]) |
| ... | ... | @@ -136,7 +182,6 @@ int main(int argc, char *argv[]) |
| 136 | 182 | galleries.append(MappedGallery(url)); |
| 137 | 183 | |
| 138 | 184 | Globals->quiet = true; |
| 139 | - distance = Distance::fromAlgorithm("FaceRecognition"); | |
| 140 | 185 | br_iterate_utemplates_file(stdin, search_utemplate, NULL); |
| 141 | 186 | |
| 142 | 187 | Context::finalize(); | ... | ... |
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 unsigned char *data) | |
| 30 | +void br_append_utemplate_contents(FILE *file, const unsigned char *imageID, const unsigned char *templateID, int32_t algorithmID, uint32_t size, const unsigned char *data) | |
| 31 | 31 | { |
| 32 | 32 | static QMutex lock; |
| 33 | 33 | QMutexLocker locker(&lock); | ... | ... |
openbr/universal_template.h
| ... | ... | @@ -30,8 +30,8 @@ extern "C" { |
| 30 | 30 | */ |
| 31 | 31 | struct br_universal_template |
| 32 | 32 | { |
| 33 | - int8_t imageID[16]; /*!< MD5 hash of the undecoded origin file. */ | |
| 34 | - int8_t templateID[16]; /*!< MD5 hash of _data_. */ | |
| 33 | + unsigned char imageID[16]; /*!< MD5 hash of the undecoded origin file. */ | |
| 34 | + unsigned char templateID[16]; /*!< MD5 hash of _data_. */ | |
| 35 | 35 | int32_t algorithmID; /*!< type of _data_. */ |
| 36 | 36 | uint32_t size; /*!< length of _data_. */ |
| 37 | 37 | unsigned char data[]; /*!< _size_-byte buffer. */ |
| ... | ... | @@ -62,7 +62,7 @@ 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 unsigned char *data); | |
| 65 | +BR_EXPORT void br_append_utemplate_contents(FILE *file, const unsigned char *imageID, const unsigned char *templateID, int32_t algorithmID, uint32_t size, const unsigned char *data); | |
| 66 | 66 | |
| 67 | 67 | /*! |
| 68 | 68 | * \brief br_universal_template iterator callback. | ... | ... |