Commit f2e360a1c24fc1d14e2a5b559ab7b83afb85157e
Merge
Showing
39 changed files
with
880 additions
and
504 deletions
CHANGELOG.md
| @@ -4,6 +4,8 @@ | @@ -4,6 +4,8 @@ | ||
| 4 | * Enrolling files/folders are now sorted naturally instead of alpha numerically | 4 | * Enrolling files/folders are now sorted naturally instead of alpha numerically |
| 5 | * YouTubeFacesDBTransform implements Dr. Wolf's experimental protocol | 5 | * YouTubeFacesDBTransform implements Dr. Wolf's experimental protocol |
| 6 | * NEC3 refactored | 6 | * NEC3 refactored |
| 7 | +* Updated transform API to add support for time-varying transforms per issue (#23) | ||
| 8 | +* Refactored File class to improve point and rect storage (#22) | ||
| 7 | 9 | ||
| 8 | 0.2.0 - 2/23/13 | 10 | 0.2.0 - 2/23/13 |
| 9 | =============== | 11 | =============== |
app/br/CMakeLists.txt
| @@ -5,3 +5,6 @@ endif() | @@ -5,3 +5,6 @@ endif() | ||
| 5 | add_executable(br br.cpp ${BR_RESOURCES}) | 5 | add_executable(br br.cpp ${BR_RESOURCES}) |
| 6 | target_link_libraries(br openbr ${CMAKE_THREAD_LIBS_INIT}) | 6 | target_link_libraries(br openbr ${CMAKE_THREAD_LIBS_INIT}) |
| 7 | install(TARGETS br RUNTIME DESTINATION bin) | 7 | install(TARGETS br RUNTIME DESTINATION bin) |
| 8 | + | ||
| 9 | +add_test(NAME br_initialize WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND br) | ||
| 10 | +add_test(NAME br_objects WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND br -objects) |
app/examples/age_estimation.cpp
| @@ -31,7 +31,7 @@ static void printTemplate(const br::Template &t) | @@ -31,7 +31,7 @@ static void printTemplate(const br::Template &t) | ||
| 31 | { | 31 | { |
| 32 | printf("%s age: %d\n", | 32 | printf("%s age: %d\n", |
| 33 | qPrintable(t.file.fileName()), | 33 | qPrintable(t.file.fileName()), |
| 34 | - t.file.getInt("Label")); | 34 | + t.file.get<int>("Label")); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | int main(int argc, char *argv[]) | 37 | int main(int argc, char *argv[]) |
app/examples/face_recognition.cpp
| @@ -30,10 +30,9 @@ | @@ -30,10 +30,9 @@ | ||
| 30 | 30 | ||
| 31 | static void printTemplate(const br::Template &t) | 31 | static void printTemplate(const br::Template &t) |
| 32 | { | 32 | { |
| 33 | - printf("%s eyes: (%d, %d) (%d, %d)\n", | ||
| 34 | - qPrintable(t.file.fileName()), | ||
| 35 | - t.file.getInt("Affine_0_X"), t.file.getInt("Affine_0_Y"), | ||
| 36 | - t.file.getInt("Affine_1_X"), t.file.getInt("Affine_1_Y")); | 33 | + const QPoint firstEye = t.file.get<QPoint>("Affine_0"); |
| 34 | + const QPoint secondEye = t.file.get<QPoint>("Affine_1"); | ||
| 35 | + printf("%s eyes: (%d, %d) (%d, %d)\n", qPrintable(t.file.fileName()), firstEye.x(), firstEye.y(), secondEye.x(), secondEye.y()); | ||
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | int main(int argc, char *argv[]) | 38 | int main(int argc, char *argv[]) |
app/examples/face_recognition_evaluation.cpp
| @@ -43,9 +43,9 @@ int main(int argc, char *argv[]) | @@ -43,9 +43,9 @@ int main(int argc, char *argv[]) | ||
| 43 | // Equivalent to 'Globals->path = "../data/MEDS/img/";' in C++ API | 43 | // Equivalent to 'Globals->path = "../data/MEDS/img/";' in C++ API |
| 44 | br_set_property("path", "../data/MEDS/img/"); | 44 | br_set_property("path", "../data/MEDS/img/"); |
| 45 | 45 | ||
| 46 | - // Enroll galleries | ||
| 47 | - br_enroll("../data/MEDS/sigset/MEDS_frontal_target.xml", "target.gal"); | ||
| 48 | - br_enroll("../data/MEDS/sigset/MEDS_frontal_query.xml", "query.gal"); | 46 | + // Enroll galleries, don't re-enroll if they already exist (cache) |
| 47 | + br_enroll("../data/MEDS/sigset/MEDS_frontal_target.xml", "target.gal[cache]"); | ||
| 48 | + br_enroll("../data/MEDS/sigset/MEDS_frontal_query.xml", "query.gal[cache]"); | ||
| 49 | 49 | ||
| 50 | // Compare galleries and store result in a binary similarity matrix | 50 | // Compare galleries and store result in a binary similarity matrix |
| 51 | br_compare("target.gal", "query.gal", "FaceRecognition_MEDS.mtx"); | 51 | br_compare("target.gal", "query.gal", "FaceRecognition_MEDS.mtx"); |
app/examples/face_recognition_search.cpp
0 → 100644
| 1 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2 | + * Copyright 2012 The MITRE Corporation * | ||
| 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 | +/*! | ||
| 18 | + * \ingroup cli | ||
| 19 | + * \page cli_face_recognition_search Face Recognition Search | ||
| 20 | + * \ref cpp_face_recognition_search "C++ Equivalent" | ||
| 21 | + * \code | ||
| 22 | + * $ br -algorithm FaceRecognition -enrollAll -enroll ../data/MEDS/img 'meds.gal;meds.csv[separator=;]' | ||
| 23 | + * $ br -algorithm FaceRecognition -compare meds.gal ../data/MEDS/img/S001-01-t10_01.jpg match_scores.csv | ||
| 24 | + * \endcode | ||
| 25 | + */ | ||
| 26 | + | ||
| 27 | +//! [face_recognition_search] | ||
| 28 | +#include <openbr_plugin.h> | ||
| 29 | + | ||
| 30 | +int main(int argc, char *argv[]) | ||
| 31 | +{ | ||
| 32 | + br::Context::initialize(argc, argv); | ||
| 33 | + | ||
| 34 | + // Retrieve classes for enrolling and comparing templates using the FaceRecognition algorithm | ||
| 35 | + QSharedPointer<br::Transform> transform = br::Transform::fromAlgorithm("FaceRecognition"); | ||
| 36 | + QSharedPointer<br::Distance> distance = br::Distance::fromAlgorithm("FaceRecognition"); | ||
| 37 | + | ||
| 38 | + // Initialize templates | ||
| 39 | + br::TemplateList target = br::TemplateList::fromGallery("../data/MEDS/img"); | ||
| 40 | + br::Template query("../data/MEDS/img/S001-01-t10_01.jpg"); | ||
| 41 | + | ||
| 42 | + // Enroll templates | ||
| 43 | + br::Globals->enrollAll = true; // Enroll 0 or more faces per image | ||
| 44 | + target >> *transform; | ||
| 45 | + br::Globals->enrollAll = false; // Enroll exactly one face per image | ||
| 46 | + query >> *transform; | ||
| 47 | + | ||
| 48 | + // Compare templates | ||
| 49 | + QList<float> scores = distance->compare(target, query); | ||
| 50 | + | ||
| 51 | + // Print an example score | ||
| 52 | + printf("Images %s and %s have a match score of %.3f\n", | ||
| 53 | + qPrintable(target[3].file.name), | ||
| 54 | + qPrintable(query.file.name), | ||
| 55 | + scores[3]); | ||
| 56 | + | ||
| 57 | + br::Context::finalize(); | ||
| 58 | + return 0; | ||
| 59 | +} | ||
| 60 | +//! [face_recognition_search] |
app/examples/gender_estimation.cpp
| @@ -31,7 +31,7 @@ static void printTemplate(const br::Template &t) | @@ -31,7 +31,7 @@ static void printTemplate(const br::Template &t) | ||
| 31 | { | 31 | { |
| 32 | printf("%s gender: %s\n", | 32 | printf("%s gender: %s\n", |
| 33 | qPrintable(t.file.fileName()), | 33 | qPrintable(t.file.fileName()), |
| 34 | - t.file.getInt("Label") == 1 ? "Female" : "Male"); | 34 | + t.file.get<int>("Label") == 1 ? "Female" : "Male"); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | int main(int argc, char *argv[]) | 37 | int main(int argc, char *argv[]) |
app/openbr-gui/classifier.cpp
| @@ -39,19 +39,18 @@ void Classifier::_classify(File file) | @@ -39,19 +39,18 @@ void Classifier::_classify(File file) | ||
| 39 | { | 39 | { |
| 40 | QString key, value; | 40 | QString key, value; |
| 41 | foreach (const File &f, Enroll(file.flat(), File("[algorithm=" + algorithm + "]"))) { | 41 | foreach (const File &f, Enroll(file.flat(), File("[algorithm=" + algorithm + "]"))) { |
| 42 | - qDebug() << f.flat(); | ||
| 43 | if (!f.contains("Label")) | 42 | if (!f.contains("Label")) |
| 44 | continue; | 43 | continue; |
| 45 | 44 | ||
| 46 | if (algorithm == "GenderClassification") { | 45 | if (algorithm == "GenderClassification") { |
| 47 | key = "Gender"; | 46 | key = "Gender"; |
| 48 | - value = (f.getInt("Label", 0) == 0 ? "Male" : "Female"); | 47 | + value = (f.get<int>("Label", 0) == 0 ? "Male" : "Female"); |
| 49 | } else if (algorithm == "AgeRegression") { | 48 | } else if (algorithm == "AgeRegression") { |
| 50 | key = "Age"; | 49 | key = "Age"; |
| 51 | - value = QString::number(int(f.getFloat("Label", 0)+0.5)) + " Years"; | 50 | + value = QString::number(int(f.get<float>("Label", 0)+0.5)) + " Years"; |
| 52 | } else { | 51 | } else { |
| 53 | key = algorithm; | 52 | key = algorithm; |
| 54 | - value = f.getString("Label"); | 53 | + value = f.get<QString>("Label"); |
| 55 | } | 54 | } |
| 56 | break; | 55 | break; |
| 57 | } | 56 | } |
app/openbr-gui/gallerytoolbar.cpp
| @@ -117,7 +117,7 @@ void br::GalleryToolBar::checkWebcam() | @@ -117,7 +117,7 @@ void br::GalleryToolBar::checkWebcam() | ||
| 117 | void br::GalleryToolBar::enrollmentFinished() | 117 | void br::GalleryToolBar::enrollmentFinished() |
| 118 | { | 118 | { |
| 119 | if (files.isEmpty()) { | 119 | if (files.isEmpty()) { |
| 120 | - if (input.getBool("enrollAll") && !tbWebcam.isChecked()) { | 120 | + if (input.get<bool>("enrollAll", false) && !tbWebcam.isChecked()) { |
| 121 | QMessageBox msgBox; | 121 | QMessageBox msgBox; |
| 122 | msgBox.setText("Quality test failed."); | 122 | msgBox.setText("Quality test failed."); |
| 123 | msgBox.setInformativeText("Enroll anyway?"); | 123 | msgBox.setInformativeText("Enroll anyway?"); |
| @@ -127,7 +127,7 @@ void br::GalleryToolBar::enrollmentFinished() | @@ -127,7 +127,7 @@ void br::GalleryToolBar::enrollmentFinished() | ||
| 127 | 127 | ||
| 128 | if (ret == QMessageBox::Ok) { | 128 | if (ret == QMessageBox::Ok) { |
| 129 | br::File file = input; | 129 | br::File file = input; |
| 130 | - file.setBool("enrollAll", false); | 130 | + file.set("enrollAll", false); |
| 131 | enroll(file); | 131 | enroll(file); |
| 132 | } | 132 | } |
| 133 | } | 133 | } |
app/openbr-gui/templatemetadata.cpp
| @@ -28,7 +28,7 @@ void br::TemplateMetadata::setFile(const br::File &file) | @@ -28,7 +28,7 @@ void br::TemplateMetadata::setFile(const br::File &file) | ||
| 28 | { | 28 | { |
| 29 | if (file.isNull()) lFile.clear(); | 29 | if (file.isNull()) lFile.clear(); |
| 30 | else lFile.setText("<b>File:</b> " + file.fileName()); | 30 | else lFile.setText("<b>File:</b> " + file.fileName()); |
| 31 | - lQuality.setText(QString("<b>Quality:</b> %1").arg(file.getBool("FTE") ? "Low" : "High")); | 31 | + lQuality.setText(QString("<b>Quality:</b> %1").arg(file.get<bool>("FTE", false) ? "Low" : "High")); |
| 32 | foreach (const ConditionalClassifier &classifier, conditionalClassifiers) | 32 | foreach (const ConditionalClassifier &classifier, conditionalClassifiers) |
| 33 | if (classifier.action->isVisible()) classifier.classifier->classify(file); | 33 | if (classifier.action->isVisible()) classifier.classifier->classify(file); |
| 34 | } | 34 | } |
app/openbr-gui/templateviewer.cpp
| @@ -39,10 +39,8 @@ void TemplateViewer::setFile(const File &file_) | @@ -39,10 +39,8 @@ void TemplateViewer::setFile(const File &file_) | ||
| 39 | 39 | ||
| 40 | // Update landmarks | 40 | // Update landmarks |
| 41 | landmarks.clear(); | 41 | landmarks.clear(); |
| 42 | - if (file.contains("Affine_0_X") && file.contains("Affine_0_Y")) | ||
| 43 | - landmarks.append(QPointF(file.getFloat("Affine_0_X"), file.getFloat("Affine_0_Y"))); | ||
| 44 | - if (file.contains("Affine_1_X") && file.contains("Affine_1_Y")) | ||
| 45 | - landmarks.append(QPointF(file.getFloat("Affine_1_X"), file.getFloat("Affine_1_Y"))); | 42 | + if (file.contains("Affine_0")) landmarks.append(file.get<QPointF>("Affine_0")); |
| 43 | + if (file.contains("Affine_1")) landmarks.append(file.get<QPointF>("Affine_1")); | ||
| 46 | while (landmarks.size() < NumLandmarks) | 44 | while (landmarks.size() < NumLandmarks) |
| 47 | landmarks.append(QPointF()); | 45 | landmarks.append(QPointF()); |
| 48 | nearestLandmark = -1; | 46 | nearestLandmark = -1; |
sdk/core/bee.cpp
| @@ -71,7 +71,7 @@ FileList BEE::readSigset(const QString &sigset, bool ignoreMetadata) | @@ -71,7 +71,7 @@ FileList BEE::readSigset(const QString &sigset, bool ignoreMetadata) | ||
| 71 | newFile.append(file); | 71 | newFile.append(file); |
| 72 | file = newFile; | 72 | file = newFile; |
| 73 | } else if (!ignoreMetadata) { | 73 | } else if (!ignoreMetadata) { |
| 74 | - file.insert(key, value); | 74 | + file.set(key, value); |
| 75 | } | 75 | } |
| 76 | } | 76 | } |
| 77 | 77 | ||
| @@ -99,7 +99,7 @@ void BEE::writeSigset(const QString &sigset, const br::FileList &files, bool ign | @@ -99,7 +99,7 @@ void BEE::writeSigset(const QString &sigset, const br::FileList &files, bool ign | ||
| 99 | QStringList metadata; | 99 | QStringList metadata; |
| 100 | if (!ignoreMetadata) | 100 | if (!ignoreMetadata) |
| 101 | foreach (const QString &key, file.localKeys()) | 101 | foreach (const QString &key, file.localKeys()) |
| 102 | - metadata.append(key+"=\""+file.getString(key, "?")+"\""); | 102 | + metadata.append(key+"=\""+file.get<QString>(key, "?")+"\""); |
| 103 | lines.append("\t<biometric-signature name=\"" + file.subject() +"\">"); | 103 | lines.append("\t<biometric-signature name=\"" + file.subject() +"\">"); |
| 104 | lines.append("\t\t<presentation file-name=\"" + file.name + "\" " + metadata.join(" ") + "/>"); | 104 | lines.append("\t\t<presentation file-name=\"" + file.name + "\" " + metadata.join(" ") + "/>"); |
| 105 | lines.append("\t</biometric-signature>"); | 105 | lines.append("\t</biometric-signature>"); |
| @@ -113,19 +113,19 @@ Mat readMatrix(const br::File &matrix) | @@ -113,19 +113,19 @@ Mat readMatrix(const br::File &matrix) | ||
| 113 | { | 113 | { |
| 114 | // Special case matrix construction | 114 | // Special case matrix construction |
| 115 | if (matrix == "Identity") { | 115 | if (matrix == "Identity") { |
| 116 | - int rows = matrix.getInt("rows", -1); | ||
| 117 | - int columns = matrix.getInt("columns", -1); | ||
| 118 | - const int size = matrix.getInt("size", -1); | 116 | + int rows = matrix.get<int>("rows", -1); |
| 117 | + int columns = matrix.get<int>("columns", -1); | ||
| 118 | + const int size = matrix.get<int>("size", -1); | ||
| 119 | if (size != -1) { | 119 | if (size != -1) { |
| 120 | if (rows == -1) rows = size; | 120 | if (rows == -1) rows = size; |
| 121 | if (columns == -1) columns = size; | 121 | if (columns == -1) columns = size; |
| 122 | } | 122 | } |
| 123 | - const int step = matrix.getInt("step", 1); | 123 | + const int step = matrix.get<int>("step", 1); |
| 124 | if (rows % step != 0) qFatal("Step does not divide rows evenly."); | 124 | if (rows % step != 0) qFatal("Step does not divide rows evenly."); |
| 125 | if (columns % step != 0) qFatal("Step does not divide columns evenly."); | 125 | if (columns % step != 0) qFatal("Step does not divide columns evenly."); |
| 126 | 126 | ||
| 127 | if (sizeof(T) == sizeof(BEE::Mask_t)) { | 127 | if (sizeof(T) == sizeof(BEE::Mask_t)) { |
| 128 | - const bool selfSimilar = matrix.getBool("selfSimilar"); | 128 | + const bool selfSimilar = matrix.get<bool>("selfSimilar", false); |
| 129 | 129 | ||
| 130 | Mat m(rows, columns, CV_8UC1); | 130 | Mat m(rows, columns, CV_8UC1); |
| 131 | m.setTo(BEE::NonMatch); | 131 | m.setTo(BEE::NonMatch); |
| @@ -171,8 +171,8 @@ Mat readMatrix(const br::File &matrix) | @@ -171,8 +171,8 @@ Mat readMatrix(const br::File &matrix) | ||
| 171 | file.close(); | 171 | file.close(); |
| 172 | 172 | ||
| 173 | Mat result; | 173 | Mat result; |
| 174 | - if (isDistance ^ matrix.getBool("negate")) m.convertTo(result, -1, -1); | ||
| 175 | - else result = m.clone(); | 174 | + if (isDistance ^ matrix.get<bool>("negate", false)) m.convertTo(result, -1, -1); |
| 175 | + else result = m.clone(); | ||
| 176 | return result; | 176 | return result; |
| 177 | } | 177 | } |
| 178 | 178 |
sdk/core/core.cpp
| @@ -189,12 +189,14 @@ struct AlgorithmCore | @@ -189,12 +189,14 @@ struct AlgorithmCore | ||
| 189 | enroll(file); | 189 | enroll(file); |
| 190 | gallery.reset(Gallery::make(getMemoryGallery(file))); | 190 | gallery.reset(Gallery::make(getMemoryGallery(file))); |
| 191 | galleryFiles = gallery->files(); | 191 | galleryFiles = gallery->files(); |
| 192 | + | ||
| 193 | + qDebug() << galleryFiles; | ||
| 192 | } | 194 | } |
| 193 | } | 195 | } |
| 194 | 196 | ||
| 195 | void compare(File targetGallery, File queryGallery, File output) | 197 | void compare(File targetGallery, File queryGallery, File output) |
| 196 | { | 198 | { |
| 197 | - if (output.exists() && output.getBool("cache")) return; | 199 | + if (output.exists() && output.get<bool>("cache", false)) return; |
| 198 | if (queryGallery == ".") queryGallery = targetGallery; | 200 | if (queryGallery == ".") queryGallery = targetGallery; |
| 199 | 201 | ||
| 200 | QScopedPointer<Gallery> t, q; | 202 | QScopedPointer<Gallery> t, q; |
| @@ -250,7 +252,7 @@ private: | @@ -250,7 +252,7 @@ private: | ||
| 250 | if (!file.isEmpty()) description = file; | 252 | if (!file.isEmpty()) description = file; |
| 251 | 253 | ||
| 252 | if (QFileInfo(description).exists()) { | 254 | if (QFileInfo(description).exists()) { |
| 253 | - if (Globals->verbose) qDebug("Loading %s", qPrintable(QFileInfo(description).fileName())); | 255 | + qDebug("Loading %s", qPrintable(QFileInfo(description).fileName())); |
| 254 | load(description); | 256 | load(description); |
| 255 | return; | 257 | return; |
| 256 | } | 258 | } |
| @@ -259,7 +261,7 @@ private: | @@ -259,7 +261,7 @@ private: | ||
| 259 | if (Globals->abbreviations.contains(description)) | 261 | if (Globals->abbreviations.contains(description)) |
| 260 | return init(Globals->abbreviations[description]); | 262 | return init(Globals->abbreviations[description]); |
| 261 | 263 | ||
| 262 | - QStringList words = description.split(':'); | 264 | + QStringList words = QtUtils::parse(description, ':'); |
| 263 | if (words.size() > 2) qFatal("Invalid algorithm format."); | 265 | if (words.size() > 2) qFatal("Invalid algorithm format."); |
| 264 | 266 | ||
| 265 | transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); | 267 | transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); |
| @@ -316,14 +318,14 @@ void br::Train(const File &input, const File &model) | @@ -316,14 +318,14 @@ void br::Train(const File &input, const File &model) | ||
| 316 | { | 318 | { |
| 317 | qDebug("Training on %s%s", qPrintable(input.flat()), | 319 | qDebug("Training on %s%s", qPrintable(input.flat()), |
| 318 | model.isNull() ? "" : qPrintable(" to " + model.flat())); | 320 | model.isNull() ? "" : qPrintable(" to " + model.flat())); |
| 319 | - AlgorithmManager::getAlgorithm(model.getString("algorithm"))->train(input, model); | 321 | + AlgorithmManager::getAlgorithm(model.get<QString>("algorithm"))->train(input, model); |
| 320 | } | 322 | } |
| 321 | 323 | ||
| 322 | FileList br::Enroll(const File &input, const File &gallery) | 324 | FileList br::Enroll(const File &input, const File &gallery) |
| 323 | { | 325 | { |
| 324 | qDebug("Enrolling %s%s", qPrintable(input.flat()), | 326 | qDebug("Enrolling %s%s", qPrintable(input.flat()), |
| 325 | gallery.isNull() ? "" : qPrintable(" to " + gallery.flat())); | 327 | gallery.isNull() ? "" : qPrintable(" to " + gallery.flat())); |
| 326 | - return AlgorithmManager::getAlgorithm(gallery.getString("algorithm"))->enroll(input, gallery); | 328 | + return AlgorithmManager::getAlgorithm(gallery.get<QString>("algorithm"))->enroll(input, gallery); |
| 327 | } | 329 | } |
| 328 | 330 | ||
| 329 | void br::Compare(const File &targetGallery, const File &queryGallery, const File &output) | 331 | void br::Compare(const File &targetGallery, const File &queryGallery, const File &output) |
| @@ -331,7 +333,7 @@ void br::Compare(const File &targetGallery, const File &queryGallery, const File | @@ -331,7 +333,7 @@ void br::Compare(const File &targetGallery, const File &queryGallery, const File | ||
| 331 | qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), | 333 | qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), |
| 332 | qPrintable(queryGallery.flat()), | 334 | qPrintable(queryGallery.flat()), |
| 333 | output.isNull() ? "" : qPrintable(" to " + output.flat())); | 335 | output.isNull() ? "" : qPrintable(" to " + output.flat())); |
| 334 | - AlgorithmManager::getAlgorithm(output.getString("algorithm"))->compare(targetGallery, queryGallery, output); | 336 | + AlgorithmManager::getAlgorithm(output.get<QString>("algorithm"))->compare(targetGallery, queryGallery, output); |
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | void br::Convert(const File &src, const File &dst) | 339 | void br::Convert(const File &src, const File &dst) |
sdk/core/plot.cpp
| @@ -119,8 +119,8 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | @@ -119,8 +119,8 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | ||
| 119 | // Read files | 119 | // Read files |
| 120 | const Mat scores = BEE::readSimmat(simmat); | 120 | const Mat scores = BEE::readSimmat(simmat); |
| 121 | File maskFile(mask); | 121 | File maskFile(mask); |
| 122 | - maskFile.insert("rows", scores.rows); | ||
| 123 | - maskFile.insert("columns", scores.cols); | 122 | + maskFile.set("rows", scores.rows); |
| 123 | + maskFile.set("columns", scores.cols); | ||
| 124 | const Mat masks = BEE::readMask(maskFile); | 124 | const Mat masks = BEE::readMask(maskFile); |
| 125 | if (scores.size() != masks.size()) qFatal("Simmat/Mask size mismatch."); | 125 | if (scores.size() != masks.size()) qFatal("Simmat/Mask size mismatch."); |
| 126 | 126 | ||
| @@ -143,6 +143,7 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | @@ -143,6 +143,7 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | ||
| 143 | if (genuineCount == 0) qFatal("No genuine scores!"); | 143 | if (genuineCount == 0) qFatal("No genuine scores!"); |
| 144 | if (impostorCount == 0) qFatal("No impostor scores!"); | 144 | if (impostorCount == 0) qFatal("No impostor scores!"); |
| 145 | 145 | ||
| 146 | + // Sort comparisons by simmat_val (score) | ||
| 146 | std::sort(comparisons.begin(), comparisons.end()); | 147 | std::sort(comparisons.begin(), comparisons.end()); |
| 147 | 148 | ||
| 148 | double genuineSum = 0, impostorSum = 0; | 149 | double genuineSum = 0, impostorSum = 0; |
| @@ -155,8 +156,10 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | @@ -155,8 +156,10 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | ||
| 155 | int index = 0; | 156 | int index = 0; |
| 156 | float minGenuineScore = std::numeric_limits<float>::max(); | 157 | float minGenuineScore = std::numeric_limits<float>::max(); |
| 157 | float minImpostorScore = std::numeric_limits<float>::max(); | 158 | float minImpostorScore = std::numeric_limits<float>::max(); |
| 159 | + | ||
| 158 | while (index < comparisons.size()) { | 160 | while (index < comparisons.size()) { |
| 159 | float thresh = comparisons[index].score; | 161 | float thresh = comparisons[index].score; |
| 162 | + // Compute genuine and imposter statistics at a threshold | ||
| 160 | while ((index < comparisons.size()) && | 163 | while ((index < comparisons.size()) && |
| 161 | (comparisons[index].score == thresh)) { | 164 | (comparisons[index].score == thresh)) { |
| 162 | const Comparison &comparison = comparisons[index]; | 165 | const Comparison &comparison = comparisons[index]; |
| @@ -205,7 +208,7 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | @@ -205,7 +208,7 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) | ||
| 205 | lines.append("Metadata,"+QString::number(impostorCount)+",Impostor"); | 208 | lines.append("Metadata,"+QString::number(impostorCount)+",Impostor"); |
| 206 | lines.append("Metadata,"+QString::number(scores.cols*scores.rows-(genuineCount+impostorCount))+",Ignored"); | 209 | lines.append("Metadata,"+QString::number(scores.cols*scores.rows-(genuineCount+impostorCount))+",Ignored"); |
| 207 | 210 | ||
| 208 | - // Write DET, PRE, REC | 211 | + // Write Detection Error Tradeoff (DET), PRE, REC |
| 209 | int points = qMin(operatingPoints.size(), Max_Points); | 212 | int points = qMin(operatingPoints.size(), Max_Points); |
| 210 | for (int i=0; i<points; i++) { | 213 | for (int i=0; i<points; i++) { |
| 211 | const OperatingPoint &operatingPoint = operatingPoints[double(i) / double(points-1) * double(operatingPoints.size()-1)]; | 214 | const OperatingPoint &operatingPoint = operatingPoints[double(i) / double(points-1) * double(operatingPoints.size()-1)]; |
| @@ -416,7 +419,7 @@ struct RPlot | @@ -416,7 +419,7 @@ struct RPlot | ||
| 416 | } | 419 | } |
| 417 | } | 420 | } |
| 418 | 421 | ||
| 419 | - const QString &smooth = destination.getString("smooth", ""); | 422 | + const QString &smooth = destination.get<QString>("smooth", ""); |
| 420 | major.smooth = !smooth.isEmpty() && (major.header == smooth) && (major.size > 1); | 423 | major.smooth = !smooth.isEmpty() && (major.header == smooth) && (major.size > 1); |
| 421 | minor.smooth = !smooth.isEmpty() && (minor.header == smooth) && (minor.size > 1); | 424 | minor.smooth = !smooth.isEmpty() && (minor.header == smooth) && (minor.size > 1); |
| 422 | if (major.smooth) major.size = 1; | 425 | if (major.smooth) major.size = 1; |
sdk/openbr_plugin.cpp
| @@ -58,10 +58,10 @@ QString File::hash() const | @@ -58,10 +58,10 @@ QString File::hash() const | ||
| 58 | return QtUtils::shortTextHash(flat()); | 58 | return QtUtils::shortTextHash(flat()); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | -void File::append(const QHash<QString, QVariant> &metadata) | 61 | +void File::append(const QMap<QString,QVariant> &metadata) |
| 62 | { | 62 | { |
| 63 | foreach (const QString &key, metadata.keys()) | 63 | foreach (const QString &key, metadata.keys()) |
| 64 | - insert(key, metadata[key]); | 64 | + set(key, metadata[key]); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void File::append(const File &other) | 67 | void File::append(const File &other) |
| @@ -70,7 +70,7 @@ void File::append(const File &other) | @@ -70,7 +70,7 @@ void File::append(const File &other) | ||
| 70 | if (name.isEmpty()) { | 70 | if (name.isEmpty()) { |
| 71 | name = other.name; | 71 | name = other.name; |
| 72 | } else { | 72 | } else { |
| 73 | - if (!contains("separator")) insert("separator", ";"); | 73 | + if (!contains("separator")) set("separator", ";"); |
| 74 | name += value("separator").toString() + other.name; | 74 | name += value("separator").toString() + other.name; |
| 75 | } | 75 | } |
| 76 | } | 76 | } |
| @@ -110,29 +110,6 @@ QVariant File::value(const QString &key) const | @@ -110,29 +110,6 @@ QVariant File::value(const QString &key) const | ||
| 110 | return m_metadata.contains(key) ? m_metadata.value(key) : Globals->property(qPrintable(key)); | 110 | return m_metadata.contains(key) ? m_metadata.value(key) : Globals->property(qPrintable(key)); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | -QString File::subject(int label) | ||
| 114 | -{ | ||
| 115 | - return Globals->classes.key(label, QString::number(label)); | ||
| 116 | -} | ||
| 117 | - | ||
| 118 | -float File::label() const | ||
| 119 | -{ | ||
| 120 | - const QVariant variant = value("Label"); | ||
| 121 | - if (variant.isNull()) return -1; | ||
| 122 | - | ||
| 123 | - if (Globals->classes.contains(variant.toString())) | ||
| 124 | - return Globals->classes.value(variant.toString()); | ||
| 125 | - | ||
| 126 | - bool ok; | ||
| 127 | - const float val = variant.toFloat(&ok); | ||
| 128 | - return ok ? val : -1; | ||
| 129 | -} | ||
| 130 | - | ||
| 131 | -void File::remove(const QString &key) | ||
| 132 | -{ | ||
| 133 | - m_metadata.remove(key); | ||
| 134 | -} | ||
| 135 | - | ||
| 136 | void File::set(const QString &key, const QVariant &value) | 113 | void File::set(const QString &key, const QVariant &value) |
| 137 | { | 114 | { |
| 138 | if (key == "Label") { | 115 | if (key == "Label") { |
| @@ -153,155 +130,90 @@ void File::set(const QString &key, const QVariant &value) | @@ -153,155 +130,90 @@ void File::set(const QString &key, const QVariant &value) | ||
| 153 | m_metadata.insert(key, value); | 130 | m_metadata.insert(key, value); |
| 154 | } | 131 | } |
| 155 | 132 | ||
| 156 | -QVariant File::get(const QString &key) const | ||
| 157 | -{ | ||
| 158 | - if (!contains(key)) qFatal("Missing key: %s", qPrintable(key)); | ||
| 159 | - return value(key); | ||
| 160 | -} | ||
| 161 | - | ||
| 162 | -QVariant File::get(const QString &key, const QVariant &defaultValue) const | ||
| 163 | -{ | ||
| 164 | - if (!contains(key)) return defaultValue; | ||
| 165 | - return value(key); | ||
| 166 | -} | ||
| 167 | - | ||
| 168 | -bool File::getBool(const QString &key) const | ||
| 169 | -{ | ||
| 170 | - if (!contains(key)) return false; | ||
| 171 | - QString v = value(key).toString(); | ||
| 172 | - if (v.isEmpty() || (v == "true")) return true; | ||
| 173 | - if (v == "false") return false; | ||
| 174 | - return v.toInt(); | ||
| 175 | -} | ||
| 176 | - | ||
| 177 | -void File::setBool(const QString &key, bool value) | ||
| 178 | -{ | ||
| 179 | - if (value) m_metadata.insert(key, QVariant()); | ||
| 180 | - else m_metadata.remove(key); | ||
| 181 | -} | ||
| 182 | - | ||
| 183 | -int File::getInt(const QString &key) const | ||
| 184 | -{ | ||
| 185 | - if (!contains(key)) qFatal("Missing key: %s", qPrintable(key)); | ||
| 186 | - bool ok; int result = value(key).toInt(&ok); | ||
| 187 | - if (!ok) qFatal("Invalid conversion from: %s", qPrintable(getString(key))); | ||
| 188 | - return result; | ||
| 189 | -} | ||
| 190 | - | ||
| 191 | -int File::getInt(const QString &key, int defaultValue) const | ||
| 192 | -{ | ||
| 193 | - if (!contains(key)) return defaultValue; | ||
| 194 | - bool ok; int result = value(key).toInt(&ok); | ||
| 195 | - if (!ok) return defaultValue; | ||
| 196 | - return result; | ||
| 197 | -} | ||
| 198 | - | ||
| 199 | -float File::getFloat(const QString &key) const | ||
| 200 | -{ | ||
| 201 | - if (!contains(key)) qFatal("Missing key: %s", qPrintable(key)); | ||
| 202 | - bool ok; float result = value(key).toFloat(&ok); | ||
| 203 | - if (!ok) qFatal("Invalid conversion from: %s", qPrintable(getString(key))); | ||
| 204 | - return result; | ||
| 205 | -} | ||
| 206 | - | ||
| 207 | -float File::getFloat(const QString &key, float defaultValue) const | 133 | +QString File::subject(int label) |
| 208 | { | 134 | { |
| 209 | - if (!contains(key)) return defaultValue; | ||
| 210 | - bool ok; float result = value(key).toFloat(&ok); | ||
| 211 | - if (!ok) return defaultValue; | ||
| 212 | - return result; | 135 | + return Globals->classes.key(label, QString::number(label)); |
| 213 | } | 136 | } |
| 214 | 137 | ||
| 215 | -QString File::getString(const QString &key) const | 138 | +float File::label() const |
| 216 | { | 139 | { |
| 217 | - if (!contains(key)) qFatal("Missing key: %s", qPrintable(key)); | ||
| 218 | - return value(key).toString(); | ||
| 219 | -} | 140 | + const QVariant variant = value("Label"); |
| 141 | + if (variant.isNull()) return -1; | ||
| 220 | 142 | ||
| 221 | -QString File::getString(const QString &key, const QString &defaultValue) const | ||
| 222 | -{ | ||
| 223 | - if (!contains(key)) return defaultValue; | ||
| 224 | - return value(key).toString(); | ||
| 225 | -} | 143 | + if (Globals->classes.contains(variant.toString())) |
| 144 | + return Globals->classes.value(variant.toString()); | ||
| 226 | 145 | ||
| 227 | -QList<QPointF> File::landmarks() const | ||
| 228 | -{ | ||
| 229 | - QList<QPointF> landmarks; | ||
| 230 | - foreach (const QVariant &landmark, value("Landmarks").toList()) | ||
| 231 | - landmarks.append(landmark.toPointF()); | ||
| 232 | - return landmarks; | 146 | + bool ok; |
| 147 | + const float val = variant.toFloat(&ok); | ||
| 148 | + return ok ? val : -1; | ||
| 233 | } | 149 | } |
| 234 | 150 | ||
| 235 | -QList<QPointF> File::namedLandmarks() const | 151 | +QList<QPointF> File::namedPoints() const |
| 236 | { | 152 | { |
| 237 | QList<QPointF> landmarks; | 153 | QList<QPointF> landmarks; |
| 238 | - QStringList keys = localMetadata().keys(); | ||
| 239 | - foreach (const QString &key, keys) { | ||
| 240 | - if (!key.endsWith("_X")) | ||
| 241 | - continue; | ||
| 242 | - QString keyBaseName = key.left(key.size()-2); | ||
| 243 | - if (!keys.contains(keyBaseName+"_Y") || | ||
| 244 | - keys.contains(keyBaseName+"_Width") || | ||
| 245 | - keys.contains(keyBaseName+"_Height") || | ||
| 246 | - keys.contains(keyBaseName+"_Radius")) | ||
| 247 | - continue; | ||
| 248 | - landmarks.append(QPointF(getFloat(keyBaseName+"_X"), getFloat(keyBaseName+"_Y"))); | 154 | + foreach (const QString &key, localMetadata().keys()) { |
| 155 | + const QVariant &variant = m_metadata[key]; | ||
| 156 | + if (variant.canConvert<QPointF>()) | ||
| 157 | + landmarks.append(variant.value<QPointF>()); | ||
| 249 | } | 158 | } |
| 250 | return landmarks; | 159 | return landmarks; |
| 251 | } | 160 | } |
| 252 | 161 | ||
| 253 | -void File::appendLandmark(const QPointF &landmark) | 162 | +QList<QPointF> File::points() const |
| 254 | { | 163 | { |
| 255 | - QList<QVariant> newLandmarks = m_metadata["Landmarks"].toList(); | ||
| 256 | - newLandmarks.append(landmark); | ||
| 257 | - m_metadata["Landmarks"] = newLandmarks; | 164 | + QList<QPointF> points; |
| 165 | + foreach (const QVariant &point, m_metadata["Points"].toList()) | ||
| 166 | + points.append(point.toPointF()); | ||
| 167 | + return points; | ||
| 258 | } | 168 | } |
| 259 | 169 | ||
| 260 | -void File::appendLandmarks(const QList<QPointF> &landmarks) | 170 | +void File::appendPoint(const QPointF &point) |
| 261 | { | 171 | { |
| 262 | - QList<QVariant> newLandmarks = m_metadata["Landmarks"].toList(); | ||
| 263 | - foreach (const QPointF &landmark, landmarks) | ||
| 264 | - newLandmarks.append(landmark); | ||
| 265 | - m_metadata["Landmarks"] = newLandmarks; | 172 | + QList<QVariant> newPoints = m_metadata["Points"].toList(); |
| 173 | + newPoints.append(point); | ||
| 174 | + m_metadata["Points"] = newPoints; | ||
| 266 | } | 175 | } |
| 267 | 176 | ||
| 268 | -void File::setLandmarks(const QList<QPointF> &landmarks) | 177 | +void File::appendPoints(const QList<QPointF> &points) |
| 269 | { | 178 | { |
| 270 | - QList<QVariant> landmarkList; landmarkList.reserve(landmarks.size()); | ||
| 271 | - foreach (const QPointF &landmark, landmarks) | ||
| 272 | - landmarkList.append(landmark); | ||
| 273 | - m_metadata["Landmarks"] = landmarkList; | 179 | + QList<QVariant> newPoints = m_metadata["Points"].toList(); |
| 180 | + foreach (const QPointF &point, points) | ||
| 181 | + newPoints.append(point); | ||
| 182 | + m_metadata["Points"] = newPoints; | ||
| 274 | } | 183 | } |
| 275 | 184 | ||
| 276 | -QList<QRectF> File::ROIs() const | 185 | +QList<QRectF> File::namedRects() const |
| 277 | { | 186 | { |
| 278 | - QList<QRectF> ROIs; | ||
| 279 | - foreach (const QVariant &ROI, value("ROIs").toList()) | ||
| 280 | - ROIs.append(ROI.toRect()); | ||
| 281 | - return ROIs; | 187 | + QList<QRectF> rects; |
| 188 | + foreach (const QString &key, localMetadata().keys()) { | ||
| 189 | + const QVariant &variant = m_metadata[key]; | ||
| 190 | + if (variant.canConvert<QRectF>()) | ||
| 191 | + rects.append(variant.value<QRectF>()); | ||
| 192 | + } | ||
| 193 | + return rects; | ||
| 282 | } | 194 | } |
| 283 | 195 | ||
| 284 | -void File::appendROI(const QRectF &ROI) | 196 | +QList<QRectF> File::rects() const |
| 285 | { | 197 | { |
| 286 | - QList<QVariant> newROIs = m_metadata["ROIs"].toList(); | ||
| 287 | - newROIs.append(ROI); | ||
| 288 | - m_metadata["ROIs"] = newROIs; | 198 | + QList<QRectF> rects; |
| 199 | + foreach (const QVariant &rect, m_metadata["Rects"].toList()) | ||
| 200 | + rects.append(rect.toRect()); | ||
| 201 | + return rects; | ||
| 289 | } | 202 | } |
| 290 | 203 | ||
| 291 | -void File::appendROIs(const QList<QRectF> &ROIs) | 204 | +void File::appendRect(const QRectF &rect) |
| 292 | { | 205 | { |
| 293 | - QList<QVariant> newROIs = m_metadata["ROIs"].toList(); | ||
| 294 | - foreach (const QRectF &ROI, ROIs) | ||
| 295 | - newROIs.append(ROI); | ||
| 296 | - m_metadata["ROIs"] = newROIs; | 206 | + QList<QVariant> newRects = m_metadata["Rects"].toList(); |
| 207 | + newRects.append(rect); | ||
| 208 | + m_metadata["Rects"] = newRects; | ||
| 297 | } | 209 | } |
| 298 | 210 | ||
| 299 | -void File::setROIs(const QList<QRectF> &ROIs) | 211 | +void File::appendRects(const QList<QRectF> &rects) |
| 300 | { | 212 | { |
| 301 | - QList<QVariant> ROIList; ROIList.reserve(ROIs.size()); | ||
| 302 | - foreach (const QRectF &ROI, ROIs) | ||
| 303 | - ROIList.append(ROI); | ||
| 304 | - m_metadata["ROIs"] = ROIList; | 213 | + QList<QVariant> newRects = m_metadata["Rects"].toList(); |
| 214 | + foreach (const QRectF &rect, rects) | ||
| 215 | + newRects.append(rect); | ||
| 216 | + m_metadata["Rects"] = newRects; | ||
| 305 | } | 217 | } |
| 306 | 218 | ||
| 307 | /* File - private methods */ | 219 | /* File - private methods */ |
| @@ -325,10 +237,10 @@ void File::init(const QString &file) | @@ -325,10 +237,10 @@ void File::init(const QString &file) | ||
| 325 | QStringList words = QtUtils::parse(parameters[i], '='); | 237 | QStringList words = QtUtils::parse(parameters[i], '='); |
| 326 | QtUtils::checkArgsSize("File", words, 1, 2); | 238 | QtUtils::checkArgsSize("File", words, 1, 2); |
| 327 | if (words.size() < 2) { | 239 | if (words.size() < 2) { |
| 328 | - if (unnamed) insertParameter(i, words[0]); | ||
| 329 | - else insert(words[0], QVariant()); | 240 | + if (unnamed) setParameter(i, words[0]); |
| 241 | + else set(words[0], QVariant()); | ||
| 330 | } else { | 242 | } else { |
| 331 | - insert(words[0], words[1]); | 243 | + set(words[0], words[1]); |
| 332 | } | 244 | } |
| 333 | } | 245 | } |
| 334 | name = name.left(index); | 246 | name = name.left(index); |
| @@ -391,9 +303,8 @@ void FileList::sort(const QString& key) | @@ -391,9 +303,8 @@ void FileList::sort(const QString& key) | ||
| 391 | FileList sortedList; | 303 | FileList sortedList; |
| 392 | 304 | ||
| 393 | for (int i = 0; i < size(); i++) { | 305 | for (int i = 0; i < size(); i++) { |
| 394 | - if (at(i).contains(key)) { | ||
| 395 | - metadata.append(at(i).get(key).toString()); | ||
| 396 | - } | 306 | + if (at(i).contains(key)) |
| 307 | + metadata.append(at(i).get<QString>(key)); | ||
| 397 | else sortedList.push_back(at(i)); | 308 | else sortedList.push_back(at(i)); |
| 398 | } | 309 | } |
| 399 | 310 | ||
| @@ -416,7 +327,7 @@ QList<int> FileList::crossValidationPartitions() const | @@ -416,7 +327,7 @@ QList<int> FileList::crossValidationPartitions() const | ||
| 416 | { | 327 | { |
| 417 | QList<int> crossValidationPartitions; crossValidationPartitions.reserve(size()); | 328 | QList<int> crossValidationPartitions; crossValidationPartitions.reserve(size()); |
| 418 | foreach (const File &f, *this) | 329 | foreach (const File &f, *this) |
| 419 | - crossValidationPartitions.append(f.getInt("Cross_Validation_Partition", 0)); | 330 | + crossValidationPartitions.append(f.get<int>("Cross_Validation_Partition", 0)); |
| 420 | return crossValidationPartitions; | 331 | return crossValidationPartitions; |
| 421 | } | 332 | } |
| 422 | 333 | ||
| @@ -424,7 +335,7 @@ int FileList::failures() const | @@ -424,7 +335,7 @@ int FileList::failures() const | ||
| 424 | { | 335 | { |
| 425 | int failures = 0; | 336 | int failures = 0; |
| 426 | foreach (const File &file, *this) | 337 | foreach (const File &file, *this) |
| 427 | - if (file.getBool("FTO") || file.getBool("FTE")) | 338 | + if (file.get<bool>("FTO", false) || file.get<bool>("FTE", false)) |
| 428 | failures++; | 339 | failures++; |
| 429 | return failures; | 340 | return failures; |
| 430 | } | 341 | } |
| @@ -447,9 +358,9 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | @@ -447,9 +358,9 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | ||
| 447 | foreach (const br::File &file, gallery.split()) { | 358 | foreach (const br::File &file, gallery.split()) { |
| 448 | QScopedPointer<Gallery> i(Gallery::make(file)); | 359 | QScopedPointer<Gallery> i(Gallery::make(file)); |
| 449 | TemplateList newTemplates = i->read(); | 360 | TemplateList newTemplates = i->read(); |
| 450 | - newTemplates = newTemplates.mid(gallery.getInt("pos", 0), gallery.getInt("length", -1)); | ||
| 451 | - if (gallery.getBool("reduce")) newTemplates = newTemplates.reduced(); | ||
| 452 | - const int crossValidate = gallery.getInt("crossValidate"); | 361 | + newTemplates = newTemplates.mid(gallery.get<int>("pos", 0), gallery.get<int>("length", -1)); |
| 362 | + if (gallery.get<bool>("reduce", false)) newTemplates = newTemplates.reduced(); | ||
| 363 | + const int crossValidate = gallery.get<int>("crossValidate"); | ||
| 453 | if (crossValidate > 0) srand(0); | 364 | if (crossValidate > 0) srand(0); |
| 454 | 365 | ||
| 455 | // If file is a Format not a Gallery | 366 | // If file is a Format not a Gallery |
| @@ -460,11 +371,11 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | @@ -460,11 +371,11 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | ||
| 460 | for (int i=0; i<newTemplates.size(); i++) { | 371 | for (int i=0; i<newTemplates.size(); i++) { |
| 461 | newTemplates[i].file.append(gallery.localMetadata()); | 372 | newTemplates[i].file.append(gallery.localMetadata()); |
| 462 | newTemplates[i].file.append(file.localMetadata()); | 373 | newTemplates[i].file.append(file.localMetadata()); |
| 463 | - newTemplates[i].file.insert("Index", i+templates.size()); | ||
| 464 | - if (crossValidate > 0) newTemplates[i].file.insert("Cross_Validation_Partition", rand()%crossValidate); | 374 | + newTemplates[i].file.set("Index", i+templates.size()); |
| 375 | + if (crossValidate > 0) newTemplates[i].file.set("Cross_Validation_Partition", rand()%crossValidate); | ||
| 465 | } | 376 | } |
| 466 | 377 | ||
| 467 | - if (!templates.isEmpty() && gallery.getBool("merge")) { | 378 | + if (!templates.isEmpty() && gallery.get<bool>("merge", false)) { |
| 468 | if (newTemplates.size() != templates.size()) | 379 | if (newTemplates.size() != templates.size()) |
| 469 | qFatal("Inputs must be the same size in order to merge."); | 380 | qFatal("Inputs must be the same size in order to merge."); |
| 470 | for (int i=0; i<templates.size(); i++) | 381 | for (int i=0; i<templates.size(); i++) |
| @@ -494,7 +405,8 @@ TemplateList TemplateList::relabel(const TemplateList &tl) | @@ -494,7 +405,8 @@ TemplateList TemplateList::relabel(const TemplateList &tl) | ||
| 494 | QStringList Object::parameters() const | 405 | QStringList Object::parameters() const |
| 495 | { | 406 | { |
| 496 | QStringList parameters; | 407 | QStringList parameters; |
| 497 | - for (int i=metaObject()->propertyOffset(); i<metaObject()->propertyCount(); i++) { | 408 | + |
| 409 | + for (int i = firstAvailablePropertyIdx; i < metaObject()->propertyCount();i++) { | ||
| 498 | QMetaProperty property = metaObject()->property(i); | 410 | QMetaProperty property = metaObject()->property(i); |
| 499 | if (property.isStored(this)) continue; | 411 | if (property.isStored(this)) continue; |
| 500 | parameters.append(QString("%1 %2 = %3").arg(property.typeName(), property.name(), property.read(this).toString())); | 412 | parameters.append(QString("%1 %2 = %3").arg(property.typeName(), property.name(), property.read(this).toString())); |
| @@ -713,18 +625,37 @@ void Object::init(const File &file_) | @@ -713,18 +625,37 @@ void Object::init(const File &file_) | ||
| 713 | // Set name | 625 | // Set name |
| 714 | QString name = metaObject()->className(); | 626 | QString name = metaObject()->className(); |
| 715 | if (name.startsWith("br::")) name = name.right(name.size()-4); | 627 | if (name.startsWith("br::")) name = name.right(name.size()-4); |
| 716 | - const QMetaObject *superClass = metaObject()->superClass(); | 628 | + |
| 629 | + firstAvailablePropertyIdx = metaObject()->propertyCount(); | ||
| 630 | + | ||
| 631 | + const QMetaObject * baseClass = metaObject(); | ||
| 632 | + const QMetaObject * superClass = metaObject()->superClass(); | ||
| 633 | + | ||
| 717 | while (superClass != NULL) { | 634 | while (superClass != NULL) { |
| 635 | + const QMetaObject * nextClass = superClass->superClass(); | ||
| 636 | + | ||
| 637 | + // baseClass <- something <- br::Object | ||
| 638 | + // baseClass is the highest class whose properties we can set via positional arguments | ||
| 639 | + if (nextClass && !strcmp(nextClass->className(),"br::Object")) { | ||
| 640 | + firstAvailablePropertyIdx = baseClass->propertyOffset(); | ||
| 641 | + } | ||
| 642 | + | ||
| 718 | QString superClassName = superClass->className(); | 643 | QString superClassName = superClass->className(); |
| 644 | + | ||
| 645 | + // strip br:: prefix from superclass name | ||
| 719 | if (superClassName.startsWith("br::")) | 646 | if (superClassName.startsWith("br::")) |
| 720 | superClassName = superClassName.right(superClassName.size()-4); | 647 | superClassName = superClassName.right(superClassName.size()-4); |
| 648 | + | ||
| 649 | + // Strip superclass name from base class name (e.g. PipeTransform -> Pipe) | ||
| 721 | if (name.endsWith(superClassName)) | 650 | if (name.endsWith(superClassName)) |
| 722 | name = name.left(name.size() - superClassName.size()); | 651 | name = name.left(name.size() - superClassName.size()); |
| 652 | + baseClass = superClass; | ||
| 723 | superClass = superClass->superClass(); | 653 | superClass = superClass->superClass(); |
| 654 | + | ||
| 724 | } | 655 | } |
| 725 | setObjectName(name); | 656 | setObjectName(name); |
| 726 | 657 | ||
| 727 | - // Set properties | 658 | + // Reset all properties |
| 728 | for (int i=0; i<metaObject()->propertyCount(); i++) { | 659 | for (int i=0; i<metaObject()->propertyCount(); i++) { |
| 729 | QMetaProperty property = metaObject()->property(i); | 660 | QMetaProperty property = metaObject()->property(i); |
| 730 | if (property.isResettable()) | 661 | if (property.isResettable()) |
| @@ -734,8 +665,17 @@ void Object::init(const File &file_) | @@ -734,8 +665,17 @@ void Object::init(const File &file_) | ||
| 734 | 665 | ||
| 735 | foreach (QString key, file.localKeys()) { | 666 | foreach (QString key, file.localKeys()) { |
| 736 | const QString value = file.value(key).toString(); | 667 | const QString value = file.value(key).toString(); |
| 737 | - if (key.startsWith("_Arg")) | ||
| 738 | - key = metaObject()->property(metaObject()->propertyOffset()+key.mid(4).toInt()).name(); | 668 | + |
| 669 | + if (key.startsWith(("_Arg"))) { | ||
| 670 | + int argument_number = key.mid(4).toInt(); | ||
| 671 | + int target_idx = argument_number + firstAvailablePropertyIdx; | ||
| 672 | + | ||
| 673 | + if (target_idx >= metaObject()->propertyCount()) { | ||
| 674 | + qWarning("too many arguments for transform, ignoring %s\n", qPrintable(value)); | ||
| 675 | + continue; | ||
| 676 | + } | ||
| 677 | + key = metaObject()->property(target_idx).name(); | ||
| 678 | + } | ||
| 739 | setProperty(key, value); | 679 | setProperty(key, value); |
| 740 | } | 680 | } |
| 741 | 681 | ||
| @@ -1107,7 +1047,7 @@ static TemplateList Downsample(const TemplateList &templates, const Transform *t | @@ -1107,7 +1047,7 @@ static TemplateList Downsample(const TemplateList &templates, const Transform *t | ||
| 1107 | const int selectedLabel = selectedLabels[i]; | 1047 | const int selectedLabel = selectedLabels[i]; |
| 1108 | QList<int> indices; | 1048 | QList<int> indices; |
| 1109 | for (int j=0; j<allLabels.size(); j++) | 1049 | for (int j=0; j<allLabels.size(); j++) |
| 1110 | - if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.getBool("FTE"))) | 1050 | + if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.get<bool>("FTE", false))) |
| 1111 | indices.append(j); | 1051 | indices.append(j); |
| 1112 | 1052 | ||
| 1113 | std::random_shuffle(indices.begin(), indices.end()); | 1053 | std::random_shuffle(indices.begin(), indices.end()); |
| @@ -1291,7 +1231,7 @@ static void _project(const Transform *transform, const Template *src, Template * | @@ -1291,7 +1231,7 @@ static void _project(const Transform *transform, const Template *src, Template * | ||
| 1291 | } catch (...) { | 1231 | } catch (...) { |
| 1292 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName())); | 1232 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName())); |
| 1293 | *dst = Template(src->file); | 1233 | *dst = Template(src->file); |
| 1294 | - dst->file.setBool("FTE"); | 1234 | + dst->file.set("FTE", true); |
| 1295 | } | 1235 | } |
| 1296 | } | 1236 | } |
| 1297 | 1237 | ||
| @@ -1302,7 +1242,7 @@ static void _backProject(const Transform *transform, const Template *dst, Templa | @@ -1302,7 +1242,7 @@ static void _backProject(const Transform *transform, const Template *dst, Templa | ||
| 1302 | } catch (...) { | 1242 | } catch (...) { |
| 1303 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName())); | 1243 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName())); |
| 1304 | *src = Template(dst->file); | 1244 | *src = Template(dst->file); |
| 1305 | - src->file.setBool("FTE"); | 1245 | + src->file.set("FTE", true); |
| 1306 | } | 1246 | } |
| 1307 | } | 1247 | } |
| 1308 | 1248 |
sdk/openbr_plugin.h
| @@ -61,6 +61,7 @@ | @@ -61,6 +61,7 @@ | ||
| 61 | * | 61 | * |
| 62 | * \section examples Examples | 62 | * \section examples Examples |
| 63 | * - \ref cpp_face_recognition | 63 | * - \ref cpp_face_recognition |
| 64 | + * - \ref cpp_face_recognition_search | ||
| 64 | * - \ref cpp_age_estimation | 65 | * - \ref cpp_age_estimation |
| 65 | * - \ref cpp_gender_estimation | 66 | * - \ref cpp_gender_estimation |
| 66 | * | 67 | * |
| @@ -68,6 +69,10 @@ | @@ -68,6 +69,10 @@ | ||
| 68 | * \ref cli_face_recognition "Command Line Interface Equivalent" | 69 | * \ref cli_face_recognition "Command Line Interface Equivalent" |
| 69 | * \snippet app/examples/face_recognition.cpp face_recognition | 70 | * \snippet app/examples/face_recognition.cpp face_recognition |
| 70 | * | 71 | * |
| 72 | + * \subsection cpp_face_recognition_search Face Recognition Search | ||
| 73 | + * \ref cli_face_recognition_search "Command Line Interface Equivalent" | ||
| 74 | + * \snippet app/examples/face_recognition_search.cpp face_recognition_search | ||
| 75 | + * | ||
| 71 | * \subsection cpp_age_estimation Age Estimation | 76 | * \subsection cpp_age_estimation Age Estimation |
| 72 | * \ref cli_age_estimation "Command Line Interface Equivalent" | 77 | * \ref cli_age_estimation "Command Line Interface Equivalent" |
| 73 | * \snippet app/examples/age_estimation.cpp age_estimation | 78 | * \snippet app/examples/age_estimation.cpp age_estimation |
| @@ -123,10 +128,8 @@ void reset_##NAME() { NAME = DEFAULT; } | @@ -123,10 +128,8 @@ void reset_##NAME() { NAME = DEFAULT; } | ||
| 123 | * | 128 | * |
| 124 | * Key | Value | Description | 129 | * Key | Value | Description |
| 125 | * --- | ---- | ----------- | 130 | * --- | ---- | ----------- |
| 126 | - * path | QString | Resolve complete file paths from file names | ||
| 127 | - * enrollAll | bool | Enroll zero or more templates per file | ||
| 128 | * separator | QString | Seperate #name into multiple files | 131 | * separator | QString | Seperate #name into multiple files |
| 129 | - * Index | int | Index of a template in a template list | 132 | + * Index | int | Index of a template in a template list |
| 130 | * Label | float | Classification/Regression class | 133 | * Label | float | Classification/Regression class |
| 131 | * Confidence | float | Classification/Regression quality | 134 | * Confidence | float | Classification/Regression quality |
| 132 | * FTE | bool | Failure to enroll | 135 | * FTE | bool | Failure to enroll |
| @@ -140,8 +143,8 @@ void reset_##NAME() { NAME = DEFAULT; } | @@ -140,8 +143,8 @@ void reset_##NAME() { NAME = DEFAULT; } | ||
| 140 | * Roll | float | Pose | 143 | * Roll | float | Pose |
| 141 | * Pitch | float | Pose | 144 | * Pitch | float | Pose |
| 142 | * Yaw | float | Pose | 145 | * Yaw | float | Pose |
| 143 | - * Landmarks | QList<QPointF> | Landmark list | ||
| 144 | - * ROIs | QList<Rect> | Region Of Interest (ROI) list | 146 | + * Points | QList<QPointF> | List of unnamed points |
| 147 | + * Rects | QList<Rect> | List of unnamed rects | ||
| 145 | * Age | QString | Age used for demographic filtering | 148 | * Age | QString | Age used for demographic filtering |
| 146 | * _* | * | Reserved for internal use | 149 | * _* | * | Reserved for internal use |
| 147 | */ | 150 | */ |
| @@ -151,24 +154,26 @@ struct BR_EXPORT File | @@ -151,24 +154,26 @@ struct BR_EXPORT File | ||
| 151 | 154 | ||
| 152 | File() {} | 155 | File() {} |
| 153 | File(const QString &file) { init(file); } /*!< \brief Construct a file from a string. */ | 156 | File(const QString &file) { init(file); } /*!< \brief Construct a file from a string. */ |
| 154 | - File(const QString &file, const QVariant &label) { init(file); insert("Label", label); } /*!< \brief Construct a file from a string and assign a label. */ | 157 | + File(const QString &file, const QVariant &label) { init(file); set("Label", label); } /*!< \brief Construct a file from a string and assign a label. */ |
| 155 | File(const char *file) { init(file); } /*!< \brief Construct a file from a c-style string. */ | 158 | File(const char *file) { init(file); } /*!< \brief Construct a file from a c-style string. */ |
| 156 | inline operator QString() const { return name; } /*!< \brief Returns #name. */ | 159 | inline operator QString() const { return name; } /*!< \brief Returns #name. */ |
| 157 | QString flat() const; /*!< \brief A stringified version of the file with metadata. */ | 160 | QString flat() const; /*!< \brief A stringified version of the file with metadata. */ |
| 158 | QString hash() const; /*!< \brief A hash of the file. */ | 161 | QString hash() const; /*!< \brief A hash of the file. */ |
| 159 | - inline void clear() { name.clear(); m_metadata.clear(); } /*!< \brief Clears the file's name and metadata. */ | ||
| 160 | 162 | ||
| 161 | inline QList<QString> localKeys() const { return m_metadata.keys(); } /*!< \brief Returns the private metadata keys. */ | 163 | inline QList<QString> localKeys() const { return m_metadata.keys(); } /*!< \brief Returns the private metadata keys. */ |
| 162 | - inline QHash<QString,QVariant> localMetadata() const { return m_metadata; } /*!< \brief Returns the private metadata. */ | ||
| 163 | - inline void insert(const QString &key, const QVariant &value) { set(key, value); } /*!< \brief Equivalent to set(). */ | ||
| 164 | - void append(const QHash<QString,QVariant> &localMetadata); /*!< \brief Add new metadata fields. */ | 164 | + inline QMap<QString,QVariant> localMetadata() const { return m_metadata; } /*!< \brief Returns the private metadata. */ |
| 165 | + | ||
| 166 | + void append(const QMap<QString,QVariant> &localMetadata); /*!< \brief Add new metadata fields. */ | ||
| 165 | void append(const File &other); /*!< \brief Append another file using \c separator. */ | 167 | void append(const File &other); /*!< \brief Append another file using \c separator. */ |
| 168 | + inline File &operator+=(const QMap<QString,QVariant> &other) { append(other); return *this; } /*!< \brief Add new metadata fields. */ | ||
| 169 | + inline File &operator+=(const File &other) { append(other); return *this; } /*!< \brief Append another file using \c separator. */ | ||
| 170 | + | ||
| 166 | QList<File> split() const; /*!< \brief Split the file using \c separator. */ | 171 | QList<File> split() const; /*!< \brief Split the file using \c separator. */ |
| 167 | QList<File> split(const QString &separator) const; /*!< \brief Split the file. */ | 172 | QList<File> split(const QString &separator) const; /*!< \brief Split the file. */ |
| 168 | 173 | ||
| 169 | - inline void insertParameter(int index, const QVariant &value) { insert("_Arg" + QString::number(index), value); } /*!< \brief Insert a keyless value. */ | ||
| 170 | - inline bool containsParameter(int index) const { return m_metadata.contains("_Arg" + QString::number(index)); } /*!< \brief Check for the existence of a keyless value. */ | ||
| 171 | - inline QVariant parameter(int index) const { return m_metadata.value("_Arg" + QString::number(index)); } /*!< \brief Retrieve a keyless value. */ | 174 | + inline void setParameter(int index, const QVariant &value) { set("_Arg" + QString::number(index), value); } /*!< \brief Insert a keyless value. */ |
| 175 | + inline bool containsParameter(int index) const { return contains("_Arg" + QString::number(index)); } /*!< \brief Check for the existence of a keyless value. */ | ||
| 176 | + inline QVariant getParameter(int index) const { return get<QVariant>("_Arg" + QString::number(index)); } /*!< \brief Retrieve a keyless value. */ | ||
| 172 | 177 | ||
| 173 | inline bool operator==(const char* other) const { return name == other; } /*!< \brief Compare name to c-style string. */ | 178 | inline bool operator==(const char* other) const { return name == other; } /*!< \brief Compare name to c-style string. */ |
| 174 | inline bool operator==(const File &other) const { return (name == other.name) && (m_metadata == other.m_metadata); } /*!< \brief Compare name and metadata for equality. */ | 179 | inline bool operator==(const File &other) const { return (name == other.name) && (m_metadata == other.m_metadata); } /*!< \brief Compare name and metadata for equality. */ |
| @@ -177,8 +182,6 @@ struct BR_EXPORT File | @@ -177,8 +182,6 @@ struct BR_EXPORT File | ||
| 177 | inline bool operator<=(const File &other) const { return name <= other.name; } /*!< \brief Compare name. */ | 182 | inline bool operator<=(const File &other) const { return name <= other.name; } /*!< \brief Compare name. */ |
| 178 | inline bool operator>(const File &other) const { return name > other.name; } /*!< \brief Compare name. */ | 183 | inline bool operator>(const File &other) const { return name > other.name; } /*!< \brief Compare name. */ |
| 179 | inline bool operator>=(const File &other) const { return name >= other.name; } /*!< \brief Compare name. */ | 184 | inline bool operator>=(const File &other) const { return name >= other.name; } /*!< \brief Compare name. */ |
| 180 | - inline File &operator+=(const QHash<QString,QVariant> &other) { append(other); return *this; } /*!< \brief Add new metadata fields. */ | ||
| 181 | - inline File &operator+=(const File &other) { append(other); return *this; } /*!< \brief Append another file using \c separator. */ | ||
| 182 | 185 | ||
| 183 | inline bool isNull() const { return name.isEmpty() && m_metadata.isEmpty(); } /*!< \brief Returns \c true if name and metadata are empty, \c false otherwise. */ | 186 | inline bool isNull() const { return name.isEmpty() && m_metadata.isEmpty(); } /*!< \brief Returns \c true if name and metadata are empty, \c false otherwise. */ |
| 184 | inline bool isTerminal() const { return name == "terminal"; } /*!< \brief Returns \c true if #name is "terminal", \c false otherwise. */ | 187 | inline bool isTerminal() const { return name == "terminal"; } /*!< \brief Returns \c true if #name is "terminal", \c false otherwise. */ |
| @@ -191,42 +194,53 @@ struct BR_EXPORT File | @@ -191,42 +194,53 @@ struct BR_EXPORT File | ||
| 191 | 194 | ||
| 192 | bool contains(const QString &key) const; /*!< \brief Returns \c true if the key has an associated value, \c false otherwise. */ | 195 | bool contains(const QString &key) const; /*!< \brief Returns \c true if the key has an associated value, \c false otherwise. */ |
| 193 | QVariant value(const QString &key) const; /*!< \brief Returns the value for the specified key. */ | 196 | QVariant value(const QString &key) const; /*!< \brief Returns the value for the specified key. */ |
| 197 | + void set(const QString &key, const QVariant &value); /*!< \brief Insert or overwrite the metadata key with the specified value. */ | ||
| 198 | + inline void remove(const QString &key) { m_metadata.remove(key); } /*!< \brief Remove the metadata key. */ | ||
| 199 | + | ||
| 200 | + /*!< \brief Returns a value for the key, throwing an error if the key does not exist. */ | ||
| 201 | + template <typename T> | ||
| 202 | + T get(const QString &key) const | ||
| 203 | + { | ||
| 204 | + if (!contains(key)) qFatal("Missing key: %s", qPrintable(key)); | ||
| 205 | + QVariant variant = value(key); | ||
| 206 | + if (!variant.canConvert<T>()) qFatal("Can't convert: %s", qPrintable(key)); | ||
| 207 | + return variant.value<T>(); | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + /*!< \brief Returns a value for the key, returning \em defaultValue if the key does not exist or can't be converted. */ | ||
| 211 | + template <typename T> | ||
| 212 | + T get(const QString &key, const T &defaultValue) const | ||
| 213 | + { | ||
| 214 | + if (!contains(key)) return defaultValue; | ||
| 215 | + QVariant variant = value(key); | ||
| 216 | + if (!variant.canConvert<T>()) return defaultValue; | ||
| 217 | + return variant.value<T>(); | ||
| 218 | + } | ||
| 219 | + | ||
| 194 | static QString subject(int label); /*!< \brief Looks up the subject for the provided label. */ | 220 | static QString subject(int label); /*!< \brief Looks up the subject for the provided label. */ |
| 195 | inline QString subject() const { return subject(label()); } /*!< \brief Looks up the subject from the file's label. */ | 221 | inline QString subject() const { return subject(label()); } /*!< \brief Looks up the subject from the file's label. */ |
| 196 | - inline bool failed() const { return getBool("FTE") || getBool("FTO"); } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */ | ||
| 197 | - | ||
| 198 | - void remove(const QString &key); /*!< \brief Remove the metadata key. */ | ||
| 199 | - void set(const QString &key, const QVariant &value); /*!< \brief Insert or overwrite the metadata key with the specified value. */ | ||
| 200 | - QVariant get(const QString &key) const; /*!< \brief Returns a QVariant for the key, throwing an error if the key does not exist. */ | ||
| 201 | - QVariant get(const QString &key, const QVariant &value) const; /*!< \brief Returns a QVariant for the key, returning \em defaultValue if the key does not exist. */ | ||
| 202 | float label() const; /*!< \brief Convenience function for retrieving the file's \c Label. */ | 222 | float label() const; /*!< \brief Convenience function for retrieving the file's \c Label. */ |
| 203 | - inline void setLabel(float label) { insert("Label", label); } /*!< \brief Convenience function for setting the file's \c Label. */ | ||
| 204 | - bool getBool(const QString &key) const; /*!< \brief Returns a boolean value for the key. */ | ||
| 205 | - void setBool(const QString &key, bool value = true); /*!< \brief Sets a boolean value for the key. */ | ||
| 206 | - int getInt(const QString &key) const; /*!< \brief Returns an int value for the key, throwing an error if the key does not exist. */ | ||
| 207 | - int getInt(const QString &key, int defaultValue) const; /*!< \brief Returns an int value for the key, returning \em defaultValue if the key does not exist. */ | ||
| 208 | - float getFloat(const QString &key) const; /*!< \brief Returns a float value for the key, throwing an error if the key does not exist. */ | ||
| 209 | - float getFloat(const QString &key, float defaultValue) const; /*!< \brief Returns a float value for the key, returning \em defaultValue if the key does not exist. */ | ||
| 210 | - QString getString(const QString &key) const; /*!< \brief Returns a string value for the key, throwing an error if the key does not exist. */ | ||
| 211 | - QString getString(const QString &key, const QString &defaultValue) const; /*!< \brief Returns a string value for the key, returning \em defaultValue if the key does not exist. */ | ||
| 212 | - | ||
| 213 | - QList<QPointF> landmarks() const; /*!< \brief Returns the file's landmark list. */ | ||
| 214 | - QList<QPointF> namedLandmarks() const; /*!< \brief Returns landmarks derived from metadata keys. */ | ||
| 215 | - void appendLandmark(const QPointF &landmark); /*!< \brief Adds a landmark to the file's landmark list. */ | ||
| 216 | - void appendLandmarks(const QList<QPointF> &landmarks); /*!< \brief Adds landmarks to the file's landmark list. */ | ||
| 217 | - inline void clearLandmarks() { m_metadata["Landmarks"] = QList<QVariant>(); } /*!< \brief Clears the file's landmark list. */ | ||
| 218 | - void setLandmarks(const QList<QPointF> &landmarks); /*!< \brief Assigns the file's landmark list. */ | ||
| 219 | - | ||
| 220 | - QList<QRectF> ROIs() const; /*!< \brief Returns the file's ROI list. */ | ||
| 221 | - void appendROI(const QRectF &ROI); /*!< \brief Adds a ROI to the file's ROI list. */ | ||
| 222 | - void appendROIs(const QList<QRectF> &ROIs); /*!< \brief Adds ROIs to the file's ROI list. */ | ||
| 223 | - inline void clearROIs() { m_metadata["ROIs"] = QList<QVariant>(); } /*!< \brief Clears the file's landmark list. */ | ||
| 224 | - void setROIs(const QList<QRectF> &ROIs); /*!< \brief Assigns the file's landmark list. */ | 223 | + inline void setLabel(float label) { set("Label", label); } /*!< \brief Convenience function for setting the file's \c Label. */ |
| 224 | + inline bool failed() const { return get<bool>("FTE", false) || get<bool>("FTO", false); } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */ | ||
| 225 | + | ||
| 226 | + QList<QPointF> namedPoints() const; /*!< \brief Returns points convertible from metadata keys. */ | ||
| 227 | + QList<QPointF> points() const; /*!< \brief Returns the file's points list. */ | ||
| 228 | + void appendPoint(const QPointF &point); /*!< \brief Adds a point to the file's point list. */ | ||
| 229 | + void appendPoints(const QList<QPointF> &points); /*!< \brief Adds landmarks to the file's landmark list. */ | ||
| 230 | + inline void clearPoints() { m_metadata["Points"] = QList<QVariant>(); } /*!< \brief Clears the file's landmark list. */ | ||
| 231 | + inline void setPoints(const QList<QPointF> &points) { clearPoints(); appendPoints(points); } /*!< \brief Overwrites the file's landmark list. */ | ||
| 232 | + | ||
| 233 | + QList<QRectF> namedRects() const; /*!< \brief Returns rects convertible from metadata values. */ | ||
| 234 | + QList<QRectF> rects() const; /*!< \brief Returns the file's rects list. */ | ||
| 235 | + void appendRect(const QRectF &rect); /*!< \brief Adds a rect to the file's rect list. */ | ||
| 236 | + void appendRects(const QList<QRectF> &rects); /*!< \brief Adds rects to the file's rect list. */ | ||
| 237 | + inline void clearRects() { m_metadata["Rects"] = QList<QVariant>(); } /*!< \brief Clears the file's rect list. */ | ||
| 238 | + inline void setRects(const QList<QRectF> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */ | ||
| 225 | 239 | ||
| 226 | private: | 240 | private: |
| 227 | - QHash<QString,QVariant> m_metadata; | ||
| 228 | - BR_EXPORT friend QDataStream &operator<<(QDataStream &stream, const File &file); /*!< */ | ||
| 229 | - BR_EXPORT friend QDataStream &operator>>(QDataStream &stream, File &file); /*!< */ | 241 | + QMap<QString,QVariant> m_metadata; |
| 242 | + BR_EXPORT friend QDataStream &operator<<(QDataStream &stream, const File &file); | ||
| 243 | + BR_EXPORT friend QDataStream &operator>>(QDataStream &stream, File &file); | ||
| 230 | 244 | ||
| 231 | void init(const QString &file); | 245 | void init(const QString &file); |
| 232 | }; | 246 | }; |
| @@ -416,6 +430,9 @@ class BR_EXPORT Object : public QObject | @@ -416,6 +430,9 @@ class BR_EXPORT Object : public QObject | ||
| 416 | { | 430 | { |
| 417 | Q_OBJECT | 431 | Q_OBJECT |
| 418 | 432 | ||
| 433 | + // Index of the first property that can be set via command line arguments | ||
| 434 | + int firstAvailablePropertyIdx; | ||
| 435 | + | ||
| 419 | public: | 436 | public: |
| 420 | File file; /*!< \brief The file used to construct the plugin. */ | 437 | File file; /*!< \brief The file used to construct the plugin. */ |
| 421 | 438 | ||
| @@ -984,6 +1001,49 @@ public: | @@ -984,6 +1001,49 @@ public: | ||
| 984 | virtual void backProject(const Template &dst, Template &src) const; /*!< \brief Invert the transform. */ | 1001 | virtual void backProject(const Template &dst, Template &src) const; /*!< \brief Invert the transform. */ |
| 985 | virtual void backProject(const TemplateList &dst, TemplateList &src) const; /*!< \brief Invert the transform. */ | 1002 | virtual void backProject(const TemplateList &dst, TemplateList &src) const; /*!< \brief Invert the transform. */ |
| 986 | 1003 | ||
| 1004 | + /*!< \brief Apply the transform, may update the transform's internal state */ | ||
| 1005 | + virtual void projectUpdate(const Template &src, Template &dst) | ||
| 1006 | + { | ||
| 1007 | + project(src, dst); | ||
| 1008 | + } | ||
| 1009 | + | ||
| 1010 | + /*!< \brief Apply the transform, may update the transform's internal state */ | ||
| 1011 | + virtual void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 1012 | + { | ||
| 1013 | + project(src,dst); | ||
| 1014 | + } | ||
| 1015 | + | ||
| 1016 | + /*!< \brief inplace projectUpdate. */ | ||
| 1017 | + void projectUpdate(Template &srcdst) | ||
| 1018 | + { | ||
| 1019 | + Template dst; | ||
| 1020 | + projectUpdate(srcdst, dst); | ||
| 1021 | + srcdst = dst; | ||
| 1022 | + } | ||
| 1023 | + | ||
| 1024 | + /*!< \brief inplace projectUpdate. */ | ||
| 1025 | + void projectUpdate(TemplateList &srcdst) | ||
| 1026 | + { | ||
| 1027 | + TemplateList dst; | ||
| 1028 | + projectUpdate(srcdst, dst); | ||
| 1029 | + srcdst = dst; | ||
| 1030 | + } | ||
| 1031 | + | ||
| 1032 | + /*! | ||
| 1033 | + * Time-varying transforms may move away from a single input->single output model, and only emit | ||
| 1034 | + * templates under some conditions (e.g. a tracking thing may emit a template for each detected | ||
| 1035 | + * unique object), in this case finalize indicates that no further calls to project will be made | ||
| 1036 | + * and the transform can emit a final set if templates if it wants. Time-invariant transforms | ||
| 1037 | + * don't have to do anything. | ||
| 1038 | + */ | ||
| 1039 | + virtual void finalize(TemplateList & output) { output = TemplateList(); } | ||
| 1040 | + | ||
| 1041 | + /*! | ||
| 1042 | + * \brief Does the transform require the non-const version of project? Can vary for aggregation type transforms | ||
| 1043 | + * (if their children are time varying, they are also time varying, otherwise probably not) | ||
| 1044 | + */ | ||
| 1045 | + virtual bool timeVarying() const { return false; } | ||
| 1046 | + | ||
| 987 | /*! | 1047 | /*! |
| 988 | * \brief Convenience function equivalent to project(). | 1048 | * \brief Convenience function equivalent to project(). |
| 989 | */ | 1049 | */ |
| @@ -1047,6 +1107,31 @@ inline QDataStream &operator>>(QDataStream &stream, Transform &f) | @@ -1047,6 +1107,31 @@ inline QDataStream &operator>>(QDataStream &stream, Transform &f) | ||
| 1047 | } | 1107 | } |
| 1048 | 1108 | ||
| 1049 | /*! | 1109 | /*! |
| 1110 | + * \brief A br::Transform for which the results of project may change due to prior calls to project | ||
| 1111 | + */ | ||
| 1112 | +class BR_EXPORT TimeVaryingTransform : public Transform | ||
| 1113 | +{ | ||
| 1114 | + Q_OBJECT | ||
| 1115 | + | ||
| 1116 | + virtual bool timeVarying() const { return true; } | ||
| 1117 | + | ||
| 1118 | + virtual void project(const Template &src, Template &dst) const | ||
| 1119 | + { | ||
| 1120 | + qFatal("No const project defined for time-varying transform"); | ||
| 1121 | + (void) dst; (void) src; | ||
| 1122 | + } | ||
| 1123 | + | ||
| 1124 | + virtual void project(const TemplateList &src, TemplateList &dst) const | ||
| 1125 | + { | ||
| 1126 | + qFatal("No const project defined for time-varying transform"); | ||
| 1127 | + (void) dst; (void) src; | ||
| 1128 | + } | ||
| 1129 | + | ||
| 1130 | +protected: | ||
| 1131 | + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} | ||
| 1132 | +}; | ||
| 1133 | + | ||
| 1134 | +/*! | ||
| 1050 | * \brief A br::Transform expecting multiple matrices per template. | 1135 | * \brief A br::Transform expecting multiple matrices per template. |
| 1051 | */ | 1136 | */ |
| 1052 | class BR_EXPORT MetaTransform : public Transform | 1137 | class BR_EXPORT MetaTransform : public Transform |
| @@ -1074,7 +1159,6 @@ private: | @@ -1074,7 +1159,6 @@ private: | ||
| 1074 | void load(QDataStream &stream) { (void) stream; } | 1159 | void load(QDataStream &stream) { (void) stream; } |
| 1075 | }; | 1160 | }; |
| 1076 | 1161 | ||
| 1077 | - | ||
| 1078 | /*! | 1162 | /*! |
| 1079 | * \brief A br::MetaTransform that does not require training data. | 1163 | * \brief A br::MetaTransform that does not require training data. |
| 1080 | */ | 1164 | */ |
sdk/plugins/cascade.cpp
| @@ -75,15 +75,15 @@ class CascadeTransform : public UntrainableTransform | @@ -75,15 +75,15 @@ class CascadeTransform : public UntrainableTransform | ||
| 75 | { | 75 | { |
| 76 | CascadeClassifier *cascade = cascadeResource.acquire(); | 76 | CascadeClassifier *cascade = cascadeResource.acquire(); |
| 77 | vector<Rect> rects; | 77 | vector<Rect> rects; |
| 78 | - cascade->detectMultiScale(src, rects, 1.2, 5, src.file.getBool("enrollAll") ? 0 : CV_HAAR_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); | 78 | + cascade->detectMultiScale(src, rects, 1.2, 5, src.file.get<bool>("enrollAll", false) ? 0 : CV_HAAR_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); |
| 79 | cascadeResource.release(cascade); | 79 | cascadeResource.release(cascade); |
| 80 | 80 | ||
| 81 | - if (!src.file.getBool("enrollAll") && rects.empty()) | 81 | + if (!src.file.get<bool>("enrollAll", false) && rects.empty()) |
| 82 | rects.push_back(Rect(0, 0, src.m().cols, src.m().rows)); | 82 | rects.push_back(Rect(0, 0, src.m().cols, src.m().rows)); |
| 83 | 83 | ||
| 84 | foreach (const Rect &rect, rects) { | 84 | foreach (const Rect &rect, rects) { |
| 85 | dst += src; | 85 | dst += src; |
| 86 | - dst.file.appendROI(OpenCVUtils::fromRect(rect)); | 86 | + dst.file.appendRect(OpenCVUtils::fromRect(rect)); |
| 87 | } | 87 | } |
| 88 | } | 88 | } |
| 89 | }; | 89 | }; |
sdk/plugins/crop.cpp
| @@ -26,7 +26,7 @@ namespace br | @@ -26,7 +26,7 @@ namespace br | ||
| 26 | 26 | ||
| 27 | /*! | 27 | /*! |
| 28 | * \ingroup transforms | 28 | * \ingroup transforms |
| 29 | - * \brief Crops the regions of interest. | 29 | + * \brief Crops the rectangular regions of interest. |
| 30 | * \author Josh Klontz \cite jklontz | 30 | * \author Josh Klontz \cite jklontz |
| 31 | */ | 31 | */ |
| 32 | class ROITransform : public UntrainableTransform | 32 | class ROITransform : public UntrainableTransform |
| @@ -35,8 +35,8 @@ class ROITransform : public UntrainableTransform | @@ -35,8 +35,8 @@ class ROITransform : public UntrainableTransform | ||
| 35 | 35 | ||
| 36 | void project(const Template &src, Template &dst) const | 36 | void project(const Template &src, Template &dst) const |
| 37 | { | 37 | { |
| 38 | - foreach (const QRectF ROI, src.file.ROIs()) | ||
| 39 | - dst += src.m()(OpenCVUtils::toRect(ROI)); | 38 | + foreach (const QRectF &rect, src.file.rects()) |
| 39 | + dst += src.m()(OpenCVUtils::toRect(rect)); | ||
| 40 | } | 40 | } |
| 41 | }; | 41 | }; |
| 42 | 42 |
sdk/plugins/draw.cpp
| @@ -47,19 +47,19 @@ class DrawTransform : public UntrainableTransform | @@ -47,19 +47,19 @@ class DrawTransform : public UntrainableTransform | ||
| 47 | const Scalar verboseColor(255, 255, 0); | 47 | const Scalar verboseColor(255, 255, 0); |
| 48 | dst = src.m().clone(); | 48 | dst = src.m().clone(); |
| 49 | 49 | ||
| 50 | - QList<Point2f> landmarks = OpenCVUtils::toPoints(src.file.landmarks()); | 50 | + QList<Point2f> landmarks = OpenCVUtils::toPoints(src.file.points()); |
| 51 | 51 | ||
| 52 | if (unnamed) { | 52 | if (unnamed) { |
| 53 | foreach (const Point2f &landmark, landmarks) | 53 | foreach (const Point2f &landmark, landmarks) |
| 54 | circle(dst, landmark, 3, color, -1); | 54 | circle(dst, landmark, 3, color, -1); |
| 55 | } | 55 | } |
| 56 | if (named) { | 56 | if (named) { |
| 57 | - QList<Point2f> namedLandmarks = OpenCVUtils::toPoints(src.file.namedLandmarks()); | 57 | + QList<Point2f> namedLandmarks = OpenCVUtils::toPoints(src.file.namedPoints()); |
| 58 | foreach (const Point2f &landmark, namedLandmarks) | 58 | foreach (const Point2f &landmark, namedLandmarks) |
| 59 | circle(dst, landmark, 3, color); | 59 | circle(dst, landmark, 3, color); |
| 60 | } | 60 | } |
| 61 | if (ROI) { | 61 | if (ROI) { |
| 62 | - QList<Rect> ROIs = OpenCVUtils::toRects(src.file.ROIs()); | 62 | + QList<Rect> ROIs = OpenCVUtils::toRects(src.file.rects()); |
| 63 | foreach (const Rect ROI, ROIs) | 63 | foreach (const Rect ROI, ROIs) |
| 64 | rectangle(dst, ROI, color); | 64 | rectangle(dst, ROI, color); |
| 65 | } | 65 | } |
| @@ -154,11 +154,11 @@ class EditTransform : public UntrainableTransform | @@ -154,11 +154,11 @@ class EditTransform : public UntrainableTransform | ||
| 154 | { | 154 | { |
| 155 | (void) event; | 155 | (void) event; |
| 156 | if (flags) { | 156 | if (flags) { |
| 157 | - QList<QRectF> ROIs = currentTemplate.file.ROIs(); | ||
| 158 | - for (int i=ROIs.size()-1; i>=0; i--) | ||
| 159 | - if (ROIs[i].contains(x,y)) | ||
| 160 | - ROIs.removeAt(i); | ||
| 161 | - currentTemplate.file.setROIs(ROIs); | 157 | + QList<QRectF> rects = currentTemplate.file.rects(); |
| 158 | + for (int i=rects.size()-1; i>=0; i--) | ||
| 159 | + if (rects[i].contains(x,y)) | ||
| 160 | + rects.removeAt(i); | ||
| 161 | + currentTemplate.file.setRects(rects); | ||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | Template temp; | 164 | Template temp; |
sdk/plugins/eigen3.cpp
| @@ -228,7 +228,7 @@ class DFFSTransform : public Transform | @@ -228,7 +228,7 @@ class DFFSTransform : public Transform | ||
| 228 | void project(const Template &src, Template &dst) const | 228 | void project(const Template &src, Template &dst) const |
| 229 | { | 229 | { |
| 230 | dst = src; | 230 | dst = src; |
| 231 | - dst.file.insert("DFFS", sqrt(pca.residualReconstructionError((*cvtFloat)(src)))); | 231 | + dst.file.set("DFFS", sqrt(pca.residualReconstructionError((*cvtFloat)(src)))); |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | void store(QDataStream &stream) const | 234 | void store(QDataStream &stream) const |
sdk/plugins/eyes.cpp
| @@ -147,7 +147,7 @@ public: | @@ -147,7 +147,7 @@ public: | ||
| 147 | private: | 147 | private: |
| 148 | void project(const Template &src, Template &dst) const | 148 | void project(const Template &src, Template &dst) const |
| 149 | { | 149 | { |
| 150 | - Rect roi = OpenCVUtils::toRect(src.file.ROIs().first()); | 150 | + Rect roi = OpenCVUtils::toRect(src.file.rects().first()); |
| 151 | 151 | ||
| 152 | Mat gray; | 152 | Mat gray; |
| 153 | OpenCVUtils::cvtGray(src.m()(roi), gray); | 153 | OpenCVUtils::cvtGray(src.m()(roi), gray); |
| @@ -183,12 +183,10 @@ private: | @@ -183,12 +183,10 @@ private: | ||
| 183 | float second_eye_y = (right_rect.y + maxLoc.y)*gray.rows/height+roi.y; | 183 | float second_eye_y = (right_rect.y + maxLoc.y)*gray.rows/height+roi.y; |
| 184 | 184 | ||
| 185 | dst = src; | 185 | dst = src; |
| 186 | - dst.file.appendLandmark(QPointF(first_eye_x, first_eye_y)); | ||
| 187 | - dst.file.appendLandmark(QPointF(second_eye_x, second_eye_y)); | ||
| 188 | - dst.file.insert("ASEF_Right_Eye_X", first_eye_x); | ||
| 189 | - dst.file.insert("ASEF_Right_Eye_Y", first_eye_y); | ||
| 190 | - dst.file.insert("ASEF_Left_Eye_X", second_eye_x); | ||
| 191 | - dst.file.insert("ASEF_Left_Eye_Y", second_eye_y); | 186 | + dst.file.appendPoint(QPointF(first_eye_x, first_eye_y)); |
| 187 | + dst.file.appendPoint(QPointF(second_eye_x, second_eye_y)); | ||
| 188 | + dst.file.set("ASEF_Right_Eye", QPointF(first_eye_x, first_eye_y)); | ||
| 189 | + dst.file.set("ASEF_Left_Eye", QPointF(second_eye_x, second_eye_y)); | ||
| 192 | } | 190 | } |
| 193 | }; | 191 | }; |
| 194 | 192 |
sdk/plugins/format.cpp
| @@ -217,11 +217,11 @@ class DefaultFormat : public Format | @@ -217,11 +217,11 @@ class DefaultFormat : public Format | ||
| 217 | } else { | 217 | } else { |
| 218 | QString fileName = file.name; | 218 | QString fileName = file.name; |
| 219 | if (!QFileInfo(fileName).exists()) { | 219 | if (!QFileInfo(fileName).exists()) { |
| 220 | - fileName = file.getString("path") + "/" + file.name; | 220 | + fileName = file.get<QString>("path") + "/" + file.name; |
| 221 | if (!QFileInfo(fileName).exists()) { | 221 | if (!QFileInfo(fileName).exists()) { |
| 222 | fileName = file.fileName(); | 222 | fileName = file.fileName(); |
| 223 | if (!QFileInfo(fileName).exists()) { | 223 | if (!QFileInfo(fileName).exists()) { |
| 224 | - fileName = file.getString("path") + "/" + file.fileName(); | 224 | + fileName = file.get<QString>("path") + "/" + file.fileName(); |
| 225 | if (!QFileInfo(fileName).exists()) return t; | 225 | if (!QFileInfo(fileName).exists()) return t; |
| 226 | } | 226 | } |
| 227 | } | 227 | } |
| @@ -604,7 +604,7 @@ class xmlFormat : public Format | @@ -604,7 +604,7 @@ class xmlFormat : public Format | ||
| 604 | (e.tagName() == "RPROFILE")) { | 604 | (e.tagName() == "RPROFILE")) { |
| 605 | // Ignore these other image fields for now | 605 | // Ignore these other image fields for now |
| 606 | } else { | 606 | } else { |
| 607 | - t.file.insert(e.tagName(), e.text()); | 607 | + t.file.set(e.tagName(), e.text()); |
| 608 | } | 608 | } |
| 609 | 609 | ||
| 610 | fileNode = fileNode.nextSibling(); | 610 | fileNode = fileNode.nextSibling(); |
| @@ -614,11 +614,11 @@ class xmlFormat : public Format | @@ -614,11 +614,11 @@ class xmlFormat : public Format | ||
| 614 | 614 | ||
| 615 | // Calculate age | 615 | // Calculate age |
| 616 | if (t.file.contains("DOB")) { | 616 | if (t.file.contains("DOB")) { |
| 617 | - const QDate dob = QDate::fromString(t.file.getString("DOB").left(10), "yyyy-MM-dd"); | 617 | + const QDate dob = QDate::fromString(t.file.get<QString>("DOB").left(10), "yyyy-MM-dd"); |
| 618 | const QDate current = QDate::currentDate(); | 618 | const QDate current = QDate::currentDate(); |
| 619 | int age = current.year() - dob.year(); | 619 | int age = current.year() - dob.year(); |
| 620 | if (current.month() < dob.month()) age--; | 620 | if (current.month() < dob.month()) age--; |
| 621 | - t.file.insert("Age", age); | 621 | + t.file.set("Age", age); |
| 622 | } | 622 | } |
| 623 | 623 | ||
| 624 | return t; | 624 | return t; |
sdk/plugins/gallery.cpp
| @@ -22,13 +22,13 @@ | @@ -22,13 +22,13 @@ | ||
| 22 | #include <QSqlQuery> | 22 | #include <QSqlQuery> |
| 23 | #include <QSqlRecord> | 23 | #include <QSqlRecord> |
| 24 | #endif // BR_EMBEDDED | 24 | #endif // BR_EMBEDDED |
| 25 | +#include <opencv2/highgui/highgui.hpp> | ||
| 25 | #include <openbr_plugin.h> | 26 | #include <openbr_plugin.h> |
| 26 | 27 | ||
| 27 | #include "NaturalStringCompare.h" | 28 | #include "NaturalStringCompare.h" |
| 28 | #include "core/bee.h" | 29 | #include "core/bee.h" |
| 29 | #include "core/opencvutils.h" | 30 | #include "core/opencvutils.h" |
| 30 | #include "core/qtutils.h" | 31 | #include "core/qtutils.h" |
| 31 | -#include <opencv2/highgui/highgui.hpp> | ||
| 32 | 32 | ||
| 33 | namespace br | 33 | namespace br |
| 34 | { | 34 | { |
| @@ -47,7 +47,7 @@ class galGallery : public Gallery | @@ -47,7 +47,7 @@ class galGallery : public Gallery | ||
| 47 | void init() | 47 | void init() |
| 48 | { | 48 | { |
| 49 | gallery.setFileName(file); | 49 | gallery.setFileName(file); |
| 50 | - if (file.getBool("remove")) | 50 | + if (file.get<bool>("remove", false)) |
| 51 | gallery.remove(); | 51 | gallery.remove(); |
| 52 | QtUtils::touchDir(gallery); | 52 | QtUtils::touchDir(gallery); |
| 53 | if (!gallery.open(QFile::ReadWrite | QFile::Append)) | 53 | if (!gallery.open(QFile::ReadWrite | QFile::Append)) |
| @@ -339,20 +339,33 @@ class csvGallery : public Gallery | @@ -339,20 +339,33 @@ class csvGallery : public Gallery | ||
| 339 | { | 339 | { |
| 340 | if (files.isEmpty()) return; | 340 | if (files.isEmpty()) return; |
| 341 | 341 | ||
| 342 | - QStringList keys; | 342 | + QMap<QString,QVariant> samples; |
| 343 | foreach (const File &file, files) | 343 | foreach (const File &file, files) |
| 344 | foreach (const QString &key, file.localKeys()) | 344 | foreach (const QString &key, file.localKeys()) |
| 345 | - if (!keys.contains(key)) keys += key; | ||
| 346 | - qSort(keys); | 345 | + if (!samples.contains(key)) |
| 346 | + samples.insert(key, file.value(key)); | ||
| 347 | + | ||
| 348 | + QStringList lines; | ||
| 349 | + lines.reserve(files.size()+1); | ||
| 350 | + | ||
| 351 | + { // Make header | ||
| 352 | + QStringList words; | ||
| 353 | + words.append("File"); | ||
| 354 | + foreach (const QString &key, samples.keys()) | ||
| 355 | + words.append(getCSVElement(key, samples[key], true)); | ||
| 356 | + lines.append(words.join(",")); | ||
| 357 | + } | ||
| 347 | 358 | ||
| 348 | - const int rows = files.size(); | ||
| 349 | - const int columns = keys.size(); | ||
| 350 | - QSharedPointer<Output> output(Output::make(file, keys, files)); | 359 | + // Make table |
| 360 | + foreach (const File &file, files) { | ||
| 361 | + QStringList words; | ||
| 362 | + words.append(file.name); | ||
| 363 | + foreach (const QString &key, samples.keys()) | ||
| 364 | + words.append(getCSVElement(key, file.value(key), false)); | ||
| 365 | + lines.append(words.join(",")); | ||
| 366 | + } | ||
| 351 | 367 | ||
| 352 | - for (int i=0; i<rows; i++) | ||
| 353 | - for (int j=0; j<columns; j++) | ||
| 354 | - if (keys[j] == "Label") output->setRelative(files[i].label(), i, j); | ||
| 355 | - else output->setRelative(files[i].getFloat(keys[j], std::numeric_limits<float>::quiet_NaN()), i, j); | 368 | + QtUtils::writeFile(file, lines); |
| 356 | } | 369 | } |
| 357 | 370 | ||
| 358 | TemplateList readBlock(bool *done) | 371 | TemplateList readBlock(bool *done) |
| @@ -377,6 +390,25 @@ class csvGallery : public Gallery | @@ -377,6 +390,25 @@ class csvGallery : public Gallery | ||
| 377 | { | 390 | { |
| 378 | files.append(t.file); | 391 | files.append(t.file); |
| 379 | } | 392 | } |
| 393 | + | ||
| 394 | + static QString getCSVElement(const QString &key, const QVariant &value, bool header) | ||
| 395 | + { | ||
| 396 | + if (value.canConvert<QString>()) { | ||
| 397 | + if (header) return key; | ||
| 398 | + else return value.value<QString>(); | ||
| 399 | + } else if (value.canConvert<QPointF>()) { | ||
| 400 | + const QPointF point = value.value<QPointF>(); | ||
| 401 | + if (header) return key+"_X,"+key+"_Y"; | ||
| 402 | + else return QString::number(point.x())+","+QString::number(point.y()); | ||
| 403 | + } else if (value.canConvert<QRectF>()) { | ||
| 404 | + const QRectF rect = value.value<QRectF>(); | ||
| 405 | + if (header) return key+"_X,"+key+"_Y,"+key+"_Width,"+key+"_Height"; | ||
| 406 | + else return QString::number(rect.x())+","+QString::number(rect.y())+","+QString::number(rect.width())+","+QString::number(rect.height()); | ||
| 407 | + } else { | ||
| 408 | + if (header) return key; | ||
| 409 | + else return QString::number(std::numeric_limits<float>::quiet_NaN()); | ||
| 410 | + } | ||
| 411 | + } | ||
| 380 | }; | 412 | }; |
| 381 | 413 | ||
| 382 | BR_REGISTER(Gallery, csvGallery) | 414 | BR_REGISTER(Gallery, csvGallery) |
| @@ -465,9 +497,9 @@ class dbGallery : public Gallery | @@ -465,9 +497,9 @@ class dbGallery : public Gallery | ||
| 465 | TemplateList readBlock(bool *done) | 497 | TemplateList readBlock(bool *done) |
| 466 | { | 498 | { |
| 467 | TemplateList templates; | 499 | TemplateList templates; |
| 468 | - br::File import = file.getString("import", ""); | ||
| 469 | - QString query = file.getString("query"); | ||
| 470 | - QString subset = file.getString("subset", ""); | 500 | + br::File import = file.get<QString>("import", ""); |
| 501 | + QString query = file.get<QString>("query"); | ||
| 502 | + QString subset = file.get<QString>("subset", ""); | ||
| 471 | 503 | ||
| 472 | #ifndef BR_EMBEDDED | 504 | #ifndef BR_EMBEDDED |
| 473 | QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); | 505 | QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); |
sdk/plugins/hist.cpp
| @@ -66,6 +66,38 @@ BR_REGISTER(Transform, HistTransform) | @@ -66,6 +66,38 @@ BR_REGISTER(Transform, HistTransform) | ||
| 66 | 66 | ||
| 67 | /*! | 67 | /*! |
| 68 | * \ingroup transforms | 68 | * \ingroup transforms |
| 69 | + * \brief Quantizes the values into bins. | ||
| 70 | + * \author Josh Klontz \cite jklontz | ||
| 71 | + */ | ||
| 72 | +class BinTransform : public UntrainableTransform | ||
| 73 | +{ | ||
| 74 | + Q_OBJECT | ||
| 75 | + Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min STORED false) | ||
| 76 | + Q_PROPERTY(float max READ get_max WRITE set_max RESET reset_max STORED false) | ||
| 77 | + Q_PROPERTY(int bins READ get_bins WRITE set_bins RESET reset_bins STORED false) | ||
| 78 | + Q_PROPERTY(bool split READ get_split WRITE set_split RESET reset_split STORED false) | ||
| 79 | + BR_PROPERTY(float, min, 0) | ||
| 80 | + BR_PROPERTY(float, max, 255) | ||
| 81 | + BR_PROPERTY(int, bins, 8) | ||
| 82 | + BR_PROPERTY(bool, split, false) | ||
| 83 | + | ||
| 84 | + void project(const Template &src, Template &dst) const | ||
| 85 | + { | ||
| 86 | + src.m().convertTo(dst, bins > 256 ? CV_16U : CV_8U, bins/(max-min)); | ||
| 87 | + if (!split) return; | ||
| 88 | + | ||
| 89 | + Mat input = dst; | ||
| 90 | + QList<Mat> outputs; outputs.reserve(bins); | ||
| 91 | + for (int i=0; i<bins; i++) | ||
| 92 | + outputs.append(input == i); | ||
| 93 | + dst.clear(); dst.append(outputs); | ||
| 94 | + } | ||
| 95 | +}; | ||
| 96 | + | ||
| 97 | +BR_REGISTER(Transform, BinTransform) | ||
| 98 | + | ||
| 99 | +/*! | ||
| 100 | + * \ingroup transforms | ||
| 69 | * \brief Converts each element to its rank-ordered value. | 101 | * \brief Converts each element to its rank-ordered value. |
| 70 | * \author Josh Klontz \cite jklontz | 102 | * \author Josh Klontz \cite jklontz |
| 71 | */ | 103 | */ |
| @@ -174,7 +206,7 @@ class VarianceChangeDetectorTransform : public UntrainableTransform | @@ -174,7 +206,7 @@ class VarianceChangeDetectorTransform : public UntrainableTransform | ||
| 174 | int *buffer = new int[bins]; | 206 | int *buffer = new int[bins]; |
| 175 | 207 | ||
| 176 | float bestRatio = -std::numeric_limits<float>::max(); | 208 | float bestRatio = -std::numeric_limits<float>::max(); |
| 177 | - QRect bestROI; | 209 | + QRectF bestRect; |
| 178 | 210 | ||
| 179 | const int rows = m.rows; | 211 | const int rows = m.rows; |
| 180 | const int cols = m.cols/bins; | 212 | const int cols = m.cols/bins; |
| @@ -202,7 +234,7 @@ class VarianceChangeDetectorTransform : public UntrainableTransform | @@ -202,7 +234,7 @@ class VarianceChangeDetectorTransform : public UntrainableTransform | ||
| 202 | 234 | ||
| 203 | if (ratio > bestRatio) { | 235 | if (ratio > bestRatio) { |
| 204 | bestRatio = ratio; | 236 | bestRatio = ratio; |
| 205 | - bestROI = QRect(j*radius, i*radius, scale*radius, scale*radius); | 237 | + bestRect = QRect(j*radius, i*radius, scale*radius, scale*radius); |
| 206 | } | 238 | } |
| 207 | } | 239 | } |
| 208 | } | 240 | } |
| @@ -210,7 +242,7 @@ class VarianceChangeDetectorTransform : public UntrainableTransform | @@ -210,7 +242,7 @@ class VarianceChangeDetectorTransform : public UntrainableTransform | ||
| 210 | } | 242 | } |
| 211 | 243 | ||
| 212 | delete[] buffer; | 244 | delete[] buffer; |
| 213 | - dst.file.appendROI(bestROI); | 245 | + dst.file.appendRect(bestRect); |
| 214 | dst.file.setLabel(bestRatio); | 246 | dst.file.setLabel(bestRatio); |
| 215 | } | 247 | } |
| 216 | }; | 248 | }; |
sdk/plugins/integral.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | +#include <openbr_plugin.h> | ||
| 3 | + | ||
| 4 | +namespace br | ||
| 5 | +{ | ||
| 6 | + | ||
| 7 | +/*! | ||
| 8 | + * \ingroup transforms | ||
| 9 | + * \brief Computes integral image. | ||
| 10 | + * \author Josh Klontz \cite jklontz | ||
| 11 | + */ | ||
| 12 | +class IntegralTransform : public UntrainableTransform | ||
| 13 | +{ | ||
| 14 | + Q_OBJECT | ||
| 15 | + | ||
| 16 | + void project(const Template &src, Template &dst) const | ||
| 17 | + { | ||
| 18 | + cv::integral(src, dst); | ||
| 19 | + } | ||
| 20 | +}; | ||
| 21 | + | ||
| 22 | +BR_REGISTER(Transform, IntegralTransform) | ||
| 23 | + | ||
| 24 | +/*! | ||
| 25 | + * \ingroup transforms | ||
| 26 | + * \brief Computes magnitude and/or angle of image. | ||
| 27 | + * \author Josh Klontz \cite jklontz | ||
| 28 | + */ | ||
| 29 | +class GradientTransform : public UntrainableTransform | ||
| 30 | +{ | ||
| 31 | + Q_OBJECT | ||
| 32 | + Q_ENUMS(Channel) | ||
| 33 | + Q_PROPERTY(Channel channel READ get_channel WRITE set_channel RESET reset_channel STORED false) | ||
| 34 | + | ||
| 35 | +public: | ||
| 36 | + enum Channel { Magnitude, Angle, MagnitudeAndAngle }; | ||
| 37 | + | ||
| 38 | +private: | ||
| 39 | + BR_PROPERTY(Channel, channel, Angle) | ||
| 40 | + | ||
| 41 | + void project(const Template &src, Template &dst) const | ||
| 42 | + { | ||
| 43 | + if (src.m().type() != CV_8UC1) qFatal("Requires CV_8UC1 input."); | ||
| 44 | + cv::Mat dx, dy, magnitude, angle; | ||
| 45 | + cv::Sobel(src, dx, CV_32F, 1, 0); | ||
| 46 | + cv::Sobel(src, dy, CV_32F, 0, 1); | ||
| 47 | + cv::cartToPolar(dx, dy, magnitude, angle, true); | ||
| 48 | + if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) | ||
| 49 | + dst.append(magnitude); | ||
| 50 | + if ((channel == Angle) || (channel == MagnitudeAndAngle)) | ||
| 51 | + dst.append(angle); | ||
| 52 | + } | ||
| 53 | +}; | ||
| 54 | + | ||
| 55 | +BR_REGISTER(Transform, GradientTransform) | ||
| 56 | + | ||
| 57 | +} // namespace br | ||
| 58 | + | ||
| 59 | +#include "integral.moc" |
sdk/plugins/keypoint.cpp
| @@ -54,13 +54,13 @@ class KeyPointDetectorTransform : public UntrainableTransform | @@ -54,13 +54,13 @@ class KeyPointDetectorTransform : public UntrainableTransform | ||
| 54 | featureDetector->detect(src, keyPoints); | 54 | featureDetector->detect(src, keyPoints); |
| 55 | } catch (...) { | 55 | } catch (...) { |
| 56 | qWarning("Key point detection failed for file %s", qPrintable(src.file.name)); | 56 | qWarning("Key point detection failed for file %s", qPrintable(src.file.name)); |
| 57 | - dst.file.setBool("FTE"); | 57 | + dst.file.set("FTE", true); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | - QList<Rect> ROIs; | 60 | + QList<Rect> rects; |
| 61 | foreach (const KeyPoint &keyPoint, keyPoints) | 61 | foreach (const KeyPoint &keyPoint, keyPoints) |
| 62 | - ROIs.append(Rect(keyPoint.pt.x, keyPoint.pt.y, keyPoint.size, keyPoint.size)); | ||
| 63 | - dst.file.setROIs(OpenCVUtils::fromRects(ROIs)); | 62 | + rects.append(Rect(keyPoint.pt.x, keyPoint.pt.y, keyPoint.size, keyPoint.size)); |
| 63 | + dst.file.setRects(OpenCVUtils::fromRects(rects)); | ||
| 64 | } | 64 | } |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| @@ -92,10 +92,10 @@ class KeyPointDescriptorTransform : public UntrainableTransform | @@ -92,10 +92,10 @@ class KeyPointDescriptorTransform : public UntrainableTransform | ||
| 92 | { | 92 | { |
| 93 | std::vector<KeyPoint> keyPoints; | 93 | std::vector<KeyPoint> keyPoints; |
| 94 | if (size == -1) { | 94 | if (size == -1) { |
| 95 | - foreach (const QRectF &ROI, src.file.ROIs()) | 95 | + foreach (const QRectF &ROI, src.file.rects()) |
| 96 | keyPoints.push_back(KeyPoint(ROI.x(), ROI.y(), (ROI.width() + ROI.height())/2)); | 96 | keyPoints.push_back(KeyPoint(ROI.x(), ROI.y(), (ROI.width() + ROI.height())/2)); |
| 97 | } else { | 97 | } else { |
| 98 | - foreach (const QPointF &landmark, src.file.landmarks()) | 98 | + foreach (const QPointF &landmark, src.file.points()) |
| 99 | keyPoints.push_back(KeyPoint(landmark.x(), landmark.y(), size)); | 99 | keyPoints.push_back(KeyPoint(landmark.x(), landmark.y(), size)); |
| 100 | } | 100 | } |
| 101 | descriptorExtractor->compute(src, keyPoints, dst); | 101 | descriptorExtractor->compute(src, keyPoints, dst); |
| @@ -166,7 +166,7 @@ class SIFTDescriptorTransform : public UntrainableTransform | @@ -166,7 +166,7 @@ class SIFTDescriptorTransform : public UntrainableTransform | ||
| 166 | void project(const Template &src, Template &dst) const | 166 | void project(const Template &src, Template &dst) const |
| 167 | { | 167 | { |
| 168 | std::vector<KeyPoint> keyPoints; | 168 | std::vector<KeyPoint> keyPoints; |
| 169 | - foreach (const QPointF &val, src.file.landmarks()) | 169 | + foreach (const QPointF &val, src.file.points()) |
| 170 | keyPoints.push_back(KeyPoint(val.x(), val.y(), size)); | 170 | keyPoints.push_back(KeyPoint(val.x(), val.y(), size)); |
| 171 | 171 | ||
| 172 | Mat m; | 172 | Mat m; |
| @@ -200,7 +200,7 @@ class GridTransform : public UntrainableTransform | @@ -200,7 +200,7 @@ class GridTransform : public UntrainableTransform | ||
| 200 | for (float j=column_step/2; j<src.m().cols; j+=column_step) | 200 | for (float j=column_step/2; j<src.m().cols; j+=column_step) |
| 201 | landmarks.append(QPointF(i,j)); | 201 | landmarks.append(QPointF(i,j)); |
| 202 | dst = src; | 202 | dst = src; |
| 203 | - dst.file.setLandmarks(landmarks); | 203 | + dst.file.setPoints(landmarks); |
| 204 | } | 204 | } |
| 205 | }; | 205 | }; |
| 206 | 206 |
sdk/plugins/meta.cpp
| @@ -31,24 +31,24 @@ static TemplateList Expanded(const TemplateList &templates) | @@ -31,24 +31,24 @@ static TemplateList Expanded(const TemplateList &templates) | ||
| 31 | TemplateList expanded; | 31 | TemplateList expanded; |
| 32 | foreach (const Template &t, templates) { | 32 | foreach (const Template &t, templates) { |
| 33 | if (t.isEmpty()) { | 33 | if (t.isEmpty()) { |
| 34 | - if (!t.file.getBool("enrollAll")) | 34 | + if (!t.file.get<bool>("enrollAll", false)) |
| 35 | expanded.append(t); | 35 | expanded.append(t); |
| 36 | continue; | 36 | continue; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | - const bool fte = t.file.getBool("FTE"); | ||
| 40 | - QList<QPointF> landmarks = t.file.landmarks(); | ||
| 41 | - QList<QRectF> ROIs = t.file.ROIs(); | ||
| 42 | - if (landmarks.size() % t.size() != 0) qFatal("Uneven landmark count."); | ||
| 43 | - if (ROIs.size() % t.size() != 0) qFatal("Uneven ROI count."); | ||
| 44 | - const int landmarkStep = landmarks.size() / t.size(); | ||
| 45 | - const int ROIStep = ROIs.size() / t.size(); | 39 | + const bool fte = t.file.get<bool>("FTE", false); |
| 40 | + QList<QPointF> points = t.file.points(); | ||
| 41 | + QList<QRectF> rects = t.file.rects(); | ||
| 42 | + if (points.size() % t.size() != 0) qFatal("Uneven point count."); | ||
| 43 | + if (rects.size() % t.size() != 0) qFatal("Uneven rect count."); | ||
| 44 | + const int pointStep = points.size() / t.size(); | ||
| 45 | + const int rectStep = rects.size() / t.size(); | ||
| 46 | 46 | ||
| 47 | for (int i=0; i<t.size(); i++) { | 47 | for (int i=0; i<t.size(); i++) { |
| 48 | - if (!fte || !t.file.getBool("enrollAll")) { | 48 | + if (!fte || !t.file.get<bool>("enrollAll", false)) { |
| 49 | expanded.append(Template(t.file, t[i])); | 49 | expanded.append(Template(t.file, t[i])); |
| 50 | - expanded.last().file.setROIs(ROIs.mid(i*ROIStep, ROIStep)); | ||
| 51 | - expanded.last().file.setLandmarks(landmarks.mid(i*landmarkStep, landmarkStep)); | 50 | + expanded.last().file.setRects(rects.mid(i*rectStep, rectStep)); |
| 51 | + expanded.last().file.setPoints(points.mid(i*pointStep, pointStep)); | ||
| 52 | } | 52 | } |
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| @@ -86,6 +86,111 @@ static void incrementStep() | @@ -86,6 +86,111 @@ static void incrementStep() | ||
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /*! | 88 | /*! |
| 89 | + * \brief Use Expanded after basic calls that take a template list, used to implement ExpandTransform | ||
| 90 | + */ | ||
| 91 | +class ExpandDecorator : public Transform | ||
| 92 | +{ | ||
| 93 | + Q_OBJECT | ||
| 94 | + | ||
| 95 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform) | ||
| 96 | + BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 97 | + | ||
| 98 | +public: | ||
| 99 | + ExpandDecorator(Transform * input) | ||
| 100 | + { | ||
| 101 | + transform = input; | ||
| 102 | + transform->setParent(this); | ||
| 103 | + file = transform->file; | ||
| 104 | + setObjectName(transform->objectName()); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + void train(const TemplateList &data) | ||
| 108 | + { | ||
| 109 | + transform->train(data); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + void project(const Template &src, Template &dst) const | ||
| 113 | + { | ||
| 114 | + transform->project(src, dst); | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + void project(const TemplateList &src, TemplateList &dst) const | ||
| 118 | + { | ||
| 119 | + transform->project(src, dst); | ||
| 120 | + dst = Expanded(dst); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + | ||
| 124 | + void projectUpdate(const Template &src, Template &dst) | ||
| 125 | + { | ||
| 126 | + transform->projectUpdate(src, dst); | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + void projectUpdate(const TemplateList & src, TemplateList & dst) | ||
| 130 | + { | ||
| 131 | + transform->projectUpdate(src, dst); | ||
| 132 | + dst = Expanded(dst); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + bool timeVarying() const | ||
| 136 | + { | ||
| 137 | + return transform->timeVarying(); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + void finalize(TemplateList & output) | ||
| 141 | + { | ||
| 142 | + transform->finalize(output); | ||
| 143 | + output = Expanded(output); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | +}; | ||
| 147 | + | ||
| 148 | +/*! | ||
| 149 | + * \brief A MetaTransform that aggregates some sub-transforms | ||
| 150 | + */ | ||
| 151 | +class BR_EXPORT CompositeTransform : public TimeVaryingTransform | ||
| 152 | +{ | ||
| 153 | + Q_OBJECT | ||
| 154 | + | ||
| 155 | +public: | ||
| 156 | + Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 157 | + BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 158 | + | ||
| 159 | + virtual void project(const Template &src, Template &dst) const | ||
| 160 | + { | ||
| 161 | + if (timeVarying()) qFatal("No const project defined for time-varying transform"); | ||
| 162 | + _project(src, dst); | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + virtual void project(const TemplateList &src, TemplateList &dst) const | ||
| 166 | + { | ||
| 167 | + if (timeVarying()) qFatal("No const project defined for time-varying transform"); | ||
| 168 | + _project(src, dst); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + bool timeVarying() const { return isTimeVarying; } | ||
| 172 | + | ||
| 173 | + void init() | ||
| 174 | + { | ||
| 175 | + isTimeVarying = false; | ||
| 176 | + foreach (const br::Transform *transform, transforms) { | ||
| 177 | + if (transform->timeVarying()) { | ||
| 178 | + isTimeVarying = true; | ||
| 179 | + break; | ||
| 180 | + } | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | +protected: | ||
| 185 | + bool isTimeVarying; | ||
| 186 | + | ||
| 187 | + virtual void _project(const Template & src, Template & dst) const = 0; | ||
| 188 | + virtual void _project(const TemplateList & src, TemplateList & dst) const = 0; | ||
| 189 | + | ||
| 190 | + CompositeTransform() : TimeVaryingTransform(false) {} | ||
| 191 | +}; | ||
| 192 | + | ||
| 193 | +/*! | ||
| 89 | * \ingroup Transforms | 194 | * \ingroup Transforms |
| 90 | * \brief Transforms in series. | 195 | * \brief Transforms in series. |
| 91 | * \author Josh Klontz \cite jklontz | 196 | * \author Josh Klontz \cite jklontz |
| @@ -95,11 +200,9 @@ static void incrementStep() | @@ -95,11 +200,9 @@ static void incrementStep() | ||
| 95 | * \see ExpandTransform | 200 | * \see ExpandTransform |
| 96 | * \see ForkTransform | 201 | * \see ForkTransform |
| 97 | */ | 202 | */ |
| 98 | -class PipeTransform : public MetaTransform | 203 | +class PipeTransform : public CompositeTransform |
| 99 | { | 204 | { |
| 100 | Q_OBJECT | 205 | Q_OBJECT |
| 101 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 102 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 103 | 206 | ||
| 104 | void train(const TemplateList &data) | 207 | void train(const TemplateList &data) |
| 105 | { | 208 | { |
| @@ -115,21 +218,78 @@ class PipeTransform : public MetaTransform | @@ -115,21 +218,78 @@ class PipeTransform : public MetaTransform | ||
| 115 | releaseStep(); | 218 | releaseStep(); |
| 116 | } | 219 | } |
| 117 | 220 | ||
| 118 | - void project(const Template &src, Template &dst) const | 221 | + void backProject(const Template &dst, Template &src) const |
| 222 | + { | ||
| 223 | + // Backprojecting a time-varying transform is probably not going to work. | ||
| 224 | + if (timeVarying()) qFatal("No backProject defined for time-varying transform"); | ||
| 225 | + | ||
| 226 | + src = dst; | ||
| 227 | + // Reverse order in which transforms are processed | ||
| 228 | + int length = transforms.length(); | ||
| 229 | + for (int i=length-1; i>=0; i--) { | ||
| 230 | + Transform *f = transforms.at(i); | ||
| 231 | + try { | ||
| 232 | + src >> *f; | ||
| 233 | + } catch (...) { | ||
| 234 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(dst.file.flat()), qPrintable(f->objectName())); | ||
| 235 | + src = Template(src.file); | ||
| 236 | + src.file.set("FTE", true); | ||
| 237 | + } | ||
| 238 | + } | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + void projectUpdate(const Template &src, Template &dst) | ||
| 119 | { | 242 | { |
| 120 | dst = src; | 243 | dst = src; |
| 121 | - foreach (const Transform *f, transforms) { | 244 | + foreach (Transform *f, transforms) { |
| 122 | try { | 245 | try { |
| 123 | - dst >> *f; | 246 | + f->projectUpdate(dst); |
| 124 | } catch (...) { | 247 | } catch (...) { |
| 125 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | 248 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); |
| 126 | dst = Template(src.file); | 249 | dst = Template(src.file); |
| 127 | - dst.file.setBool("FTE"); | 250 | + dst.file.set("FTE", true); |
| 128 | } | 251 | } |
| 129 | } | 252 | } |
| 130 | } | 253 | } |
| 131 | 254 | ||
| 132 | - void project(const TemplateList &src, TemplateList &dst) const | 255 | + // For time varying transforms, parallel execution over individual templates |
| 256 | + // won't work. | ||
| 257 | + void projectUpdate(const TemplateList & src, TemplateList & dst) | ||
| 258 | + { | ||
| 259 | + dst = src; | ||
| 260 | + foreach (Transform *f, transforms) | ||
| 261 | + { | ||
| 262 | + f->projectUpdate(dst); | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + virtual void finalize(TemplateList & output) | ||
| 267 | + { | ||
| 268 | + output.clear(); | ||
| 269 | + // For each transform, | ||
| 270 | + for (int i = 0; i < transforms.size(); i++) | ||
| 271 | + { | ||
| 272 | + | ||
| 273 | + // Collect any final templates | ||
| 274 | + TemplateList last_set; | ||
| 275 | + transforms[i]->finalize(last_set); | ||
| 276 | + if (last_set.empty()) | ||
| 277 | + continue; | ||
| 278 | + // Push any templates received through the remaining transforms in the sequence | ||
| 279 | + for (int j = (i+1); j < transforms.size();j++) | ||
| 280 | + { | ||
| 281 | + transforms[j]->projectUpdate(last_set); | ||
| 282 | + } | ||
| 283 | + // append the result to the output set | ||
| 284 | + output.append(last_set); | ||
| 285 | + } | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | + | ||
| 289 | +protected: | ||
| 290 | + // Template list project -- process templates in parallel through Transform::project | ||
| 291 | + // or if parallelism is disabled, handle them sequentially | ||
| 292 | + void _project(const TemplateList &src, TemplateList &dst) const | ||
| 133 | { | 293 | { |
| 134 | if (Globals->parallelism < 0) { | 294 | if (Globals->parallelism < 0) { |
| 135 | dst = src; | 295 | dst = src; |
| @@ -140,22 +300,20 @@ class PipeTransform : public MetaTransform | @@ -140,22 +300,20 @@ class PipeTransform : public MetaTransform | ||
| 140 | } | 300 | } |
| 141 | } | 301 | } |
| 142 | 302 | ||
| 143 | - void backProject(const Template &dst, Template &src) const | ||
| 144 | - { | ||
| 145 | - src = dst; | ||
| 146 | - // Reverse order in which transforms are processed | ||
| 147 | - int length = transforms.length(); | ||
| 148 | - for (int i=length-1; i>=0; i--) { | ||
| 149 | - Transform *f = transforms.at(i); | ||
| 150 | - try { | ||
| 151 | - src >> *f; | ||
| 152 | - } catch (...) { | ||
| 153 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(dst.file.flat()), qPrintable(f->objectName())); | ||
| 154 | - src = Template(src.file); | ||
| 155 | - src.file.setBool("FTE"); | ||
| 156 | - } | ||
| 157 | - } | ||
| 158 | - } | 303 | + // Single template const project, pass the template through each sub-transform, one after the other |
| 304 | + virtual void _project(const Template & src, Template & dst) const | ||
| 305 | + { | ||
| 306 | + dst = src; | ||
| 307 | + foreach (const Transform *f, transforms) { | ||
| 308 | + try { | ||
| 309 | + dst >> *f; | ||
| 310 | + } catch (...) { | ||
| 311 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 312 | + dst = Template(src.file); | ||
| 313 | + dst.file.set("FTE", true); | ||
| 314 | + } | ||
| 315 | + } | ||
| 316 | + } | ||
| 159 | }; | 317 | }; |
| 160 | 318 | ||
| 161 | BR_REGISTER(Transform, PipeTransform) | 319 | BR_REGISTER(Transform, PipeTransform) |
| @@ -170,64 +328,31 @@ BR_REGISTER(Transform, PipeTransform) | @@ -170,64 +328,31 @@ BR_REGISTER(Transform, PipeTransform) | ||
| 170 | * | 328 | * |
| 171 | * \see PipeTransform | 329 | * \see PipeTransform |
| 172 | */ | 330 | */ |
| 173 | -class ExpandTransform : public MetaTransform | 331 | +class ExpandTransform : public PipeTransform |
| 174 | { | 332 | { |
| 175 | Q_OBJECT | 333 | Q_OBJECT |
| 176 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 177 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 178 | 334 | ||
| 179 | - void train(const TemplateList &data) | 335 | + void init() |
| 180 | { | 336 | { |
| 181 | - acquireStep(); | ||
| 182 | - | ||
| 183 | - TemplateList copy(data); | ||
| 184 | - for (int i=0; i<transforms.size(); i++) { | ||
| 185 | - transforms[i]->train(copy); | ||
| 186 | - copy >> *transforms[i]; | ||
| 187 | - copy = Expanded(copy); | ||
| 188 | - incrementStep(); | 337 | + for (int i = 0; i < transforms.size(); i++) |
| 338 | + { | ||
| 339 | + transforms[i] = new ExpandDecorator(transforms[i]); | ||
| 189 | } | 340 | } |
| 190 | - | ||
| 191 | - releaseStep(); | 341 | + // Need to call this to set up timevariance correctly, and it won't |
| 342 | + // be called automatically | ||
| 343 | + CompositeTransform::init(); | ||
| 192 | } | 344 | } |
| 193 | 345 | ||
| 194 | - void project(const Template &src, Template &dst) const | ||
| 195 | - { | ||
| 196 | - dst = src; | ||
| 197 | - foreach (const Transform *f, transforms) { | ||
| 198 | - try { | ||
| 199 | - dst >> *f; | ||
| 200 | - } catch (...) { | ||
| 201 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 202 | - dst = Template(src.file); | ||
| 203 | - dst.file.setBool("FTE"); | ||
| 204 | - } | ||
| 205 | - } | ||
| 206 | - } | 346 | +protected: |
| 207 | 347 | ||
| 208 | - void project(const TemplateList &src, TemplateList &dst) const | 348 | + // Template list project -- project through transforms sequentially, |
| 349 | + // then expand the results, can't use Transform::Project(templateList) since | ||
| 350 | + // we need to expand between tranforms, so actually do need to overload this method | ||
| 351 | + void _project(const TemplateList &src, TemplateList &dst) const | ||
| 209 | { | 352 | { |
| 210 | dst = src; | 353 | dst = src; |
| 211 | for (int i=0; i<transforms.size(); i++) { | 354 | for (int i=0; i<transforms.size(); i++) { |
| 212 | dst >> *transforms[i]; | 355 | dst >> *transforms[i]; |
| 213 | - dst = Expanded(dst); | ||
| 214 | - } | ||
| 215 | - } | ||
| 216 | - | ||
| 217 | - void backProject(const Template &dst, Template &src) const | ||
| 218 | - { | ||
| 219 | - src = dst; | ||
| 220 | - // Reverse order in which transforms are processed | ||
| 221 | - int length = transforms.length(); | ||
| 222 | - for (int i=length-1; i>=0; i--) { | ||
| 223 | - Transform *f = transforms.at(i); | ||
| 224 | - try { | ||
| 225 | - src >> *f; | ||
| 226 | - } catch (...) { | ||
| 227 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(dst.file.flat()), qPrintable(f->objectName())); | ||
| 228 | - src = Template(src.file); | ||
| 229 | - src.file.setBool("FTE"); | ||
| 230 | - } | ||
| 231 | } | 356 | } |
| 232 | } | 357 | } |
| 233 | }; | 358 | }; |
| @@ -243,11 +368,9 @@ BR_REGISTER(Transform, ExpandTransform) | @@ -243,11 +368,9 @@ BR_REGISTER(Transform, ExpandTransform) | ||
| 243 | * | 368 | * |
| 244 | * \see PipeTransform | 369 | * \see PipeTransform |
| 245 | */ | 370 | */ |
| 246 | -class ForkTransform : public MetaTransform | 371 | +class ForkTransform : public CompositeTransform |
| 247 | { | 372 | { |
| 248 | Q_OBJECT | 373 | Q_OBJECT |
| 249 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 250 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 251 | 374 | ||
| 252 | void train(const TemplateList &data) | 375 | void train(const TemplateList &data) |
| 253 | { | 376 | { |
| @@ -260,7 +383,69 @@ class ForkTransform : public MetaTransform | @@ -260,7 +383,69 @@ class ForkTransform : public MetaTransform | ||
| 260 | if (threaded) Globals->trackFutures(futures); | 383 | if (threaded) Globals->trackFutures(futures); |
| 261 | } | 384 | } |
| 262 | 385 | ||
| 263 | - void project(const Template &src, Template &dst) const | 386 | + void backProject(const Template &dst, Template &src) const {Transform::backProject(dst, src);} |
| 387 | + | ||
| 388 | + // same as _project, but calls projectUpdate on sub-transforms | ||
| 389 | + void projectupdate(const Template & src, Template & dst) | ||
| 390 | + { | ||
| 391 | + foreach (Transform *f, transforms) { | ||
| 392 | + try { | ||
| 393 | + Template res; | ||
| 394 | + f->projectUpdate(src, res); | ||
| 395 | + dst.merge(res); | ||
| 396 | + } catch (...) { | ||
| 397 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 398 | + dst = Template(src.file); | ||
| 399 | + dst.file.set("FTE", true); | ||
| 400 | + } | ||
| 401 | + } | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + void projectUpdate(const TemplateList & src, TemplateList & dst) | ||
| 405 | + { | ||
| 406 | + dst = src; | ||
| 407 | + dst.reserve(src.size()); | ||
| 408 | + for (int i=0; i<src.size(); i++) dst.append(Template()); | ||
| 409 | + foreach (Transform *f, transforms) { | ||
| 410 | + TemplateList m; | ||
| 411 | + f->projectUpdate(src, m); | ||
| 412 | + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); | ||
| 413 | + for (int i=0; i<src.size(); i++) dst[i].append(m[i]); | ||
| 414 | + } | ||
| 415 | + } | ||
| 416 | + | ||
| 417 | + // this is probably going to go bad, fork transform probably won't work well in a variable | ||
| 418 | + // input/output scenario | ||
| 419 | + virtual void finalize(TemplateList & output) | ||
| 420 | + { | ||
| 421 | + output.clear(); | ||
| 422 | + // For each transform, | ||
| 423 | + for (int i = 0; i < transforms.size(); i++) | ||
| 424 | + { | ||
| 425 | + // Collect any final templates | ||
| 426 | + TemplateList last_set; | ||
| 427 | + transforms[i]->finalize(last_set); | ||
| 428 | + if (last_set.empty()) | ||
| 429 | + continue; | ||
| 430 | + | ||
| 431 | + if (output.empty()) output = last_set; | ||
| 432 | + else | ||
| 433 | + { | ||
| 434 | + // is the number of templates received from this transform consistent with the number | ||
| 435 | + // received previously? If not we can't do anything coherent here. | ||
| 436 | + if (last_set.size() != output.size()) | ||
| 437 | + qFatal("mismatched template list sizes in ForkTransform"); | ||
| 438 | + for (int j = 0; j < output.size(); j++) { | ||
| 439 | + output[j].append(last_set[j]); | ||
| 440 | + } | ||
| 441 | + } | ||
| 442 | + } | ||
| 443 | + } | ||
| 444 | + | ||
| 445 | +protected: | ||
| 446 | + | ||
| 447 | + // Apply each transform to src, concatenate the results | ||
| 448 | + void _project(const Template &src, Template &dst) const | ||
| 264 | { | 449 | { |
| 265 | foreach (const Transform *f, transforms) { | 450 | foreach (const Transform *f, transforms) { |
| 266 | try { | 451 | try { |
| @@ -268,12 +453,12 @@ class ForkTransform : public MetaTransform | @@ -268,12 +453,12 @@ class ForkTransform : public MetaTransform | ||
| 268 | } catch (...) { | 453 | } catch (...) { |
| 269 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | 454 | qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); |
| 270 | dst = Template(src.file); | 455 | dst = Template(src.file); |
| 271 | - dst.file.setBool("FTE"); | 456 | + dst.file.set("FTE", true); |
| 272 | } | 457 | } |
| 273 | } | 458 | } |
| 274 | } | 459 | } |
| 275 | 460 | ||
| 276 | - void project(const TemplateList &src, TemplateList &dst) const | 461 | + void _project(const TemplateList &src, TemplateList &dst) const |
| 277 | { | 462 | { |
| 278 | if (Globals->parallelism < 0) { | 463 | if (Globals->parallelism < 0) { |
| 279 | dst.reserve(src.size()); | 464 | dst.reserve(src.size()); |
| @@ -288,6 +473,7 @@ class ForkTransform : public MetaTransform | @@ -288,6 +473,7 @@ class ForkTransform : public MetaTransform | ||
| 288 | Transform::project(src, dst); | 473 | Transform::project(src, dst); |
| 289 | } | 474 | } |
| 290 | } | 475 | } |
| 476 | + | ||
| 291 | }; | 477 | }; |
| 292 | 478 | ||
| 293 | BR_REGISTER(Transform, ForkTransform) | 479 | BR_REGISTER(Transform, ForkTransform) |
| @@ -423,7 +609,7 @@ private: | @@ -423,7 +609,7 @@ private: | ||
| 423 | const QString file = getFileName(); | 609 | const QString file = getFileName(); |
| 424 | if (file.isEmpty()) return false; | 610 | if (file.isEmpty()) return false; |
| 425 | 611 | ||
| 426 | - qDebug("Loading %s", qPrintable(baseName)); | 612 | + if (Globals->verbose) qDebug("Loading %s", qPrintable(baseName)); |
| 427 | QByteArray data; | 613 | QByteArray data; |
| 428 | QtUtils::readFile(file, data, true); | 614 | QtUtils::readFile(file, data, true); |
| 429 | QDataStream stream(&data, QFile::ReadOnly); | 615 | QDataStream stream(&data, QFile::ReadOnly); |
| @@ -462,7 +648,7 @@ class FTETransform : public Transform | @@ -462,7 +648,7 @@ class FTETransform : public Transform | ||
| 462 | foreach (const Template &t, projectedData) { | 648 | foreach (const Template &t, projectedData) { |
| 463 | if (!t.file.contains(transform->objectName())) | 649 | if (!t.file.contains(transform->objectName())) |
| 464 | qFatal("Matrix metadata missing key %s.", qPrintable(transform->objectName())); | 650 | qFatal("Matrix metadata missing key %s.", qPrintable(transform->objectName())); |
| 465 | - vals.append(t.file.getFloat(transform->objectName())); | 651 | + vals.append(t.file.get<float>(transform->objectName())); |
| 466 | } | 652 | } |
| 467 | float q1, q3; | 653 | float q1, q3; |
| 468 | Common::Median(vals, &q1, &q3); | 654 | Common::Median(vals, &q1, &q3); |
| @@ -474,11 +660,11 @@ class FTETransform : public Transform | @@ -474,11 +660,11 @@ class FTETransform : public Transform | ||
| 474 | { | 660 | { |
| 475 | Template projectedSrc; | 661 | Template projectedSrc; |
| 476 | transform->project(src, projectedSrc); | 662 | transform->project(src, projectedSrc); |
| 477 | - const float val = projectedSrc.file.getFloat(transform->objectName()); | 663 | + const float val = projectedSrc.file.get<float>(transform->objectName()); |
| 478 | 664 | ||
| 479 | dst = src; | 665 | dst = src; |
| 480 | - dst.file.insert(transform->objectName(), val); | ||
| 481 | - dst.file.insert("FTE", (val < min) || (val > max)); | 666 | + dst.file.set(transform->objectName(), val); |
| 667 | + dst.file.set("FTE", (val < min) || (val > max)); | ||
| 482 | } | 668 | } |
| 483 | }; | 669 | }; |
| 484 | 670 |
sdk/plugins/misc.cpp
| @@ -44,7 +44,7 @@ class OpenTransform : public UntrainableMetaTransform | @@ -44,7 +44,7 @@ class OpenTransform : public UntrainableMetaTransform | ||
| 44 | dst.append(t); | 44 | dst.append(t); |
| 45 | dst.file.append(t.file.localMetadata()); | 45 | dst.file.append(t.file.localMetadata()); |
| 46 | } | 46 | } |
| 47 | - dst.file.insert("FTO", dst.isEmpty()); | 47 | + dst.file.set("FTO", dst.isEmpty()); |
| 48 | } | 48 | } |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| @@ -100,16 +100,19 @@ class PrintTransform : public UntrainableMetaTransform | @@ -100,16 +100,19 @@ class PrintTransform : public UntrainableMetaTransform | ||
| 100 | Q_OBJECT | 100 | Q_OBJECT |
| 101 | Q_PROPERTY(bool error READ get_error WRITE set_error RESET reset_error) | 101 | Q_PROPERTY(bool error READ get_error WRITE set_error RESET reset_error) |
| 102 | Q_PROPERTY(bool data READ get_data WRITE set_data RESET reset_data) | 102 | Q_PROPERTY(bool data READ get_data WRITE set_data RESET reset_data) |
| 103 | + Q_PROPERTY(bool nTemplates READ get_data WRITE set_data RESET reset_data) | ||
| 103 | BR_PROPERTY(bool, error, true) | 104 | BR_PROPERTY(bool, error, true) |
| 104 | BR_PROPERTY(bool, data, false) | 105 | BR_PROPERTY(bool, data, false) |
| 106 | + BR_PROPERTY(bool, size, false) | ||
| 105 | 107 | ||
| 106 | void project(const Template &src, Template &dst) const | 108 | void project(const Template &src, Template &dst) const |
| 107 | { | 109 | { |
| 108 | dst = src; | 110 | dst = src; |
| 109 | const QString nameString = src.file.flat(); | 111 | const QString nameString = src.file.flat(); |
| 110 | const QString dataString = data ? OpenCVUtils::matrixToString(src)+"\n" : QString(); | 112 | const QString dataString = data ? OpenCVUtils::matrixToString(src)+"\n" : QString(); |
| 111 | - if (error) qDebug("%s\n%s", qPrintable(nameString), qPrintable(dataString)); | ||
| 112 | - else printf("%s\n%s", qPrintable(nameString), qPrintable(dataString)); | 113 | + const QString nTemplates = size ? QString::number(src.size()) : QString(); |
| 114 | + if (error) qDebug("%s\n%s\n%s", qPrintable(nameString), qPrintable(dataString), qPrintable(nTemplates)); | ||
| 115 | + else printf("%s\n%s\n%s", qPrintable(nameString), qPrintable(dataString), qPrintable(nTemplates)); | ||
| 113 | } | 116 | } |
| 114 | }; | 117 | }; |
| 115 | 118 | ||
| @@ -282,7 +285,7 @@ class RenameTransform : public UntrainableMetaTransform | @@ -282,7 +285,7 @@ class RenameTransform : public UntrainableMetaTransform | ||
| 282 | { | 285 | { |
| 283 | dst = src; | 286 | dst = src; |
| 284 | if (dst.file.localKeys().contains(find)) { | 287 | if (dst.file.localKeys().contains(find)) { |
| 285 | - dst.file.insert(replace, dst.file.get(find)); | 288 | + dst.file.set(replace, dst.file.value(find)); |
| 286 | dst.file.remove(find); | 289 | dst.file.remove(find); |
| 287 | } | 290 | } |
| 288 | } | 291 | } |
| @@ -308,7 +311,7 @@ class RenameFirstTransform : public UntrainableMetaTransform | @@ -308,7 +311,7 @@ class RenameFirstTransform : public UntrainableMetaTransform | ||
| 308 | dst = src; | 311 | dst = src; |
| 309 | foreach (const QString &key, find) | 312 | foreach (const QString &key, find) |
| 310 | if (dst.file.localKeys().contains(key)) { | 313 | if (dst.file.localKeys().contains(key)) { |
| 311 | - dst.file.insert(replace, dst.file.get(key)); | 314 | + dst.file.set(replace, dst.file.value(key)); |
| 312 | dst.file.remove(key); | 315 | dst.file.remove(key); |
| 313 | break; | 316 | break; |
| 314 | } | 317 | } |
sdk/plugins/output.cpp
| @@ -106,7 +106,7 @@ class meltOutput : public MatrixOutput | @@ -106,7 +106,7 @@ class meltOutput : public MatrixOutput | ||
| 106 | const bool genuineOnly = file.contains("Genuine") && !file.contains("Impostor"); | 106 | const bool genuineOnly = file.contains("Genuine") && !file.contains("Impostor"); |
| 107 | const bool impostorOnly = file.contains("Impostor") && !file.contains("Genuine"); | 107 | const bool impostorOnly = file.contains("Impostor") && !file.contains("Genuine"); |
| 108 | 108 | ||
| 109 | - QHash<QString,QVariant> args = file.localMetadata(); | 109 | + QMap<QString,QVariant> args = file.localMetadata(); |
| 110 | args.remove("Genuine"); | 110 | args.remove("Genuine"); |
| 111 | args.remove("Impostor"); | 111 | args.remove("Impostor"); |
| 112 | 112 | ||
| @@ -165,9 +165,9 @@ class rrOutput : public MatrixOutput | @@ -165,9 +165,9 @@ class rrOutput : public MatrixOutput | ||
| 165 | ~rrOutput() | 165 | ~rrOutput() |
| 166 | { | 166 | { |
| 167 | if (file.isNull() || targetFiles.isEmpty() || queryFiles.isEmpty()) return; | 167 | if (file.isNull() || targetFiles.isEmpty() || queryFiles.isEmpty()) return; |
| 168 | - const int limit = file.getInt("limit", 20); | ||
| 169 | - const bool byLine = file.getBool("byLine"); | ||
| 170 | - const float threshold = file.getFloat("threshold", -std::numeric_limits<float>::max()); | 168 | + const int limit = file.get<int>("limit", 20); |
| 169 | + const bool byLine = file.get<bool>("byLine", false); | ||
| 170 | + const float threshold = file.get<float>("threshold", -std::numeric_limits<float>::max()); | ||
| 171 | 171 | ||
| 172 | QStringList lines; | 172 | QStringList lines; |
| 173 | 173 | ||
| @@ -279,7 +279,7 @@ class rankOutput : public MatrixOutput | @@ -279,7 +279,7 @@ class rankOutput : public MatrixOutput | ||
| 279 | typedef QPair<float,int> Pair; | 279 | typedef QPair<float,int> Pair; |
| 280 | int rank = 1; | 280 | int rank = 1; |
| 281 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector(data.row(i)), true)) { | 281 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector(data.row(i)), true)) { |
| 282 | - if(targetFiles[pair.second].getString("Label") == queryFiles[i].getString("Label")) { | 282 | + if(targetFiles[pair.second].get<QString>("Label") == queryFiles[i].get<QString>("Label")) { |
| 283 | ranks.append(rank); | 283 | ranks.append(rank); |
| 284 | positions.append(pair.second); | 284 | positions.append(pair.second); |
| 285 | scores.append(pair.first); | 285 | scores.append(pair.first); |
| @@ -347,10 +347,10 @@ class tailOutput : public Output | @@ -347,10 +347,10 @@ class tailOutput : public Output | ||
| 347 | void initialize(const FileList &targetFiles, const FileList &queryFiles) | 347 | void initialize(const FileList &targetFiles, const FileList &queryFiles) |
| 348 | { | 348 | { |
| 349 | Output::initialize(targetFiles, queryFiles); | 349 | Output::initialize(targetFiles, queryFiles); |
| 350 | - threshold = file.getFloat("threshold", -std::numeric_limits<float>::max()); | ||
| 351 | - atLeast = file.getInt("atLeast", 1); | ||
| 352 | - atMost = file.getInt("atMost", std::numeric_limits<int>::max()); | ||
| 353 | - args = file.getBool("args"); | 350 | + threshold = file.get<float>("threshold", -std::numeric_limits<float>::max()); |
| 351 | + atLeast = file.get<int>("atLeast", 1); | ||
| 352 | + atMost = file.get<int>("atMost", std::numeric_limits<int>::max()); | ||
| 353 | + args = file.get<bool>("args", false); | ||
| 354 | lastValue = -std::numeric_limits<float>::max(); | 354 | lastValue = -std::numeric_limits<float>::max(); |
| 355 | } | 355 | } |
| 356 | 356 | ||
| @@ -462,9 +462,9 @@ class histOutput : public Output | @@ -462,9 +462,9 @@ class histOutput : public Output | ||
| 462 | void initialize(const FileList &targetFiles, const FileList &queryFiles) | 462 | void initialize(const FileList &targetFiles, const FileList &queryFiles) |
| 463 | { | 463 | { |
| 464 | Output::initialize(targetFiles, queryFiles); | 464 | Output::initialize(targetFiles, queryFiles); |
| 465 | - min = file.getFloat("min", -5); | ||
| 466 | - max = file.getFloat("max", 5); | ||
| 467 | - step = file.getFloat("step", 0.1); | 465 | + min = file.get<float>("min", -5); |
| 466 | + max = file.get<float>("max", 5); | ||
| 467 | + step = file.get<float>("step", 0.1); | ||
| 468 | bins = QVector<int>((max-min)/step, 0); | 468 | bins = QVector<int>((max-min)/step, 0); |
| 469 | } | 469 | } |
| 470 | 470 |
sdk/plugins/pixel.cpp
| @@ -120,7 +120,7 @@ class PerPixelClassifierTransform : public MetaTransform | @@ -120,7 +120,7 @@ class PerPixelClassifierTransform : public MetaTransform | ||
| 120 | uchar *psrc = src[n].ptr(); | 120 | uchar *psrc = src[n].ptr(); |
| 121 | ptemp[n] = psrc[index]; | 121 | ptemp[n] = psrc[index]; |
| 122 | } | 122 | } |
| 123 | - cv::Mat labelMat = src.file.get("labels").value<cv::Mat>(); | 123 | + cv::Mat labelMat = src.file.value("labels").value<cv::Mat>(); |
| 124 | uchar* plabel = labelMat.ptr(); | 124 | uchar* plabel = labelMat.ptr(); |
| 125 | temp.file.setLabel(plabel[index]); | 125 | temp.file.setLabel(plabel[index]); |
| 126 | 126 |
sdk/plugins/pp5.cpp
| @@ -148,9 +148,9 @@ struct PP5Context | @@ -148,9 +148,9 @@ struct PP5Context | ||
| 148 | return "Unknown"; | 148 | return "Unknown"; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | - static QHash<QString,QVariant> toMetadata(const ppr_face_type &face) | 151 | + static QMap<QString,QVariant> toMetadata(const ppr_face_type &face) |
| 152 | { | 152 | { |
| 153 | - QHash<QString,QVariant> metadata; | 153 | + QMap<QString,QVariant> metadata; |
| 154 | 154 | ||
| 155 | ppr_face_attributes_type face_attributes; | 155 | ppr_face_attributes_type face_attributes; |
| 156 | ppr_get_face_attributes(face, &face_attributes); | 156 | ppr_get_face_attributes(face, &face_attributes); |
| @@ -250,7 +250,7 @@ class PP5Enroll : public UntrainableTransform | @@ -250,7 +250,7 @@ class PP5Enroll : public UntrainableTransform | ||
| 250 | dst.file.append(PP5Context::toMetadata(face)); | 250 | dst.file.append(PP5Context::toMetadata(face)); |
| 251 | dst += m; | 251 | dst += m; |
| 252 | 252 | ||
| 253 | - if (!src.file.getBool("enrollAll")) break; | 253 | + if (!src.file.get<bool>("enrollAll", false)) break; |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | ppr_free_face_list(face_list); | 256 | ppr_free_face_list(face_list); |
| @@ -259,7 +259,7 @@ class PP5Enroll : public UntrainableTransform | @@ -259,7 +259,7 @@ class PP5Enroll : public UntrainableTransform | ||
| 259 | 259 | ||
| 260 | contexts.release(context); | 260 | contexts.release(context); |
| 261 | 261 | ||
| 262 | - if (!src.file.getBool("enrollAll") && dst.isEmpty()) { | 262 | + if (!src.file.get<bool>("enrollAll", false) && dst.isEmpty()) { |
| 263 | if (detectOnly) dst += src; | 263 | if (detectOnly) dst += src; |
| 264 | else dst += cv::Mat(); | 264 | else dst += cv::Mat(); |
| 265 | } | 265 | } |
sdk/plugins/quality.cpp
| @@ -53,8 +53,8 @@ class ImpostorUniquenessMeasureTransform : public Transform | @@ -53,8 +53,8 @@ class ImpostorUniquenessMeasureTransform : public Transform | ||
| 53 | { | 53 | { |
| 54 | dst = src; | 54 | dst = src; |
| 55 | float ium = calculateIUM(src, impostors); | 55 | float ium = calculateIUM(src, impostors); |
| 56 | - dst.file.insert("Impostor_Uniqueness_Measure", ium); | ||
| 57 | - dst.file.insert("Impostor_Uniqueness_Measure_Bin", ium < mean-stddev ? 0 : (ium < mean+stddev ? 1 : 2)); | 56 | + dst.file.set("Impostor_Uniqueness_Measure", ium); |
| 57 | + dst.file.set("Impostor_Uniqueness_Measure_Bin", ium < mean-stddev ? 0 : (ium < mean+stddev ? 1 : 2)); | ||
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | void store(QDataStream &stream) const | 60 | void store(QDataStream &stream) const |
sdk/plugins/random.cpp
| @@ -27,47 +27,6 @@ namespace br | @@ -27,47 +27,6 @@ namespace br | ||
| 27 | 27 | ||
| 28 | /*! | 28 | /*! |
| 29 | * \ingroup transforms | 29 | * \ingroup transforms |
| 30 | - * \brief Selects a random transform. | ||
| 31 | - * \author Josh Klontz \cite jklontz | ||
| 32 | - */ | ||
| 33 | -class RndTransformTransform : public Transform | ||
| 34 | -{ | ||
| 35 | - Q_OBJECT | ||
| 36 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms STORED false) | ||
| 37 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 38 | - | ||
| 39 | - int selectedIndex; | ||
| 40 | - Transform *selectedTransform; | ||
| 41 | - | ||
| 42 | - void train(const TemplateList &data) | ||
| 43 | - { | ||
| 44 | - selectedIndex = theRNG().uniform(0, transforms.size()); | ||
| 45 | - selectedTransform = transforms[selectedIndex]->clone(); | ||
| 46 | - selectedTransform->train(data); | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | - void project(const Template &src, Template &dst) const | ||
| 50 | - { | ||
| 51 | - selectedTransform->project(src, dst); | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - void store(QDataStream &stream) const | ||
| 55 | - { | ||
| 56 | - stream << selectedIndex << *selectedTransform; | ||
| 57 | - } | ||
| 58 | - | ||
| 59 | - void load(QDataStream &stream) | ||
| 60 | - { | ||
| 61 | - stream >> selectedIndex; | ||
| 62 | - selectedTransform = transforms[selectedIndex]->clone(); | ||
| 63 | - stream >> *selectedTransform; | ||
| 64 | - } | ||
| 65 | -}; | ||
| 66 | - | ||
| 67 | -BR_REGISTER(Transform, RndTransformTransform) | ||
| 68 | - | ||
| 69 | -/*! | ||
| 70 | - * \ingroup transforms | ||
| 71 | * \brief Generates a random subspace. | 30 | * \brief Generates a random subspace. |
| 72 | * \author Josh Klontz \cite jklontz | 31 | * \author Josh Klontz \cite jklontz |
| 73 | */ | 32 | */ |
| @@ -196,7 +155,7 @@ class RndPointTransform : public Transform | @@ -196,7 +155,7 @@ class RndPointTransform : public Transform | ||
| 196 | void project(const Template &src, Template &dst) const | 155 | void project(const Template &src, Template &dst) const |
| 197 | { | 156 | { |
| 198 | dst = src; | 157 | dst = src; |
| 199 | - dst.file.appendLandmark(QPointF(src.m().cols * x, src.m().rows * y)); | 158 | + dst.file.appendPoint(QPointF(src.m().cols * x, src.m().rows * y)); |
| 200 | } | 159 | } |
| 201 | }; | 160 | }; |
| 202 | 161 |
sdk/plugins/regions.cpp
| @@ -148,8 +148,8 @@ class RectFromLandmarksTransform : public UntrainableTransform | @@ -148,8 +148,8 @@ class RectFromLandmarksTransform : public UntrainableTransform | ||
| 148 | 148 | ||
| 149 | void project(const Template &src, Template &dst) const | 149 | void project(const Template &src, Template &dst) const |
| 150 | { | 150 | { |
| 151 | - if (src.file.landmarks().isEmpty()) { | ||
| 152 | - qWarning("No landmarks for %s", qPrintable(src.file.fileName())); | 151 | + if (src.file.points().isEmpty()) { |
| 152 | + qWarning("No landmarks"); | ||
| 153 | dst = src; | 153 | dst = src; |
| 154 | return; | 154 | return; |
| 155 | } | 155 | } |
| @@ -160,12 +160,12 @@ class RectFromLandmarksTransform : public UntrainableTransform | @@ -160,12 +160,12 @@ class RectFromLandmarksTransform : public UntrainableTransform | ||
| 160 | maxX = maxY = -std::numeric_limits<int>::max(); | 160 | maxX = maxY = -std::numeric_limits<int>::max(); |
| 161 | 161 | ||
| 162 | foreach(int index, indices) { | 162 | foreach(int index, indices) { |
| 163 | - if (src.file.landmarks().size() > index+1) { | ||
| 164 | - if (src.file.landmarks()[index].x() < minX) minX = src.file.landmarks()[index].x(); | ||
| 165 | - if (src.file.landmarks()[index].x() > maxX) maxX = src.file.landmarks()[index].x(); | ||
| 166 | - if (src.file.landmarks()[index].y() < minY) minY = src.file.landmarks()[index].y(); | ||
| 167 | - if (src.file.landmarks()[index].y() > maxY) maxY = src.file.landmarks()[index].y(); | ||
| 168 | - dst.file.appendLandmark(src.file.landmarks()[index]); | 163 | + if (src.file.points().size() > index+1) { |
| 164 | + if (src.file.points()[index].x() < minX) minX = src.file.points()[index].x(); | ||
| 165 | + if (src.file.points()[index].x() > maxX) maxX = src.file.points()[index].x(); | ||
| 166 | + if (src.file.points()[index].y() < minY) minY = src.file.points()[index].y(); | ||
| 167 | + if (src.file.points()[index].y() > maxY) maxY = src.file.points()[index].y(); | ||
| 168 | + dst.file.appendPoint(src.file.points()[index]); | ||
| 169 | } | 169 | } |
| 170 | } | 170 | } |
| 171 | 171 |
sdk/plugins/register.cpp
| @@ -67,17 +67,14 @@ class AffineTransform : public UntrainableTransform | @@ -67,17 +67,14 @@ class AffineTransform : public UntrainableTransform | ||
| 67 | else dstPoints[2] = Point2f(x3*width, y3*height); | 67 | else dstPoints[2] = Point2f(x3*width, y3*height); |
| 68 | 68 | ||
| 69 | Point2f srcPoints[3]; | 69 | Point2f srcPoints[3]; |
| 70 | - if (src.file.contains("Affine_0_X") && | ||
| 71 | - src.file.contains("Affine_0_Y") && | ||
| 72 | - src.file.contains("Affine_1_X") && | ||
| 73 | - src.file.contains("Affine_1_Y") && | ||
| 74 | - (src.file.contains("Affine_2_X") || twoPoints) && | ||
| 75 | - (src.file.contains("Affine_2_Y") || twoPoints)) { | ||
| 76 | - srcPoints[0] = Point2f(src.file.getFloat("Affine_0_X"), src.file.getFloat("Affine_0_Y")); | ||
| 77 | - srcPoints[1] = Point2f(src.file.getFloat("Affine_1_X"), src.file.getFloat("Affine_1_Y")); | ||
| 78 | - if (!twoPoints) srcPoints[2] = Point2f(src.file.getFloat("Affine_2_X"), src.file.getFloat("Affine_2_Y")); | 70 | + if (src.file.contains("Affine_0") && |
| 71 | + src.file.contains("Affine_1") && | ||
| 72 | + (src.file.contains("Affine_2") || twoPoints)) { | ||
| 73 | + srcPoints[0] = OpenCVUtils::toPoint(src.file.get<QPointF>("Affine_0")); | ||
| 74 | + srcPoints[1] = OpenCVUtils::toPoint(src.file.get<QPointF>("Affine_1")); | ||
| 75 | + if (!twoPoints) srcPoints[2] = OpenCVUtils::toPoint(src.file.get<QPointF>("Affine_2")); | ||
| 79 | } else { | 76 | } else { |
| 80 | - const QList<Point2f> landmarks = OpenCVUtils::toPoints(src.file.landmarks()); | 77 | + const QList<Point2f> landmarks = OpenCVUtils::toPoints(src.file.points()); |
| 81 | 78 | ||
| 82 | if ((landmarks.size() < 2) || (!twoPoints && (landmarks.size() < 3))) { | 79 | if ((landmarks.size() < 2) || (!twoPoints && (landmarks.size() < 3))) { |
| 83 | resize(src, dst, Size(width, height)); | 80 | resize(src, dst, Size(width, height)); |
| @@ -87,14 +84,9 @@ class AffineTransform : public UntrainableTransform | @@ -87,14 +84,9 @@ class AffineTransform : public UntrainableTransform | ||
| 87 | srcPoints[1] = landmarks[1]; | 84 | srcPoints[1] = landmarks[1]; |
| 88 | if (!twoPoints) srcPoints[2] = landmarks[2]; | 85 | if (!twoPoints) srcPoints[2] = landmarks[2]; |
| 89 | 86 | ||
| 90 | - dst.file.insert("Affine_0_X", landmarks[0].x); | ||
| 91 | - dst.file.insert("Affine_0_Y", landmarks[0].y); | ||
| 92 | - dst.file.insert("Affine_1_X", landmarks[1].x); | ||
| 93 | - dst.file.insert("Affine_1_Y", landmarks[1].y); | ||
| 94 | - if (!twoPoints) { | ||
| 95 | - dst.file.insert("Affine_2_X", landmarks[2].x); | ||
| 96 | - dst.file.insert("Affine_2_Y", landmarks[2].y); | ||
| 97 | - } | 87 | + dst.file.set("Affine_0", OpenCVUtils::fromPoint(landmarks[0])); |
| 88 | + dst.file.set("Affine_1", OpenCVUtils::fromPoint(landmarks[1])); | ||
| 89 | + if (!twoPoints) dst.file.set("Affine_2", OpenCVUtils::fromPoint(landmarks[2])); | ||
| 98 | } | 90 | } |
| 99 | } | 91 | } |
| 100 | if (twoPoints) srcPoints[2] = getThirdAffinePoint(srcPoints[0], srcPoints[1]); | 92 | if (twoPoints) srcPoints[2] = getThirdAffinePoint(srcPoints[0], srcPoints[1]); |
sdk/plugins/stasm.cpp
| @@ -18,7 +18,7 @@ class StasmInitializer : public Initializer | @@ -18,7 +18,7 @@ class StasmInitializer : public Initializer | ||
| 18 | 18 | ||
| 19 | void initialize() const | 19 | void initialize() const |
| 20 | { | 20 | { |
| 21 | - Globals->abbreviations.insert("RectFromStasmEyes","RectFromLandmarks([27, 28, 29, 30, 31, 32, 33, 34, 35, 36],0.125,6.0)+Resize(44,168)"); // | 21 | + Globals->abbreviations.insert("RectFromStasmEyes","RectFromLandmarks([27, 28, 29, 30, 31, 32, 33, 34, 35, 36],0.125,6.0)+Resize(44,164)"); // |
| 22 | Globals->abbreviations.insert("RectFromStasmJaw","RectFromLandmarks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],10)"); | 22 | Globals->abbreviations.insert("RectFromStasmJaw","RectFromLandmarks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],10)"); |
| 23 | Globals->abbreviations.insert("RectFromStasmBrow","RectFromLandmarks([15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26],0.25,6.5)+Resize(44,230)"); | 23 | Globals->abbreviations.insert("RectFromStasmBrow","RectFromLandmarks([15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26],0.25,6.5)+Resize(44,230)"); |
| 24 | Globals->abbreviations.insert("RectFromStasmNose","RectFromLandmarks([38, 39, 40, 41, 42, 43, 44, 67],0.1,1.5)+Resize(44,44)"); | 24 | Globals->abbreviations.insert("RectFromStasmNose","RectFromLandmarks([38, 39, 40, 41, 42, 43, 44, 67],0.1,1.5)+Resize(44,44)"); |
| @@ -54,13 +54,13 @@ class StasmTransform : public UntrainableTransform | @@ -54,13 +54,13 @@ class StasmTransform : public UntrainableTransform | ||
| 54 | 54 | ||
| 55 | if (nlandmarks == 0) { | 55 | if (nlandmarks == 0) { |
| 56 | qWarning("Unable to detect Stasm landmarks for %s", qPrintable(src.file.fileName())); | 56 | qWarning("Unable to detect Stasm landmarks for %s", qPrintable(src.file.fileName())); |
| 57 | - dst.file.setBool("FTE"); | 57 | + dst.file.set("FTE", true); |
| 58 | dst.m() = src.m(); | 58 | dst.m() = src.m(); |
| 59 | return; | 59 | return; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | for (int i = 0; i < nlandmarks; i++) | 62 | for (int i = 0; i < nlandmarks; i++) |
| 63 | - dst.file.appendLandmark(QPointF(landmarks[2 * i], landmarks[2 * i + 1])); | 63 | + dst.file.appendPoint(QPointF(landmarks[2 * i], landmarks[2 * i + 1])); |
| 64 | 64 | ||
| 65 | dst.m() = src.m(); | 65 | dst.m() = src.m(); |
| 66 | } | 66 | } |
sdk/plugins/validate.cpp
| @@ -22,7 +22,7 @@ class CrossValidateTransform : public MetaTransform | @@ -22,7 +22,7 @@ class CrossValidateTransform : public MetaTransform | ||
| 22 | int numPartitions = 0; | 22 | int numPartitions = 0; |
| 23 | QList<int> partitions; partitions.reserve(data.size()); | 23 | QList<int> partitions; partitions.reserve(data.size()); |
| 24 | foreach (const File &file, data.files()) { | 24 | foreach (const File &file, data.files()) { |
| 25 | - partitions.append(file.getInt("Cross_Validation_Partition", 0)); | 25 | + partitions.append(file.get<int>("Cross_Validation_Partition", 0)); |
| 26 | numPartitions = std::max(numPartitions, partitions.last()+1); | 26 | numPartitions = std::max(numPartitions, partitions.last()+1); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| @@ -48,7 +48,7 @@ class CrossValidateTransform : public MetaTransform | @@ -48,7 +48,7 @@ class CrossValidateTransform : public MetaTransform | ||
| 48 | 48 | ||
| 49 | void project(const Template &src, Template &dst) const | 49 | void project(const Template &src, Template &dst) const |
| 50 | { | 50 | { |
| 51 | - transforms[src.file.getInt("Cross_Validation_Partition", 0)]->project(src, dst); | 51 | + transforms[src.file.get<int>("Cross_Validation_Partition", 0)]->project(src, dst); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | void store(QDataStream &stream) const | 54 | void store(QDataStream &stream) const |
| @@ -82,8 +82,8 @@ class CrossValidateDistance : public Distance | @@ -82,8 +82,8 @@ class CrossValidateDistance : public Distance | ||
| 82 | 82 | ||
| 83 | float compare(const Template &a, const Template &b) const | 83 | float compare(const Template &a, const Template &b) const |
| 84 | { | 84 | { |
| 85 | - const int partitionA = a.file.getInt("Cross_Validation_Partition", 0); | ||
| 86 | - const int partitionB = b.file.getInt("Cross_Validation_Partition", 0); | 85 | + const int partitionA = a.file.get<int>("Cross_Validation_Partition", 0); |
| 86 | + const int partitionB = b.file.get<int>("Cross_Validation_Partition", 0); | ||
| 87 | return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0; | 87 | return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0; |
| 88 | } | 88 | } |
| 89 | }; | 89 | }; |
| @@ -104,7 +104,7 @@ class FilterDistance : public Distance | @@ -104,7 +104,7 @@ class FilterDistance : public Distance | ||
| 104 | (void) b; // Query template isn't checked | 104 | (void) b; // Query template isn't checked |
| 105 | foreach (const QString &key, Globals->filters.keys()) { | 105 | foreach (const QString &key, Globals->filters.keys()) { |
| 106 | bool keep = false; | 106 | bool keep = false; |
| 107 | - const QString metadata = a.file.getString(key, ""); | 107 | + const QString metadata = a.file.get<QString>(key, ""); |
| 108 | if (metadata.isEmpty()) continue; | 108 | if (metadata.isEmpty()) continue; |
| 109 | foreach (const QString &value, Globals->filters[key]) { | 109 | foreach (const QString &value, Globals->filters[key]) { |
| 110 | if (metadata == value) { | 110 | if (metadata == value) { |
sdk/plugins/wavelet.cpp
| @@ -189,11 +189,11 @@ class GaborJetTransform : public UntrainableTransform | @@ -189,11 +189,11 @@ class GaborJetTransform : public UntrainableTransform | ||
| 189 | 189 | ||
| 190 | void project(const Template &src, Template &dst) const | 190 | void project(const Template &src, Template &dst) const |
| 191 | { | 191 | { |
| 192 | - const QList<QPointF> landmarks = src.file.landmarks(); | ||
| 193 | - dst = Mat(landmarks.size(), kReals.size(), CV_32FC1); | ||
| 194 | - for (int i=0; i<landmarks.size(); i++) | 192 | + const QList<QPointF> points = src.file.points(); |
| 193 | + dst = Mat(points.size(), kReals.size(), CV_32FC1); | ||
| 194 | + for (int i=0; i<points.size(); i++) | ||
| 195 | for (int j=0; j<kReals.size(); j++) | 195 | for (int j=0; j<kReals.size(); j++) |
| 196 | - dst.m().at<float>(i,j) = response(src, landmarks[i], kReals[j], kImaginaries[j], component); | 196 | + dst.m().at<float>(i,j) = response(src, points[i], kReals[j], kImaginaries[j], component); |
| 197 | } | 197 | } |
| 198 | }; | 198 | }; |
| 199 | 199 |
sdk/plugins/youtube.cpp
| 1 | #include <openbr_plugin.h> | 1 | #include <openbr_plugin.h> |
| 2 | 2 | ||
| 3 | +#include "core/common.h" | ||
| 4 | + | ||
| 3 | namespace br | 5 | namespace br |
| 4 | { | 6 | { |
| 5 | 7 | ||
| @@ -19,24 +21,27 @@ class YouTubeFacesDBTransform : public UntrainableMetaTransform | @@ -19,24 +21,27 @@ class YouTubeFacesDBTransform : public UntrainableMetaTransform | ||
| 19 | 21 | ||
| 20 | void init() | 22 | void init() |
| 21 | { | 23 | { |
| 24 | + if (algorithm.isEmpty()) return; | ||
| 22 | transform = Transform::fromAlgorithm(algorithm); | 25 | transform = Transform::fromAlgorithm(algorithm); |
| 23 | distance = Distance::fromAlgorithm(algorithm); | 26 | distance = Distance::fromAlgorithm(algorithm); |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | - void project(const Template &src, Template &dst) const | 29 | + void project(const TemplateList &src, TemplateList &dst) const |
| 27 | { | 30 | { |
| 28 | - dst = src; | ||
| 29 | - | ||
| 30 | - // First input is the header in 'splits.txt' | ||
| 31 | - if (src.file.getInt("Index") == 0) return; | 31 | + Transform::project(src.mid(1) /* First template is the header in 'splits.txt' */, dst); |
| 32 | + } | ||
| 32 | 33 | ||
| 34 | + void project(const Template &src, Template &dst) const | ||
| 35 | + { | ||
| 33 | const QStringList words = src.file.name.split(", "); | 36 | const QStringList words = src.file.name.split(", "); |
| 34 | dst.file.name = words[0] + "_" + words[1] + "_" + words[4] + ".mtx"; | 37 | dst.file.name = words[0] + "_" + words[1] + "_" + words[4] + ".mtx"; |
| 35 | 38 | ||
| 36 | TemplateList queryTemplates = TemplateList::fromGallery(File(words[2]).resolved()); | 39 | TemplateList queryTemplates = TemplateList::fromGallery(File(words[2]).resolved()); |
| 40 | + sort(queryTemplates); | ||
| 37 | queryTemplates >> *transform; | 41 | queryTemplates >> *transform; |
| 38 | 42 | ||
| 39 | TemplateList targetTemplates = TemplateList::fromGallery(File(words[3]).resolved()); | 43 | TemplateList targetTemplates = TemplateList::fromGallery(File(words[3]).resolved()); |
| 44 | + sort(targetTemplates); | ||
| 40 | targetTemplates >> *transform; | 45 | targetTemplates >> *transform; |
| 41 | 46 | ||
| 42 | QScopedPointer<MatrixOutput> memoryOutput(MatrixOutput::make(targetTemplates.files(), queryTemplates.files())); | 47 | QScopedPointer<MatrixOutput> memoryOutput(MatrixOutput::make(targetTemplates.files(), queryTemplates.files())); |
| @@ -45,6 +50,26 @@ class YouTubeFacesDBTransform : public UntrainableMetaTransform | @@ -45,6 +50,26 @@ class YouTubeFacesDBTransform : public UntrainableMetaTransform | ||
| 45 | dst.clear(); | 50 | dst.clear(); |
| 46 | dst.m() = memoryOutput.data()->data; | 51 | dst.m() = memoryOutput.data()->data; |
| 47 | } | 52 | } |
| 53 | + | ||
| 54 | + static void sort(TemplateList &templates) | ||
| 55 | + { | ||
| 56 | + // The file names in the YouTube Faces Database make it very difficult | ||
| 57 | + // for them to be ordered by frame number automatically, | ||
| 58 | + // hence we do it manually here. | ||
| 59 | + QList<int> frames; | ||
| 60 | + foreach (const Template &t, templates) { | ||
| 61 | + QStringList words = t.file.name.split('.'); | ||
| 62 | + frames.append(words[words.size()-2].toInt()); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + typedef QPair<int,int> SortedFrame; // <frame number, original index> | ||
| 66 | + QList<SortedFrame> sortedFrames = Common::Sort(frames); | ||
| 67 | + TemplateList sortedTemplates; sortedTemplates.reserve(templates.size()); | ||
| 68 | + foreach (const SortedFrame &sortedFrame, sortedFrames) | ||
| 69 | + sortedTemplates.append(templates[sortedFrame.second]); | ||
| 70 | + | ||
| 71 | + templates = sortedTemplates; | ||
| 72 | + } | ||
| 48 | }; | 73 | }; |
| 49 | 74 | ||
| 50 | BR_REGISTER(Transform, YouTubeFacesDBTransform) | 75 | BR_REGISTER(Transform, YouTubeFacesDBTransform) |