Commit 3ef48e1b097ba0f9cd9d3d88d134417e83254d3d
1 parent
278fa768
removed public support for br-search and br-serve
Showing
5 changed files
with
0 additions
and
407 deletions
app/CMakeLists.txt
app/br-search/CMakeLists.txt deleted
app/br-search/br-search.cpp deleted
| 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 <iomanip> | |
| 21 | -#include <iostream> | |
| 22 | -#include <limits> | |
| 23 | -#include <utility> | |
| 24 | -#include <vector> | |
| 25 | -#include <openbr/openbr_plugin.h> | |
| 26 | -#include <openbr/universal_template.h> | |
| 27 | - | |
| 28 | -using namespace br; | |
| 29 | -using namespace cv; | |
| 30 | -using namespace std; | |
| 31 | - | |
| 32 | -static void help() | |
| 33 | -{ | |
| 34 | - printf("br-search URL(s) [args]\n" | |
| 35 | - "=======================\n" | |
| 36 | - "* __stdin__ - Templates (feature vectors)\n" | |
| 37 | - "* __stdout__ - JSON\n" | |
| 38 | - "\n" | |
| 39 | - "_br-search_ does retrieval by comparing query templates to target gallery(s).\n" | |
| 40 | - "The search strategy is implementation defined.\n" | |
| 41 | - "\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" | |
| 44 | - "\n" | |
| 45 | - "Optional Arguments\n" | |
| 46 | - "------------------\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)."); | |
| 50 | -} | |
| 51 | - | |
| 52 | -static size_t limit = 20; | |
| 53 | -static float threshold = -numeric_limits<float>::max(); | |
| 54 | - | |
| 55 | -struct MappedGallery | |
| 56 | -{ | |
| 57 | - QSharedPointer<QFile> file; | |
| 58 | - qint64 size; | |
| 59 | - uchar *data; | |
| 60 | - | |
| 61 | - MappedGallery(QString url) | |
| 62 | - { | |
| 63 | - if (url.startsWith("file://")) | |
| 64 | - url = url.mid(7); | |
| 65 | - file.reset(new QFile(url)); | |
| 66 | - file->open(QFile::ReadOnly); | |
| 67 | - size = file->size(); | |
| 68 | - data = file->map(0, size); | |
| 69 | - if (data == NULL) | |
| 70 | - qFatal("Unable to map gallery: %s", qPrintable(url)); | |
| 71 | - } | |
| 72 | -}; | |
| 73 | - | |
| 74 | -static QList<MappedGallery> galleries; | |
| 75 | - | |
| 76 | -struct SearchResults | |
| 77 | -{ | |
| 78 | - typedef pair<float, br_const_utemplate> Target; | |
| 79 | - vector<Target> topTargets; | |
| 80 | - br_const_utemplate query; | |
| 81 | - | |
| 82 | - SearchResults(br_const_utemplate query) | |
| 83 | - : query(query) {} | |
| 84 | - | |
| 85 | - virtual ~SearchResults() {} | |
| 86 | - | |
| 87 | - virtual void consider(const MappedGallery &gallery) | |
| 88 | - { | |
| 89 | - br_iterate_utemplates(reinterpret_cast<br_const_utemplate>(gallery.data), reinterpret_cast<br_const_utemplate>(gallery.data + gallery.size), compare_utemplates, this); | |
| 90 | - } | |
| 91 | - | |
| 92 | - void print() | |
| 93 | - { | |
| 94 | - sort_heap(topTargets.begin(), topTargets.end()); | |
| 95 | - | |
| 96 | - cout << "{ \"AlgorithmID\":" << query->algorithmID; | |
| 97 | - cout << ", \"ImageID\":\""; | |
| 98 | - writeMD5asHex(query->imageID); | |
| 99 | - cout << "\", \"TemplateID\":\""; | |
| 100 | - writeMD5asHex(query->templateID); | |
| 101 | - cout << "\""; | |
| 102 | - printMetadata(query); | |
| 103 | - cout << ", \"Targets\":[ "; | |
| 104 | - for (int i=topTargets.size()-1; i>=0; i--) { | |
| 105 | - Target &target = topTargets[i]; | |
| 106 | - cout << "{ \"ImageID\":\""; | |
| 107 | - writeMD5asHex(target.second->imageID); | |
| 108 | - cout << "\", \"TemplateID\":\""; | |
| 109 | - writeMD5asHex(target.second->templateID); | |
| 110 | - cout << "\", \"Score\":" << target.first; | |
| 111 | - printMetadata(target.second); | |
| 112 | - cout << " }"; | |
| 113 | - if (i > 0) | |
| 114 | - cout << ", "; | |
| 115 | - } | |
| 116 | - cout << "] }\n" << flush; | |
| 117 | - } | |
| 118 | - | |
| 119 | -private: | |
| 120 | - void consider(br_const_utemplate target) | |
| 121 | - { | |
| 122 | - if (target->algorithmID != query->algorithmID) | |
| 123 | - return; | |
| 124 | - | |
| 125 | - const float score = compare(target, query); | |
| 126 | - if ((score < threshold) || ((topTargets.size() == limit) && (score < topTargets.front().first))) | |
| 127 | - return; | |
| 128 | - | |
| 129 | - topTargets.push_back(Target(score, target)); | |
| 130 | - make_heap(topTargets.begin(), topTargets.end()); | |
| 131 | - | |
| 132 | - if (topTargets.size() == limit + 1) | |
| 133 | - pop_heap(topTargets.begin(), topTargets.end()); | |
| 134 | - } | |
| 135 | - | |
| 136 | - static void compare_utemplates(br_const_utemplate target, br_callback_context context) | |
| 137 | - { | |
| 138 | - SearchResults *searchResults = (SearchResults*) context; | |
| 139 | - searchResults->consider(target); | |
| 140 | - } | |
| 141 | - | |
| 142 | - static void writeMD5asHex(const unsigned char *md5) | |
| 143 | - { | |
| 144 | - const char prevFill = cout.fill(); | |
| 145 | - cout << hex << setfill('0'); | |
| 146 | - for (int i=0; i<16; i++) | |
| 147 | - cout << setw(2) << int(md5[i]); | |
| 148 | - cout << dec; | |
| 149 | - setfill(prevFill); | |
| 150 | - } | |
| 151 | - | |
| 152 | - virtual float compare(br_const_utemplate target, br_const_utemplate query) const = 0; | |
| 153 | - virtual void printMetadata(br_const_utemplate) const { return; } | |
| 154 | -}; | |
| 155 | - | |
| 156 | -struct VoidSearch : public SearchResults | |
| 157 | -{ | |
| 158 | - VoidSearch(br_const_utemplate query) | |
| 159 | - : SearchResults(query) {} | |
| 160 | - | |
| 161 | -private: | |
| 162 | - void consider(const MappedGallery &) { return; } | |
| 163 | - float compare(br_const_utemplate, br_const_utemplate) const { return 0; } | |
| 164 | -}; | |
| 165 | - | |
| 166 | -struct ImageID : public SearchResults | |
| 167 | -{ | |
| 168 | - ImageID(br_const_utemplate query) | |
| 169 | - : SearchResults(query) {} | |
| 170 | - | |
| 171 | -private: | |
| 172 | - float compare(br_const_utemplate target, br_const_utemplate query) const | |
| 173 | - { | |
| 174 | - return !memcmp(&target->imageID, &query->imageID, sizeof(target->imageID)); | |
| 175 | - } | |
| 176 | - | |
| 177 | - void printMetadata(br_const_utemplate t) const | |
| 178 | - { | |
| 179 | - cout << ", \"Data\":\"" << reinterpret_cast<const char*>(&t->data) << "\""; | |
| 180 | - } | |
| 181 | -}; | |
| 182 | - | |
| 183 | -struct FaceRecognition : public SearchResults | |
| 184 | -{ | |
| 185 | - FaceRecognition(br_const_utemplate query) | |
| 186 | - : SearchResults(query) | |
| 187 | - { | |
| 188 | - algorithm = Distance::fromAlgorithm("FaceRecognition"); | |
| 189 | - } | |
| 190 | - | |
| 191 | -private: | |
| 192 | - QSharedPointer<Distance> algorithm; | |
| 193 | - | |
| 194 | - float compare(br_const_utemplate target, br_const_utemplate query) const | |
| 195 | - { | |
| 196 | - return algorithm->compare(target->data, query->data, 768); | |
| 197 | - } | |
| 198 | - | |
| 199 | - void printMetadata(br_const_utemplate t) const | |
| 200 | - { | |
| 201 | - const float *metadata = reinterpret_cast<const float*>(&t->data[768]); | |
| 202 | - cout << ", \"X\":" << metadata[0] | |
| 203 | - << ", \"Y\":" << metadata[1] | |
| 204 | - << ", \"Width\":" << metadata[2] | |
| 205 | - << ", \"Height\":" << metadata[3] | |
| 206 | - << ", \"RightEyeX\":" << metadata[4] | |
| 207 | - << ", \"RightEyeY\":" << metadata[5] | |
| 208 | - << ", \"LeftEyeX\":" << metadata[6] | |
| 209 | - << ", \"LeftEyeY\":" << metadata[7]; | |
| 210 | - } | |
| 211 | -}; | |
| 212 | - | |
| 213 | -static void search_utemplate(br_const_utemplate query, br_callback_context) | |
| 214 | -{ | |
| 215 | - SearchResults *searchResults = NULL; | |
| 216 | - switch (query->algorithmID) { | |
| 217 | - case 0: searchResults = new VoidSearch(query); break; | |
| 218 | - case 2: searchResults = new ImageID(query); break; | |
| 219 | - case -1: searchResults = new FaceRecognition(query); break; | |
| 220 | - } | |
| 221 | - if (!searchResults) | |
| 222 | - qFatal("Unsupported AlgorithmID: %d", query->algorithmID); | |
| 223 | - | |
| 224 | - foreach (const MappedGallery &gallery, galleries) | |
| 225 | - searchResults->consider(gallery); | |
| 226 | - searchResults->print(); | |
| 227 | - delete searchResults; | |
| 228 | -} | |
| 229 | - | |
| 230 | -int main(int argc, char *argv[]) | |
| 231 | -{ | |
| 232 | - QStringList urls; | |
| 233 | - for (int i=1; i<argc; i++) { | |
| 234 | - if (!strcmp(argv[i], "-help" )) { help(); exit(EXIT_SUCCESS); } | |
| 235 | - else if (!strcmp(argv[i], "-limit")) limit = atoi(argv[++i]); | |
| 236 | - else if (!strcmp(argv[i], "-threshold")) threshold = atof(argv[++i]); | |
| 237 | - else urls.append(argv[i]); | |
| 238 | - } | |
| 239 | - | |
| 240 | - Context::initialize(argc, argv, "", false); | |
| 241 | - | |
| 242 | - foreach (const QString &url, urls) | |
| 243 | - galleries.append(MappedGallery(url)); | |
| 244 | - | |
| 245 | - Globals->quiet = true; | |
| 246 | - br_iterate_utemplates_file(stdin, search_utemplate, NULL, false); | |
| 247 | - | |
| 248 | - Context::finalize(); | |
| 249 | - return EXIT_SUCCESS; | |
| 250 | -} |
app/br-serve/CMakeLists.txt deleted
| 1 | -set(QHTTPSERVER_DIR "${CMAKE_SOURCE_DIR}/3rdparty/qhttpserver") | |
| 2 | -set(QHTTPSERVER_SRC ${QHTTPSERVER_DIR}/src/qhttpconnection.cpp | |
| 3 | - ${QHTTPSERVER_DIR}/src/qhttpresponse.cpp | |
| 4 | - ${QHTTPSERVER_DIR}/src/qhttprequest.cpp | |
| 5 | - ${QHTTPSERVER_DIR}/src/qhttpserver.cpp | |
| 6 | - ${QHTTPSERVER_DIR}/http-parser/http_parser.c) | |
| 7 | -add_definitions(-DQHTTPSERVER_EXPORT) | |
| 8 | -include_directories(${CMAKE_SOURCE_DIR}/3rdparty/qhttpserver/src | |
| 9 | - ${CMAKE_SOURCE_DIR}/3rdparty/qhttpserver/http-parser | |
| 10 | - ${CMAKE_CURRENT_BINARY_DIR}) | |
| 11 | -add_executable(br-serve br-serve.cpp ${QHTTPSERVER_SRC} ${BR_RESOURCES}) | |
| 12 | -target_link_libraries(br-serve openbr ${BR_THIRDPARTY_LIBS}) | |
| 13 | -qt5_use_modules(br-serve ${QT_DEPENDENCIES}) | |
| 14 | -install(TARGETS br-serve RUNTIME DESTINATION bin) |
app/br-serve/br-serve.cpp deleted
| 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 <QtNetwork> | |
| 19 | -#include <cstdio> | |
| 20 | -#include <cstring> | |
| 21 | -#include <qhttpserver.h> | |
| 22 | -#include <qhttprequest.h> | |
| 23 | -#include <qhttpresponse.h> | |
| 24 | -#include <openbr/universal_template.h> | |
| 25 | - | |
| 26 | -static void help() | |
| 27 | -{ | |
| 28 | - printf("br-serve [command]\n" | |
| 29 | - "==================\n" | |
| 30 | - "\n" | |
| 31 | - "_br-serve_ converts the command's stdin/stdout into a web service.\n" | |
| 32 | - "\n" | |
| 33 | - "Optional Arguments\n" | |
| 34 | - "------------------\n" | |
| 35 | - "* -help - Print usage information.\n" | |
| 36 | - "* -port <int> - The port to communicate on (80 otherwise)."); | |
| 37 | -} | |
| 38 | - | |
| 39 | -static int port = 80; | |
| 40 | -static QProcess process; | |
| 41 | - | |
| 42 | -class Handler : public QObject | |
| 43 | -{ | |
| 44 | - Q_OBJECT | |
| 45 | - | |
| 46 | -public slots: | |
| 47 | - void handle(QHttpRequest *request, QHttpResponse *response) | |
| 48 | - { | |
| 49 | - QByteArray message; | |
| 50 | - | |
| 51 | - const QUrlQuery urlQuery(request->url()); | |
| 52 | - if (urlQuery.hasQueryItem("URL")) { | |
| 53 | - process.write(qPrintable(QString(urlQuery.queryItemValue("URL") + "\n"))); | |
| 54 | - process.waitForReadyRead(); | |
| 55 | - if (process.error() != QProcess::UnknownError) | |
| 56 | - qFatal("%s\n", qPrintable(process.errorString())); | |
| 57 | - message = process.readLine(); | |
| 58 | - response->setHeader("Content-Type", "application/json"); | |
| 59 | - } else if (urlQuery.hasQueryItem("ImageID")) { | |
| 60 | - const QByteArray imageID = QByteArray::fromHex(urlQuery.queryItemValue("ImageID").toLatin1()); | |
| 61 | - if (imageID.size() == 16) { | |
| 62 | - br_universal_template in; | |
| 63 | - in.algorithmID = 2; | |
| 64 | - memcpy(&in.imageID, imageID.data(), 16); | |
| 65 | - memset(in.templateID, 0, 16); | |
| 66 | - in.size = 0; | |
| 67 | - | |
| 68 | - process.write((const char *)&in, sizeof(br_universal_template)); | |
| 69 | - process.waitForReadyRead(); | |
| 70 | - if (process.error() != QProcess::UnknownError) | |
| 71 | - qFatal("%s\n", qPrintable(process.errorString())); | |
| 72 | - | |
| 73 | - br_utemplate out = (br_utemplate) malloc(sizeof(br_universal_template)); | |
| 74 | - if (process.read((char*) out, sizeof(br_universal_template)) == sizeof(br_universal_template)) { | |
| 75 | - out = (br_utemplate) realloc(out, sizeof(br_universal_template) + out->size); | |
| 76 | - if (process.read(reinterpret_cast<char*>(out+1), out->size) != out->size) | |
| 77 | - qFatal("Unexepected EOF when reading universal template data."); | |
| 78 | - message = QByteArray((char*)&out->data, out->size); | |
| 79 | - } | |
| 80 | - free(out); | |
| 81 | - } | |
| 82 | - response->setHeader("Content-Type", "image/jpeg"); | |
| 83 | - } else { | |
| 84 | - QString path = request->path(); | |
| 85 | - if (path == "/") | |
| 86 | - path = "localhost"; | |
| 87 | - message = QString("<!DOCTYPE html>\n" | |
| 88 | - "<html>\n" | |
| 89 | - "<head>\n" | |
| 90 | - " <title>Web Services API</title>\n" | |
| 91 | - "</head>\n" | |
| 92 | - "\n" | |
| 93 | - "<body>\n" | |
| 94 | - " <h1><a href=\"http://en.wikipedia.org/wiki/Query_string\">Query String</a> Parameters</h1>" | |
| 95 | - " <ul>\n" | |
| 96 | - " <li><b>URL</b> - Query URL for image search.</li>\n" | |
| 97 | - " <li><b>ImageID</b> - Query ImageID for image retrieval.</li>\n" | |
| 98 | - " </ul>\n" | |
| 99 | - " <h1>Examples</h1>\n" | |
| 100 | - " <ul>\n" | |
| 101 | - " <li>http://%1%2/?URL=data.liblikely.org/misc/lenna.tiff</li>\n" | |
| 102 | - " <li>http://%1%2/?ImageID=ecaee0b4cd73a76dd2a8060b2909a4a1</li>\n" | |
| 103 | - " </ul>\n" | |
| 104 | - "</body>\n" | |
| 105 | - "</html>").arg(path, port == 80 ? QString() : (QString(":") + QString::number(port))).toLatin1(); | |
| 106 | - response->setHeader("Content-Type", "text/html"); | |
| 107 | - } | |
| 108 | - | |
| 109 | - response->setHeader("Content-Length", QString::number(message.size())); | |
| 110 | - response->writeHead(200); // everything is OK | |
| 111 | - response->write(message); | |
| 112 | - response->end(); | |
| 113 | - } | |
| 114 | -}; | |
| 115 | - | |
| 116 | -int main(int argc, char *argv[]) | |
| 117 | -{ | |
| 118 | - QCoreApplication application(argc, argv); | |
| 119 | - | |
| 120 | - for (int i=1; i<argc; i++) { | |
| 121 | - if (!strcmp(argv[i], "-help")) { help(); exit(EXIT_SUCCESS); } | |
| 122 | - else if (!strcmp(argv[i], "-port")) port = atoi(argv[++i]); | |
| 123 | - else process.start(argv[i]); | |
| 124 | - } | |
| 125 | - | |
| 126 | - QHttpServer server; | |
| 127 | - Handler handler; | |
| 128 | - QObject::connect(&server, SIGNAL(newRequest(QHttpRequest*, QHttpResponse*)), | |
| 129 | - &handler, SLOT(handle(QHttpRequest*, QHttpResponse*))); | |
| 130 | - | |
| 131 | - if (!server.listen(port)) | |
| 132 | - qFatal("Failed to connect to port: %d.", port); | |
| 133 | - | |
| 134 | - return application.exec(); | |
| 135 | -} | |
| 136 | - | |
| 137 | -#include "br-serve.moc" |