Commit 5edb29cab8bc5ffa553578e8c5ceb5a1a173b0e2
1 parent
96970eb8
deprecated br-enroll
Showing
9 changed files
with
98 additions
and
130 deletions
app/CMakeLists.txt
| @@ -8,7 +8,6 @@ add_subdirectory(examples) | @@ -8,7 +8,6 @@ add_subdirectory(examples) | ||
| 8 | if(NOT ${BR_EMBEDDED}) | 8 | if(NOT ${BR_EMBEDDED}) |
| 9 | add_subdirectory(br-download) | 9 | add_subdirectory(br-download) |
| 10 | add_subdirectory(br-crawl) | 10 | add_subdirectory(br-crawl) |
| 11 | - add_subdirectory(br-enroll) | ||
| 12 | add_subdirectory(br-gui) | 11 | add_subdirectory(br-gui) |
| 13 | add_subdirectory(br-print) | 12 | add_subdirectory(br-print) |
| 14 | add_subdirectory(br-search) | 13 | add_subdirectory(br-search) |
app/br-download/br-download.cpp
| @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) | @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) | ||
| 121 | json ? line : QByteArray(), | 121 | json ? line : QByteArray(), |
| 122 | nam); | 122 | nam); |
| 123 | 123 | ||
| 124 | - if (error.error != QJsonParseError::NoError) | 124 | + if (json && (error.error != QJsonParseError::NoError)) |
| 125 | qDebug() << error.errorString(); | 125 | qDebug() << error.errorString(); |
| 126 | } | 126 | } |
| 127 | } | 127 | } |
app/br-enroll/CMakeLists.txt deleted
app/br-enroll/br-enroll.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 <opencv2/highgui/highgui.hpp> | ||
| 19 | -#include <cstdio> | ||
| 20 | -#include <cstring> | ||
| 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-enroll [args]\n" | ||
| 30 | - "================\n" | ||
| 31 | - "* __stdin__ - Templates (raw data)\n" | ||
| 32 | - "* __stdout__ - Templates (feature vectors)\n" | ||
| 33 | - "\n" | ||
| 34 | - "_br-enroll_ is an application that creates feature vector template(s) from images.\n" | ||
| 35 | - "For every input image template in _stdin_, enroll writes zero or more templates to _stdout_.\n" | ||
| 36 | - "\n" | ||
| 37 | - "Enroll may choose to store metadata in the feature vector in an algorithm-specific manner.\n" | ||
| 38 | - "For example, a face recognition algorithm may devote the first 16-bytes of the feature vector to saving four 4-byte integers representing the face bounding box (X, Y, Width, Height).\n" | ||
| 39 | - "It is expected that _br-search_ will understand and output algorithm-specific metadata for the top matching templates.\n"); | ||
| 40 | -} | ||
| 41 | - | ||
| 42 | -static QSharedPointer<Transform> algorithm; | ||
| 43 | - | ||
| 44 | -static void enroll_utemplate(br_const_utemplate utemplate, br_callback_context) | ||
| 45 | -{ | ||
| 46 | - if (utemplate->algorithmID != 3) | ||
| 47 | - qFatal("Expected an encoded image."); | ||
| 48 | - | ||
| 49 | - TemplateList templates; | ||
| 50 | - templates.append(Template(imdecode(Mat(1, utemplate->size, CV_8UC1, (void*) utemplate->data), IMREAD_UNCHANGED))); | ||
| 51 | - templates >> *algorithm; | ||
| 52 | - | ||
| 53 | - foreach (const Template &t, templates) { | ||
| 54 | - const Mat &m = t.m(); | ||
| 55 | - QByteArray data((const char*) m.data, m.rows * m.cols * m.elemSize()); | ||
| 56 | - | ||
| 57 | - const QRectF frontalFace = t.file.get<QRectF>("FrontalFace"); | ||
| 58 | - const QPointF firstEye = t.file.get<QPointF>("First_Eye"); | ||
| 59 | - const QPointF secondEye = t.file.get<QPointF>("Second_Eye"); | ||
| 60 | - const float x = frontalFace.x(); | ||
| 61 | - const float y = frontalFace.y(); | ||
| 62 | - const float width = frontalFace.width(); | ||
| 63 | - const float height = frontalFace.height(); | ||
| 64 | - const float rightEyeX = firstEye.x(); | ||
| 65 | - const float rightEyeY = firstEye.y(); | ||
| 66 | - const float leftEyeX = secondEye.x(); | ||
| 67 | - const float leftEyeY = secondEye.y(); | ||
| 68 | - | ||
| 69 | - data.append((const char*)&x , sizeof(float)); | ||
| 70 | - data.append((const char*)&y , sizeof(float)); | ||
| 71 | - data.append((const char*)&width , sizeof(float)); | ||
| 72 | - data.append((const char*)&height , sizeof(float)); | ||
| 73 | - data.append((const char*)&rightEyeX, sizeof(float)); | ||
| 74 | - data.append((const char*)&rightEyeY, sizeof(float)); | ||
| 75 | - data.append((const char*)&leftEyeX , sizeof(float)); | ||
| 76 | - data.append((const char*)&leftEyeY , sizeof(float)); | ||
| 77 | - | ||
| 78 | - const QByteArray templateID = QCryptographicHash::hash(data, QCryptographicHash::Md5); | ||
| 79 | - br_append_utemplate_contents(stdout, utemplate->imageID, (const unsigned char*) templateID.data(), -1, data.size(), (const unsigned char*) data.data()); | ||
| 80 | - } | ||
| 81 | -} | ||
| 82 | - | ||
| 83 | -int main(int argc, char *argv[]) | ||
| 84 | -{ | ||
| 85 | - for (int i=1; i<argc; i++) | ||
| 86 | - if (!strcmp(argv[i], "-help")) { help(); exit(EXIT_SUCCESS); } | ||
| 87 | - | ||
| 88 | - Context::initialize(argc, argv, "", false); | ||
| 89 | - Globals->quiet = true; | ||
| 90 | - Globals->enrollAll = true; | ||
| 91 | - algorithm = Transform::fromAlgorithm("FaceRecognition"); | ||
| 92 | - br_iterate_utemplates_file(stdin, enroll_utemplate, NULL, true); | ||
| 93 | - Context::finalize(); | ||
| 94 | - return EXIT_SUCCESS; | ||
| 95 | -} |
openbr/plugins/algorithms.cpp
| @@ -31,7 +31,7 @@ class AlgorithmsInitializer : public Initializer | @@ -31,7 +31,7 @@ class AlgorithmsInitializer : public Initializer | ||
| 31 | void initialize() const | 31 | void initialize() const |
| 32 | { | 32 | { |
| 33 | // Face | 33 | // Face |
| 34 | - Globals->abbreviations.insert("FaceRecognition", "FaceDetection+Expand+<FaceRecognitionRegistration>+Expand+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>:MatchProbability(ByteL1)"); | 34 | + Globals->abbreviations.insert("FaceRecognition", "FaceDetection+Expand+<FaceRecognitionRegistration>+Expand+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>+SetMetadata(AlgorithmID,-1):MatchProbability(ByteL1)"); |
| 35 | Globals->abbreviations.insert("GenderClassification", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<GenderClassifier>+Discard"); | 35 | Globals->abbreviations.insert("GenderClassification", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<GenderClassifier>+Discard"); |
| 36 | Globals->abbreviations.insert("AgeRegression", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<AgeRegressor>+Discard"); | 36 | Globals->abbreviations.insert("AgeRegression", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<AgeRegressor>+Discard"); |
| 37 | Globals->abbreviations.insert("FaceQuality", "Open+Expand+Cascade(FrontalFace)+ASEFEyes+Affine(64,64,0.25,0.35)+ImageQuality+Cvt(Gray)+DFFS+Discard"); | 37 | Globals->abbreviations.insert("FaceQuality", "Open+Expand+Cascade(FrontalFace)+ASEFEyes+Affine(64,64,0.25,0.35)+ImageQuality+Cvt(Gray)+DFFS+Discard"); |
openbr/plugins/gallery.cpp
| @@ -95,17 +95,26 @@ class BinaryGallery : public Gallery | @@ -95,17 +95,26 @@ class BinaryGallery : public Gallery | ||
| 95 | 95 | ||
| 96 | void init() | 96 | void init() |
| 97 | { | 97 | { |
| 98 | - gallery.setFileName(file); | ||
| 99 | - if (file.get<bool>("remove")) | ||
| 100 | - gallery.remove(); | ||
| 101 | - QtUtils::touchDir(gallery); | ||
| 102 | - QFile::OpenMode mode = QFile::ReadWrite; | 98 | + const QString baseName = file.baseName(); |
| 99 | + if (baseName == "stdin") { | ||
| 100 | + gallery.open(stdin, QFile::ReadOnly); | ||
| 101 | + } else if (baseName == "stdout") { | ||
| 102 | + gallery.open(stdout, QFile::WriteOnly); | ||
| 103 | + } else if (baseName == "stderr") { | ||
| 104 | + gallery.open(stderr, QFile::WriteOnly); | ||
| 105 | + } else { | ||
| 106 | + gallery.setFileName(file); | ||
| 107 | + if (file.get<bool>("remove")) | ||
| 108 | + gallery.remove(); | ||
| 109 | + QtUtils::touchDir(gallery); | ||
| 110 | + QFile::OpenMode mode = QFile::ReadWrite; | ||
| 103 | 111 | ||
| 104 | - if (file.get<bool>("append")) | ||
| 105 | - mode |= QFile::Append; | 112 | + if (file.get<bool>("append")) |
| 113 | + mode |= QFile::Append; | ||
| 106 | 114 | ||
| 107 | - if (!gallery.open(mode)) | ||
| 108 | - qFatal("Can't open gallery: %s", qPrintable(gallery.fileName())); | 115 | + if (!gallery.open(mode)) |
| 116 | + qFatal("Can't open gallery: %s", qPrintable(gallery.fileName())); | ||
| 117 | + } | ||
| 109 | stream.setDevice(&gallery); | 118 | stream.setDevice(&gallery); |
| 110 | } | 119 | } |
| 111 | 120 | ||
| @@ -181,20 +190,44 @@ class utGallery : public BinaryGallery | @@ -181,20 +190,44 @@ class utGallery : public BinaryGallery | ||
| 181 | 190 | ||
| 182 | Template readTemplate() | 191 | Template readTemplate() |
| 183 | { | 192 | { |
| 184 | - cv::Mat m; | ||
| 185 | - br_utemplate t = (br_utemplate) malloc(sizeof(br_universal_template)); | ||
| 186 | - if (gallery.read((char*)t, sizeof(br_universal_template)) == sizeof(br_universal_template)) { | ||
| 187 | - m = cv::Mat(1, t->size, CV_8UC1); | ||
| 188 | - if (gallery.read((char*)m.data, t->size) != t->size) | ||
| 189 | - qFatal("Unexepected EOF when reading universal template data."); | 193 | + Template t; |
| 194 | + br_utemplate ut = (br_utemplate) malloc(sizeof(br_universal_template)); | ||
| 195 | + if (gallery.read((char*)ut, sizeof(br_universal_template)) == sizeof(br_universal_template)) { | ||
| 196 | + cv::Mat m = cv::Mat(1, ut->size, CV_8UC1); | ||
| 197 | + char *dst = (char*) m.data; | ||
| 198 | + qint64 bytesNeeded = ut->size; | ||
| 199 | + while (bytesNeeded > 0) { | ||
| 200 | + qint64 bytesRead = gallery.read(dst, bytesNeeded); | ||
| 201 | + if (bytesRead <= 0) | ||
| 202 | + qFatal("Unexepected EOF when reading universal template data."); | ||
| 203 | + bytesNeeded -= bytesRead; | ||
| 204 | + dst += bytesRead; | ||
| 205 | + } | ||
| 206 | + t.append(m); | ||
| 207 | + t.file.set("ImageID", QVariant(QByteArray((const char*)ut->imageID, 16))); | ||
| 208 | + t.file.set("TemplateID", QVariant(QByteArray((const char*)ut->templateID, 16))); | ||
| 209 | + t.file.set("AlgorithmID", QVariant(ut->algorithmID)); | ||
| 190 | } | 210 | } |
| 191 | - free(t); | ||
| 192 | - return m; | 211 | + free(ut); |
| 212 | + return t; | ||
| 193 | } | 213 | } |
| 194 | 214 | ||
| 195 | - void write(const Template &) | 215 | + void write(const Template &t) |
| 196 | { | 216 | { |
| 197 | - qFatal("Not implemented."); | 217 | + const QByteArray imageID = t.file.get<QByteArray>("ImageID"); |
| 218 | + if (imageID.size() != 16) | ||
| 219 | + qFatal("Expected 16-byte ImageID, got: %d bytes.", imageID.size()); | ||
| 220 | + | ||
| 221 | + const int32_t algorithmID = t.file.get<int32_t>("AlgorithmID"); | ||
| 222 | + const QByteArray data((const char*) t.m().data, t.m().rows * t.m().cols * t.m().elemSize()); | ||
| 223 | + const QByteArray templateID = QCryptographicHash::hash(data, QCryptographicHash::Md5); | ||
| 224 | + const uint32_t size = data.size(); | ||
| 225 | + | ||
| 226 | + gallery.write(imageID); | ||
| 227 | + gallery.write(templateID); | ||
| 228 | + gallery.write((const char*) &algorithmID, 4); | ||
| 229 | + gallery.write((const char*) &size, 4); | ||
| 230 | + gallery.write(data); | ||
| 198 | } | 231 | } |
| 199 | }; | 232 | }; |
| 200 | 233 |
openbr/plugins/misc.cpp
| @@ -37,17 +37,28 @@ class OpenTransform : public UntrainableMetaTransform | @@ -37,17 +37,28 @@ class OpenTransform : public UntrainableMetaTransform | ||
| 37 | 37 | ||
| 38 | void project(const Template &src, Template &dst) const | 38 | void project(const Template &src, Template &dst) const |
| 39 | { | 39 | { |
| 40 | - if (!src.isEmpty()) { dst = src; return; } | ||
| 41 | - if (Globals->verbose) qDebug("Opening %s", qPrintable(src.file.flat())); | ||
| 42 | dst.file = src.file; | 40 | dst.file = src.file; |
| 43 | - foreach (const File &file, src.file.split()) { | ||
| 44 | - QScopedPointer<Format> format(Factory<Format>::make(file)); | ||
| 45 | - Template t = format->read(); | ||
| 46 | - if (t.isEmpty()) qWarning("Can't open %s from %s", qPrintable(file.flat()), qPrintable(QDir::currentPath())); | ||
| 47 | - dst.append(t); | ||
| 48 | - dst.file.append(t.file.localMetadata()); | 41 | + if (src.empty()) { |
| 42 | + if (Globals->verbose) | ||
| 43 | + qDebug("Opening %s", qPrintable(src.file.flat())); | ||
| 44 | + | ||
| 45 | + // Read from disk otherwise | ||
| 46 | + foreach (const File &file, src.file.split()) { | ||
| 47 | + QScopedPointer<Format> format(Factory<Format>::make(file)); | ||
| 48 | + Template t = format->read(); | ||
| 49 | + if (t.isEmpty()) | ||
| 50 | + qWarning("Can't open %s from %s", qPrintable(file.flat()), qPrintable(QDir::currentPath())); | ||
| 51 | + dst.append(t); | ||
| 52 | + dst.file.append(t.file.localMetadata()); | ||
| 53 | + } | ||
| 54 | + dst.file.set("FTO", dst.isEmpty()); | ||
| 55 | + } else { | ||
| 56 | + // Propogate or decode existing matricies | ||
| 57 | + foreach (const Mat &m, src) { | ||
| 58 | + if (((m.rows > 1) && (m.cols > 1)) || (m.type() != CV_8UC1)) dst += m; | ||
| 59 | + else dst += imdecode(src.m(), IMREAD_UNCHANGED); | ||
| 60 | + } | ||
| 49 | } | 61 | } |
| 50 | - dst.file.set("FTO", dst.isEmpty()); | ||
| 51 | } | 62 | } |
| 52 | }; | 63 | }; |
| 53 | 64 |
openbr/plugins/stream.cpp
| @@ -334,6 +334,8 @@ public: | @@ -334,6 +334,8 @@ public: | ||
| 334 | // Otherwise, read another block | 334 | // Otherwise, read another block |
| 335 | if (!lastBlock) { | 335 | if (!lastBlock) { |
| 336 | currentData = gallery->readBlock(&lastBlock); | 336 | currentData = gallery->readBlock(&lastBlock); |
| 337 | + if (currentData.empty()) | ||
| 338 | + qFatal("Expected at least one template."); | ||
| 337 | nextIdx = 0; | 339 | nextIdx = 0; |
| 338 | } | 340 | } |
| 339 | else | 341 | else |
openbr/plugins/template.cpp
| @@ -52,6 +52,28 @@ BR_REGISTER(Transform, RemoveTemplatesTransform) | @@ -52,6 +52,28 @@ BR_REGISTER(Transform, RemoveTemplatesTransform) | ||
| 52 | 52 | ||
| 53 | /*! | 53 | /*! |
| 54 | * \ingroup transforms | 54 | * \ingroup transforms |
| 55 | + * \brief Sets the metadata key/value pair. | ||
| 56 | + * \author Josh Klontz \cite jklontz | ||
| 57 | + */ | ||
| 58 | +class SetMetadataTransform : public UntrainableMetadataTransform | ||
| 59 | +{ | ||
| 60 | + Q_OBJECT | ||
| 61 | + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false) | ||
| 62 | + Q_PROPERTY(QString value READ get_value WRITE set_value RESET reset_value STORED false) | ||
| 63 | + BR_PROPERTY(QString, key, "") | ||
| 64 | + BR_PROPERTY(QString, value, "") | ||
| 65 | + | ||
| 66 | + void projectMetadata(const File &src, File &dst) const | ||
| 67 | + { | ||
| 68 | + dst = src; | ||
| 69 | + dst.set(key, value); | ||
| 70 | + } | ||
| 71 | +}; | ||
| 72 | + | ||
| 73 | +BR_REGISTER(Transform, SetMetadataTransform) | ||
| 74 | + | ||
| 75 | +/*! | ||
| 76 | + * \ingroup transforms | ||
| 55 | * \brief Removes a metadata field from all templates | 77 | * \brief Removes a metadata field from all templates |
| 56 | * \author Brendan Klare \cite bklare | 78 | * \author Brendan Klare \cite bklare |
| 57 | */ | 79 | */ |