Commit 5edb29cab8bc5ffa553578e8c5ceb5a1a173b0e2
1 parent
96970eb8
deprecated br-enroll
Showing
9 changed files
with
98 additions
and
130 deletions
app/CMakeLists.txt
app/br-download/br-download.cpp
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 | 31 | void initialize() const |
| 32 | 32 | { |
| 33 | 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 | 35 | Globals->abbreviations.insert("GenderClassification", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<GenderClassifier>+Discard"); |
| 36 | 36 | Globals->abbreviations.insert("AgeRegression", "FaceDetection+Expand+<FaceClassificationRegistration>+Expand+<FaceClassificationExtraction>+<AgeRegressor>+Discard"); |
| 37 | 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 | 95 | |
| 96 | 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 | 118 | stream.setDevice(&gallery); |
| 110 | 119 | } |
| 111 | 120 | |
| ... | ... | @@ -181,20 +190,44 @@ class utGallery : public BinaryGallery |
| 181 | 190 | |
| 182 | 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 | 37 | |
| 38 | 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 | 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
openbr/plugins/template.cpp
| ... | ... | @@ -52,6 +52,28 @@ BR_REGISTER(Transform, RemoveTemplatesTransform) |
| 52 | 52 | |
| 53 | 53 | /*! |
| 54 | 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 | 77 | * \brief Removes a metadata field from all templates |
| 56 | 78 | * \author Brendan Klare \cite bklare |
| 57 | 79 | */ | ... | ... |