Commit a3d263f0f600b94f2a72b247b0f22529f1dfc701
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
51 changed files
with
1114 additions
and
235 deletions
.gitignore
| @@ -41,4 +41,9 @@ scripts/results | @@ -41,4 +41,9 @@ scripts/results | ||
| 41 | data/INRIAPerson/sigset | 41 | data/INRIAPerson/sigset |
| 42 | data/KTH/sigset | 42 | data/KTH/sigset |
| 43 | data/CaltechPedestrians/annotations | 43 | data/CaltechPedestrians/annotations |
| 44 | +data/CaltechPedestrians/*.xml | ||
| 44 | 45 | ||
| 46 | +### Sublime ### | ||
| 47 | +*.check_cache | ||
| 48 | +*.sublime-project | ||
| 49 | +*.sublime-workspace |
README.md
| @@ -14,4 +14,3 @@ To optionally check out a particular [tagged release](https://github.com/biometr | @@ -14,4 +14,3 @@ To optionally check out a particular [tagged release](https://github.com/biometr | ||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | [](https://bitdeli.com/free "Bitdeli Badge") | 16 | [](https://bitdeli.com/free "Bitdeli Badge") |
| 17 | - |
app/CMakeLists.txt
app/br/br.cpp
| @@ -158,15 +158,24 @@ public: | @@ -158,15 +158,24 @@ public: | ||
| 158 | } else if (!strcmp(fun, "plotMetadata")) { | 158 | } else if (!strcmp(fun, "plotMetadata")) { |
| 159 | check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); | 159 | check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); |
| 160 | br_plot_metadata(parc-1, parv, parv[parc-1], true); | 160 | br_plot_metadata(parc-1, parv, parv[parc-1], true); |
| 161 | + } else if (!strcmp(fun, "deduplicate")) { | ||
| 162 | + check(parc == 3, "Incorrect parameter count for 'deduplicate'."); | ||
| 163 | + br_deduplicate(parv[0], parv[1], parv[2]); | ||
| 161 | } | 164 | } |
| 162 | 165 | ||
| 163 | // Miscellaneous | 166 | // Miscellaneous |
| 164 | else if (!strcmp(fun, "help")) { | 167 | else if (!strcmp(fun, "help")) { |
| 165 | check(parc == 0, "No parameters expected for 'help'."); | 168 | check(parc == 0, "No parameters expected for 'help'."); |
| 166 | help(); | 169 | help(); |
| 170 | + } else if (!strcmp(fun, "gui")) { | ||
| 171 | + // Do nothing because we checked for this flag prior to initialization | ||
| 167 | } else if (!strcmp(fun, "objects")) { | 172 | } else if (!strcmp(fun, "objects")) { |
| 168 | check(parc <= 2, "Incorrect parameter count for 'objects'."); | 173 | check(parc <= 2, "Incorrect parameter count for 'objects'."); |
| 169 | - printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*")); | 174 | + int size = br_objects(NULL, 0, parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*"); |
| 175 | + char * temp = new char[size]; | ||
| 176 | + br_objects(temp, size, parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*"); | ||
| 177 | + printf("%s\n", temp); | ||
| 178 | + delete [] temp; | ||
| 170 | } else if (!strcmp(fun, "about")) { | 179 | } else if (!strcmp(fun, "about")) { |
| 171 | check(parc == 0, "No parameters expected for 'about'."); | 180 | check(parc == 0, "No parameters expected for 'about'."); |
| 172 | printf("%s\n", br_about()); | 181 | printf("%s\n", br_about()); |
| @@ -177,11 +186,10 @@ public: | @@ -177,11 +186,10 @@ public: | ||
| 177 | check(parc == 1, "Incorrect parameter count for 'daemon'."); | 186 | check(parc == 1, "Incorrect parameter count for 'daemon'."); |
| 178 | daemon = true; | 187 | daemon = true; |
| 179 | daemon_pipe = parv[0]; | 188 | daemon_pipe = parv[0]; |
| 180 | - } else if (!strcmp(fun,"slave")) { | 189 | + } else if (!strcmp(fun, "slave")) { |
| 181 | check(parc == 1, "Incorrect parameter count for 'slave'"); | 190 | check(parc == 1, "Incorrect parameter count for 'slave'"); |
| 182 | br_slave_process(parv[0]); | 191 | br_slave_process(parv[0]); |
| 183 | - } | ||
| 184 | - else if (!strcmp(fun, "exit")) { | 192 | + } else if (!strcmp(fun, "exit")) { |
| 185 | check(parc == 0, "No parameters expected for 'exit'."); | 193 | check(parc == 0, "No parameters expected for 'exit'."); |
| 186 | daemon = false; | 194 | daemon = false; |
| 187 | } else if (!strcmp(fun, "getHeader")) { | 195 | } else if (!strcmp(fun, "getHeader")) { |
| @@ -245,6 +253,7 @@ private: | @@ -245,6 +253,7 @@ private: | ||
| 245 | "\n" | 253 | "\n" |
| 246 | "==== Miscellaneous ====\n" | 254 | "==== Miscellaneous ====\n" |
| 247 | "-help\n" | 255 | "-help\n" |
| 256 | + "-gui\n" | ||
| 248 | "-objects [abstraction [implementation]]\n" | 257 | "-objects [abstraction [implementation]]\n" |
| 249 | "-about\n" | 258 | "-about\n" |
| 250 | "-version\n" | 259 | "-version\n" |
| @@ -255,7 +264,7 @@ private: | @@ -255,7 +264,7 @@ private: | ||
| 255 | 264 | ||
| 256 | int main(int argc, char *argv[]) | 265 | int main(int argc, char *argv[]) |
| 257 | { | 266 | { |
| 258 | - br_initialize(argc, argv); | 267 | + br_initialize(argc, argv, "", argc >= 2 && !strcmp(argv[1], "-gui")); |
| 259 | 268 | ||
| 260 | FakeMain *fakeMain = new FakeMain(argc, argv); | 269 | FakeMain *fakeMain = new FakeMain(argc, argv); |
| 261 | QThreadPool::globalInstance()->start(fakeMain); | 270 | QThreadPool::globalInstance()->start(fakeMain); |
openbr/CMakeLists.txt
| @@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL "Build Janus implementatio | @@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL "Build Janus implementatio | ||
| 34 | set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation") | 34 | set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation") |
| 35 | mark_as_advanced(JANUS_BUILD_PP5_WRAPPER) | 35 | mark_as_advanced(JANUS_BUILD_PP5_WRAPPER) |
| 36 | mark_as_advanced(JANUS_BUILD_DOCS) | 36 | mark_as_advanced(JANUS_BUILD_DOCS) |
| 37 | -set(JANUS_TEST_IMPLEMENTATION openbr) | 37 | +set(JANUS_IMPLEMENTATION openbr) |
| 38 | add_subdirectory(janus) | 38 | add_subdirectory(janus) |
| 39 | 39 | ||
| 40 | # Install | 40 | # Install |
openbr/core/bee.cpp
| @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi | @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi | ||
| 172 | qint64 read = file.read((char*)m.data, bytesExpected); | 172 | qint64 read = file.read((char*)m.data, bytesExpected); |
| 173 | if (read != bytesExpected) | 173 | if (read != bytesExpected) |
| 174 | qFatal("Invalid matrix size."); | 174 | qFatal("Invalid matrix size."); |
| 175 | + if (!file.atEnd()) | ||
| 176 | + qFatal("Expected matrix end of file."); | ||
| 175 | file.close(); | 177 | file.close(); |
| 176 | 178 | ||
| 177 | Mat result; | 179 | Mat result; |
| @@ -303,11 +305,14 @@ cv::Mat BEE::makeMask(const br::FileList &targets, const br::FileList &queries, | @@ -303,11 +305,14 @@ cv::Mat BEE::makeMask(const br::FileList &targets, const br::FileList &queries, | ||
| 303 | QList<int> targetPartitions = targets.crossValidationPartitions(); | 305 | QList<int> targetPartitions = targets.crossValidationPartitions(); |
| 304 | QList<int> queryPartitions = queries.crossValidationPartitions(); | 306 | QList<int> queryPartitions = queries.crossValidationPartitions(); |
| 305 | 307 | ||
| 308 | + QList<bool> targetsOnly = File::get<bool>(queries, "targetOnly", false); | ||
| 309 | + | ||
| 306 | Mat mask(queries.size(), targets.size(), CV_8UC1); | 310 | Mat mask(queries.size(), targets.size(), CV_8UC1); |
| 307 | for (int i=0; i<queries.size(); i++) { | 311 | for (int i=0; i<queries.size(); i++) { |
| 308 | const QString &fileA = queries[i]; | 312 | const QString &fileA = queries[i]; |
| 309 | const QString labelA = queryLabels[i]; | 313 | const QString labelA = queryLabels[i]; |
| 310 | const int partitionA = queryPartitions[i]; | 314 | const int partitionA = queryPartitions[i]; |
| 315 | + const bool targetOnly = targetsOnly[i]; | ||
| 311 | 316 | ||
| 312 | for (int j=0; j<targets.size(); j++) { | 317 | for (int j=0; j<targets.size(); j++) { |
| 313 | const QString &fileB = targets[j]; | 318 | const QString &fileB = targets[j]; |
| @@ -316,6 +321,7 @@ cv::Mat BEE::makeMask(const br::FileList &targets, const br::FileList &queries, | @@ -316,6 +321,7 @@ cv::Mat BEE::makeMask(const br::FileList &targets, const br::FileList &queries, | ||
| 316 | 321 | ||
| 317 | Mask_t val; | 322 | Mask_t val; |
| 318 | if (fileA == fileB) val = DontCare; | 323 | if (fileA == fileB) val = DontCare; |
| 324 | + else if (targetOnly) val = DontCare; | ||
| 319 | else if (labelA == "-1") val = DontCare; | 325 | else if (labelA == "-1") val = DontCare; |
| 320 | else if (labelB == "-1") val = DontCare; | 326 | else if (labelB == "-1") val = DontCare; |
| 321 | else if (partitionA != partition) val = DontCare; | 327 | else if (partitionA != partition) val = DontCare; |
openbr/core/cluster.cpp
| @@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
| 21 | #include <QSet> | 21 | #include <QSet> |
| 22 | #include <limits> | 22 | #include <limits> |
| 23 | #include <openbr/openbr_plugin.h> | 23 | #include <openbr/openbr_plugin.h> |
| 24 | +#include <assert.h> | ||
| 24 | 25 | ||
| 25 | #include "openbr/core/bee.h" | 26 | #include "openbr/core/bee.h" |
| 26 | #include "openbr/core/cluster.h" | 27 | #include "openbr/core/cluster.h" |
openbr/core/core.cpp
| @@ -65,6 +65,9 @@ struct AlgorithmCore | @@ -65,6 +65,9 @@ struct AlgorithmCore | ||
| 65 | downcast->train(data); | 65 | downcast->train(data); |
| 66 | 66 | ||
| 67 | if (!distance.isNull()) { | 67 | if (!distance.isNull()) { |
| 68 | + if (Globals->crossValidate > 0) | ||
| 69 | + for (int i=data.size()-1; i>=0; i--) if (data[i].file.get<bool>("allPartitions",false)) data.removeAt(i); | ||
| 70 | + | ||
| 68 | qDebug("Projecting Enrollment"); | 71 | qDebug("Projecting Enrollment"); |
| 69 | downcast->projectUpdate(data,data); | 72 | downcast->projectUpdate(data,data); |
| 70 | 73 | ||
| @@ -251,6 +254,56 @@ struct AlgorithmCore | @@ -251,6 +254,56 @@ struct AlgorithmCore | ||
| 251 | Globals->blockSize = old_block_size; | 254 | Globals->blockSize = old_block_size; |
| 252 | } | 255 | } |
| 253 | 256 | ||
| 257 | + void deduplicate(const File &inputGallery, const File &outputGallery, const float threshold) | ||
| 258 | + { | ||
| 259 | + qDebug("Deduplicating %s to %s with a score threshold of %f", qPrintable(inputGallery.flat()), qPrintable(outputGallery.flat()), threshold); | ||
| 260 | + | ||
| 261 | + if (distance.isNull()) qFatal("Null distance."); | ||
| 262 | + | ||
| 263 | + QScopedPointer<Gallery> i; | ||
| 264 | + FileList inputFiles; | ||
| 265 | + retrieveOrEnroll(inputGallery, i, inputFiles); | ||
| 266 | + | ||
| 267 | + TemplateList t = i->read(); | ||
| 268 | + | ||
| 269 | + Output *o = Output::make(QString("buffer.tail[selfSimilar,threshold=%1,atLeast=0]").arg(QString::number(threshold)),inputFiles,inputFiles); | ||
| 270 | + | ||
| 271 | + // Compare to global tail output | ||
| 272 | + distance->compare(t,t,o); | ||
| 273 | + | ||
| 274 | + delete o; | ||
| 275 | + | ||
| 276 | + QString buffer(Globals->buffer); | ||
| 277 | + | ||
| 278 | + QStringList tail = buffer.split("\n"); | ||
| 279 | + | ||
| 280 | + // Remove header | ||
| 281 | + tail.removeFirst(); | ||
| 282 | + | ||
| 283 | + QStringList toRemove; | ||
| 284 | + foreach(const QString &s, tail) | ||
| 285 | + toRemove.append(s.split(',').at(1)); | ||
| 286 | + | ||
| 287 | + QSet<QString> duplicates = QSet<QString>::fromList(toRemove); | ||
| 288 | + | ||
| 289 | + QStringList fileNames = inputFiles.names(); | ||
| 290 | + | ||
| 291 | + QList<int> indices; | ||
| 292 | + foreach(const QString &d, duplicates) | ||
| 293 | + indices.append(fileNames.indexOf(d)); | ||
| 294 | + | ||
| 295 | + std::sort(indices.begin(),indices.end(),std::greater<float>()); | ||
| 296 | + | ||
| 297 | + qDebug("\n%d duplicates removed.", indices.size()); | ||
| 298 | + | ||
| 299 | + for (int i=0; i<indices.size(); i++) | ||
| 300 | + inputFiles.removeAt(indices[i]); | ||
| 301 | + | ||
| 302 | + QScopedPointer<Gallery> og(Gallery::make(outputGallery)); | ||
| 303 | + | ||
| 304 | + og->writeBlock(inputFiles); | ||
| 305 | + } | ||
| 306 | + | ||
| 254 | void compare(File targetGallery, File queryGallery, File output) | 307 | void compare(File targetGallery, File queryGallery, File output) |
| 255 | { | 308 | { |
| 256 | qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), | 309 | qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), |
| @@ -496,6 +549,14 @@ void br::Cat(const QStringList &inputGalleries, const QString &outputGallery) | @@ -496,6 +549,14 @@ void br::Cat(const QStringList &inputGalleries, const QString &outputGallery) | ||
| 496 | } | 549 | } |
| 497 | } | 550 | } |
| 498 | 551 | ||
| 552 | +void br::Deduplicate(const File &inputGallery, const File &outputGallery, const QString &threshold) | ||
| 553 | +{ | ||
| 554 | + bool ok; | ||
| 555 | + float thresh = threshold.toFloat(&ok); | ||
| 556 | + if (ok) AlgorithmManager::getAlgorithm(inputGallery.get<QString>("algorithm"))->deduplicate(inputGallery, outputGallery, thresh); | ||
| 557 | + else qFatal("Unable to convert deduplication threshold to float."); | ||
| 558 | +} | ||
| 559 | + | ||
| 499 | QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess) | 560 | QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess) |
| 500 | { | 561 | { |
| 501 | if (!preprocess) | 562 | if (!preprocess) |
openbr/core/opencvutils.cpp
| @@ -15,7 +15,9 @@ | @@ -15,7 +15,9 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/highgui/highgui.hpp> | 17 | #include <opencv2/highgui/highgui.hpp> |
| 18 | +#include <opencv2/highgui/highgui_c.h> | ||
| 18 | #include <opencv2/imgproc/imgproc.hpp> | 19 | #include <opencv2/imgproc/imgproc.hpp> |
| 20 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 19 | #include <openbr/openbr_plugin.h> | 21 | #include <openbr/openbr_plugin.h> |
| 20 | 22 | ||
| 21 | #include "opencvutils.h" | 23 | #include "opencvutils.h" |
openbr/core/opencvutils.h
openbr/gui/algorithm.cpp
| 1 | #include <QStringList> | 1 | #include <QStringList> |
| 2 | #include <openbr/openbr.h> | 2 | #include <openbr/openbr.h> |
| 3 | +#include <openbr/openbr_plugin.h> | ||
| 3 | 4 | ||
| 4 | #include "algorithm.h" | 5 | #include "algorithm.h" |
| 5 | 6 | ||
| @@ -18,7 +19,7 @@ bool br::Algorithm::addAlgorithm(const QString &algorithm, const QString &displa | @@ -18,7 +19,7 @@ bool br::Algorithm::addAlgorithm(const QString &algorithm, const QString &displa | ||
| 18 | { | 19 | { |
| 19 | static QStringList availableAlgorithms; | 20 | static QStringList availableAlgorithms; |
| 20 | if (availableAlgorithms.isEmpty()) | 21 | if (availableAlgorithms.isEmpty()) |
| 21 | - availableAlgorithms = QString(br_objects("Abbreviation", ".*", false)).split("\n"); | 22 | + availableAlgorithms = br::Context::objects("Abbreviation", ".*", false); |
| 22 | 23 | ||
| 23 | if (!availableAlgorithms.contains(algorithm)) | 24 | if (!availableAlgorithms.contains(algorithm)) |
| 24 | return false; | 25 | return false; |
openbr/gui/gallerytoolbar.cpp
| @@ -84,7 +84,7 @@ void br::GalleryToolBar::_enroll(const br::File &input) | @@ -84,7 +84,7 @@ void br::GalleryToolBar::_enroll(const br::File &input) | ||
| 84 | galleryLock.lock(); | 84 | galleryLock.lock(); |
| 85 | this->input = input; | 85 | this->input = input; |
| 86 | if (input.suffix() == "gal") gallery = input.name + ".mem"; | 86 | if (input.suffix() == "gal") gallery = input.name + ".mem"; |
| 87 | - else gallery = QString("%1/galleries/%2.gal[cache]").arg(br_scratch_path(), qPrintable(input.baseName()+input.hash())); | 87 | + else gallery = QString("%1/galleries/%2.gal[cache]").arg(br::Globals->scratchPath(), qPrintable(input.baseName()+input.hash())); |
| 88 | files = br::Enroll(input.flat(), gallery.flat()); | 88 | files = br::Enroll(input.flat(), gallery.flat()); |
| 89 | galleryLock.unlock(); | 89 | galleryLock.unlock(); |
| 90 | } | 90 | } |
| @@ -148,7 +148,7 @@ void br::GalleryToolBar::home() | @@ -148,7 +148,7 @@ void br::GalleryToolBar::home() | ||
| 148 | 148 | ||
| 149 | void br::GalleryToolBar::mean() | 149 | void br::GalleryToolBar::mean() |
| 150 | { | 150 | { |
| 151 | - const QString file = QString("%1/mean/%2.png").arg(br_scratch_path(), input.baseName()+input.hash()); | 151 | + const QString file = QString("%1/mean/%2.png").arg(br::Globals->scratchPath(), input.baseName()+input.hash()); |
| 152 | br_set_property("CENTER_TRAIN_B", qPrintable(file)); | 152 | br_set_property("CENTER_TRAIN_B", qPrintable(file)); |
| 153 | br::File trainingFile = input; | 153 | br::File trainingFile = input; |
| 154 | br_train(qPrintable(trainingFile.flat()), "[algorithm=MedianFace]"); | 154 | br_train(qPrintable(trainingFile.flat()), "[algorithm=MedianFace]"); |
openbr/gui/progress.cpp
| 1 | #include <openbr/openbr.h> | 1 | #include <openbr/openbr.h> |
| 2 | +#include <openbr/openbr_plugin.h> | ||
| 2 | 3 | ||
| 3 | #include "progress.h" | 4 | #include "progress.h" |
| 4 | 5 | ||
| @@ -29,7 +30,7 @@ void br::Progress::checkProgress() | @@ -29,7 +30,7 @@ void br::Progress::checkProgress() | ||
| 29 | const bool visible = progress >= 0 && progress < 100; | 30 | const bool visible = progress >= 0 && progress < 100; |
| 30 | 31 | ||
| 31 | if (visible) { | 32 | if (visible) { |
| 32 | - showMessage(br_most_recent_message()); | 33 | + showMessage(Globals->mostRecentMessage); |
| 33 | pbProgress.setValue(progress); | 34 | pbProgress.setValue(progress); |
| 34 | if (progress > 100) pbProgress.setMaximum(0); | 35 | if (progress > 100) pbProgress.setMaximum(0); |
| 35 | else pbProgress.setMaximum(100); | 36 | else pbProgress.setMaximum(100); |
openbr/gui/tail.cpp
openbr/gui/templateviewer.cpp
| @@ -72,7 +72,7 @@ void TemplateViewer::refreshImage() | @@ -72,7 +72,7 @@ void TemplateViewer::refreshImage() | ||
| 72 | if (file.isNull() || (format == "Photo")) { | 72 | if (file.isNull() || (format == "Photo")) { |
| 73 | setImage(file, true); | 73 | setImage(file, true); |
| 74 | } else { | 74 | } else { |
| 75 | - const QString path = QString(br_scratch_path()) + "/thumbnails"; | 75 | + const QString path = QString(br::Globals->scratchPath()) + "/thumbnails"; |
| 76 | const QString hash = file.hash()+format; | 76 | const QString hash = file.hash()+format; |
| 77 | const QString processedFile = path+"/"+file.baseName()+hash+".png"; | 77 | const QString processedFile = path+"/"+file.baseName()+hash+".png"; |
| 78 | if (!QFileInfo(processedFile).exists()) { | 78 | if (!QFileInfo(processedFile).exists()) { |
openbr/gui/transformeditor.cpp
| @@ -24,7 +24,7 @@ using namespace br; | @@ -24,7 +24,7 @@ using namespace br; | ||
| 24 | br::TransformEditor::TransformEditor(Transform *transform, QWidget *parent) | 24 | br::TransformEditor::TransformEditor(Transform *transform, QWidget *parent) |
| 25 | : QWidget(parent) | 25 | : QWidget(parent) |
| 26 | { | 26 | { |
| 27 | - name.addItems(QString(br_objects("Transform", ".*", false)).split('\n')); | 27 | + name.addItems(br::Context::objects("Transform", ".*", false)); |
| 28 | layout.addWidget(&name); | 28 | layout.addWidget(&name); |
| 29 | setLayout(&layout); | 29 | setLayout(&layout); |
| 30 | 30 |
openbr/gui/utility.cpp
| 1 | #include <limits> | 1 | #include <limits> |
| 2 | #include <vector> | 2 | #include <vector> |
| 3 | +#include <assert.h> | ||
| 3 | #include <opencv2/imgproc/imgproc.hpp> | 4 | #include <opencv2/imgproc/imgproc.hpp> |
| 5 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 4 | #include "utility.h" | 6 | #include "utility.h" |
| 5 | 7 | ||
| 6 | using namespace cv; | 8 | using namespace cv; |
openbr/janus.cpp
| @@ -3,140 +3,138 @@ | @@ -3,140 +3,138 @@ | ||
| 3 | #endif | 3 | #endif |
| 4 | 4 | ||
| 5 | #include "janus.h" | 5 | #include "janus.h" |
| 6 | +#include "janus_io.h" | ||
| 6 | #include "openbr_plugin.h" | 7 | #include "openbr_plugin.h" |
| 7 | 8 | ||
| 8 | -// Use the provided default implementation of some functions | ||
| 9 | -#include "janus/src/janus.cpp" | ||
| 10 | - | ||
| 11 | using namespace br; | 9 | using namespace br; |
| 12 | 10 | ||
| 13 | static QSharedPointer<Transform> transform; | 11 | static QSharedPointer<Transform> transform; |
| 14 | static QSharedPointer<Distance> distance; | 12 | static QSharedPointer<Distance> distance; |
| 15 | 13 | ||
| 14 | +size_t janus_max_template_size() | ||
| 15 | +{ | ||
| 16 | + return 33554432; // 32 MB | ||
| 17 | +} | ||
| 18 | + | ||
| 16 | janus_error janus_initialize(const char *sdk_path, const char *model_file) | 19 | janus_error janus_initialize(const char *sdk_path, const char *model_file) |
| 17 | { | 20 | { |
| 18 | int argc = 1; | 21 | int argc = 1; |
| 19 | const char *argv[1] = { "janus" }; | 22 | const char *argv[1] = { "janus" }; |
| 20 | Context::initialize(argc, (char**)argv, sdk_path); | 23 | Context::initialize(argc, (char**)argv, sdk_path); |
| 21 | QString algorithm = model_file; | 24 | QString algorithm = model_file; |
| 22 | - if (algorithm.isEmpty()) algorithm = "Cvt(Gray)+Affine(88,88,0.25,0.35)+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>:ByteL1"; | ||
| 23 | - transform = Transform::fromAlgorithm(algorithm, false); | ||
| 24 | - distance = Distance::fromAlgorithm(algorithm); | 25 | + if (algorithm.isEmpty()) { |
| 26 | + transform = Transform::fromAlgorithm("Cvt(Gray)+Affine(88,88,0.25,0.35)+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>", false); | ||
| 27 | + distance = Distance::fromAlgorithm("FaceRecognition"); | ||
| 28 | + } else if (algorithm == "PP5") { | ||
| 29 | + transform.reset(Transform::make("PP5Enroll", NULL)); | ||
| 30 | + distance.reset(Distance::make("PP5Compare", NULL)); | ||
| 31 | + } else { | ||
| 32 | + transform = Transform::fromAlgorithm(algorithm, false); | ||
| 33 | + distance = Distance::fromAlgorithm(algorithm); | ||
| 34 | + } | ||
| 25 | return JANUS_SUCCESS; | 35 | return JANUS_SUCCESS; |
| 26 | } | 36 | } |
| 27 | 37 | ||
| 28 | janus_error janus_finalize() | 38 | janus_error janus_finalize() |
| 29 | { | 39 | { |
| 40 | + transform.reset(); | ||
| 41 | + distance.reset(); | ||
| 30 | Context::finalize(); | 42 | Context::finalize(); |
| 31 | return JANUS_SUCCESS; | 43 | return JANUS_SUCCESS; |
| 32 | } | 44 | } |
| 33 | 45 | ||
| 34 | -struct janus_incomplete_template_type | ||
| 35 | -{ | ||
| 36 | - QList<cv::Mat> data; | ||
| 37 | -}; | 46 | +struct janus_template_type : public Template |
| 47 | +{}; | ||
| 38 | 48 | ||
| 39 | -janus_error janus_initialize_template(janus_incomplete_template *incomplete_template) | 49 | +janus_error janus_initialize_template(janus_template *template_) |
| 40 | { | 50 | { |
| 41 | - *incomplete_template = new janus_incomplete_template_type(); | 51 | + *template_ = new janus_template_type(); |
| 42 | return JANUS_SUCCESS; | 52 | return JANUS_SUCCESS; |
| 43 | } | 53 | } |
| 44 | 54 | ||
| 45 | -janus_error janus_add_image(const janus_image image, const janus_attribute_list attributes, janus_incomplete_template incomplete_template) | 55 | +janus_error janus_augment(const janus_image image, const janus_attribute_list attributes, janus_template template_) |
| 46 | { | 56 | { |
| 47 | Template t; | 57 | Template t; |
| 48 | t.append(cv::Mat(image.height, | 58 | t.append(cv::Mat(image.height, |
| 49 | image.width, | 59 | image.width, |
| 50 | - image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC1, | 60 | + image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC3, |
| 51 | image.data)); | 61 | image.data)); |
| 52 | for (size_t i=0; i<attributes.size; i++) | 62 | for (size_t i=0; i<attributes.size; i++) |
| 53 | t.file.set(janus_attribute_to_string(attributes.attributes[i]), attributes.values[i]); | 63 | t.file.set(janus_attribute_to_string(attributes.attributes[i]), attributes.values[i]); |
| 54 | 64 | ||
| 55 | - if (!t.file.contains("JANUS_RIGHT_EYE_X") || | ||
| 56 | - !t.file.contains("JANUS_RIGHT_EYE_Y") || | ||
| 57 | - !t.file.contains("JANUS_LEFT_EYE_X") || | ||
| 58 | - !t.file.contains("JANUS_LEFT_EYE_Y")) | 65 | + if (!t.file.contains("RIGHT_EYE_X") || |
| 66 | + !t.file.contains("RIGHT_EYE_Y") || | ||
| 67 | + !t.file.contains("LEFT_EYE_X") || | ||
| 68 | + !t.file.contains("LEFT_EYE_Y")) | ||
| 59 | return JANUS_SUCCESS; | 69 | return JANUS_SUCCESS; |
| 60 | 70 | ||
| 61 | - t.file.set("Affine_0", QPointF(t.file.get<float>("JANUS_RIGHT_EYE_X"), t.file.get<float>("JANUS_RIGHT_EYE_Y"))); | ||
| 62 | - t.file.set("Affine_1", QPointF(t.file.get<float>("JANUS_LEFT_EYE_X"), t.file.get<float>("JANUS_LEFT_EYE_Y"))); | 71 | + t.file.set("Affine_0", QPointF(t.file.get<float>("RIGHT_EYE_X"), t.file.get<float>("RIGHT_EYE_Y"))); |
| 72 | + t.file.set("Affine_1", QPointF(t.file.get<float>("LEFT_EYE_X"), t.file.get<float>("LEFT_EYE_Y"))); | ||
| 63 | Template u; | 73 | Template u; |
| 64 | transform->project(t, u); | 74 | transform->project(t, u); |
| 65 | - incomplete_template->data.append(u); | 75 | + template_->append(u); |
| 66 | return JANUS_SUCCESS; | 76 | return JANUS_SUCCESS; |
| 67 | } | 77 | } |
| 68 | 78 | ||
| 69 | -janus_error janus_finalize_template(janus_incomplete_template incomplete_template, janus_template template_, size_t *bytes) | 79 | +janus_error janus_finalize_template(janus_template template_, janus_flat_template flat_template, size_t *bytes) |
| 70 | { | 80 | { |
| 71 | - size_t templateBytes = 0; | ||
| 72 | - size_t numTemplates = 0; | ||
| 73 | - *bytes = sizeof(templateBytes) + sizeof(numTemplates); | ||
| 74 | - janus_template pos = template_ + *bytes; | ||
| 75 | - | ||
| 76 | - foreach (const cv::Mat &m, incomplete_template->data) { | 81 | + foreach (const cv::Mat &m, *template_) { |
| 77 | assert(m.isContinuous()); | 82 | assert(m.isContinuous()); |
| 78 | - const size_t currentTemplateBytes = m.rows * m.cols * m.elemSize(); | ||
| 79 | - if (templateBytes == 0) | ||
| 80 | - templateBytes = currentTemplateBytes; | ||
| 81 | - if (templateBytes != currentTemplateBytes) | ||
| 82 | - return JANUS_UNKNOWN_ERROR; | ||
| 83 | - if (*bytes + templateBytes > janus_max_template_size()) | 83 | + const size_t templateBytes = m.rows * m.cols * m.elemSize(); |
| 84 | + if (*bytes + sizeof(size_t) + templateBytes > janus_max_template_size()) | ||
| 84 | break; | 85 | break; |
| 85 | - memcpy(pos, m.data, templateBytes); | ||
| 86 | - *bytes += templateBytes; | ||
| 87 | - pos = pos + templateBytes; | ||
| 88 | - numTemplates++; | 86 | + memcpy(flat_template, &templateBytes, sizeof(templateBytes)); |
| 87 | + flat_template += sizeof(templateBytes); | ||
| 88 | + memcpy(flat_template, m.data, templateBytes); | ||
| 89 | + flat_template += templateBytes; | ||
| 90 | + *bytes += sizeof(size_t) + templateBytes; | ||
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | - *(reinterpret_cast<size_t*>(template_)+0) = templateBytes; | ||
| 92 | - *(reinterpret_cast<size_t*>(template_)+1) = numTemplates; | ||
| 93 | - delete incomplete_template; | 93 | + delete template_; |
| 94 | return JANUS_SUCCESS; | 94 | return JANUS_SUCCESS; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | -janus_error janus_verify(const janus_template a, const size_t a_bytes, const janus_template b, const size_t b_bytes, double *similarity) | 97 | +janus_error janus_verify(const janus_flat_template a, const size_t a_bytes, const janus_flat_template b, const size_t b_bytes, double *similarity) |
| 98 | { | 98 | { |
| 99 | - (void) a_bytes; | ||
| 100 | - (void) b_bytes; | ||
| 101 | - | ||
| 102 | - size_t a_template_bytes, a_templates, b_template_bytes, b_templates; | ||
| 103 | - a_template_bytes = *(reinterpret_cast<size_t*>(a)+0); | ||
| 104 | - a_templates = *(reinterpret_cast<size_t*>(a)+1); | ||
| 105 | - b_template_bytes = *(reinterpret_cast<size_t*>(b)+0); | ||
| 106 | - b_templates = *(reinterpret_cast<size_t*>(b)+1); | ||
| 107 | - if (a_template_bytes != b_template_bytes) | ||
| 108 | - return JANUS_UNKNOWN_ERROR; | 99 | + *similarity = 0; |
| 109 | 100 | ||
| 110 | - float dist = 0; | ||
| 111 | - for (size_t i=0; i<a_templates; i++) | ||
| 112 | - for (size_t j=0; j<b_templates; j++) | ||
| 113 | - dist += distance->compare(cv::Mat(1, a_template_bytes, CV_8UC1, a+2*sizeof(size_t)+i*a_template_bytes), | ||
| 114 | - cv::Mat(1, b_template_bytes, CV_8UC1, b+2*sizeof(size_t)+i*b_template_bytes)); | ||
| 115 | - *similarity = a_templates * b_templates / dist; | ||
| 116 | - return JANUS_SUCCESS; | ||
| 117 | -} | 101 | + int comparisons = 0; |
| 102 | + janus_flat_template a_template = a; | ||
| 103 | + while (a_template < a + a_bytes) { | ||
| 104 | + const size_t a_template_bytes = *reinterpret_cast<size_t*>(a_template); | ||
| 105 | + a_template += sizeof(a_template_bytes); | ||
| 118 | 106 | ||
| 119 | -struct janus_incomplete_gallery_type | ||
| 120 | -{ | ||
| 121 | - QList< QPair<janus_template, janus_template_id> > templates; | ||
| 122 | -}; | 107 | + janus_flat_template b_template = b; |
| 108 | + while (b_template < b + b_bytes) { | ||
| 109 | + const size_t b_template_bytes = *reinterpret_cast<size_t*>(b_template); | ||
| 110 | + b_template += sizeof(b_template_bytes); | ||
| 123 | 111 | ||
| 124 | -janus_error janus_initialize_gallery(janus_incomplete_gallery *incomplete_gallery) | ||
| 125 | -{ | ||
| 126 | - *incomplete_gallery = new janus_incomplete_gallery_type(); | ||
| 127 | - return JANUS_SUCCESS; | ||
| 128 | -} | 112 | + *similarity += distance->compare(cv::Mat(1, a_template_bytes, CV_8UC1, a_template), |
| 113 | + cv::Mat(1, b_template_bytes, CV_8UC1, b_template)); | ||
| 114 | + comparisons++; | ||
| 129 | 115 | ||
| 130 | -janus_error janus_add_template(const janus_template template_, const size_t bytes, const janus_template_id template_id, janus_incomplete_gallery incomplete_gallery) | ||
| 131 | -{ | ||
| 132 | - (void) bytes; | ||
| 133 | - incomplete_gallery->templates.append(QPair<janus_template, janus_template_id>(template_, template_id)); | 116 | + b_template += b_template_bytes; |
| 117 | + } | ||
| 118 | + | ||
| 119 | + a_template += a_template_bytes; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + if (*similarity != *similarity) // True for NaN | ||
| 123 | + return JANUS_UNKNOWN_ERROR; | ||
| 124 | + | ||
| 125 | + *similarity /= comparisons; | ||
| 134 | return JANUS_SUCCESS; | 126 | return JANUS_SUCCESS; |
| 135 | } | 127 | } |
| 136 | 128 | ||
| 137 | -janus_error janus_finalize_gallery(janus_incomplete_gallery incomplete_gallery, const char *gallery_file) | 129 | +janus_error janus_enroll(const janus_template template_, const janus_template_id template_id, janus_gallery gallery) |
| 138 | { | 130 | { |
| 139 | - (void) incomplete_gallery; | ||
| 140 | - (void) gallery_file; | 131 | + template_->file.set("TEMPLATE_ID", template_id); |
| 132 | + QFile file(gallery); | ||
| 133 | + if (!file.open(QFile::WriteOnly | QFile::Append)) | ||
| 134 | + return JANUS_WRITE_ERROR; | ||
| 135 | + QDataStream stream(&file); | ||
| 136 | + stream << *template_; | ||
| 137 | + file.close(); | ||
| 138 | + delete template_; | ||
| 141 | return JANUS_SUCCESS; | 139 | return JANUS_SUCCESS; |
| 142 | } | 140 | } |
openbr/openbr.cpp
| @@ -24,12 +24,31 @@ | @@ -24,12 +24,31 @@ | ||
| 24 | #include "core/qtutils.h" | 24 | #include "core/qtutils.h" |
| 25 | #include "plugins/openbr_internal.h" | 25 | #include "plugins/openbr_internal.h" |
| 26 | #include <opencv2/highgui/highgui.hpp> | 26 | #include <opencv2/highgui/highgui.hpp> |
| 27 | +#include <opencv2/highgui/highgui_c.h> | ||
| 27 | 28 | ||
| 28 | using namespace br; | 29 | using namespace br; |
| 29 | 30 | ||
| 31 | +static int partialCopy(const QString & string, char * buffer, int buffer_length) | ||
| 32 | +{ | ||
| 33 | + | ||
| 34 | + QByteArray byteArray = string.toLocal8Bit(); | ||
| 35 | + | ||
| 36 | + int copyLength = std::min(buffer_length-1, byteArray.size()); | ||
| 37 | + if (copyLength < 0) | ||
| 38 | + return byteArray.size() + 1; | ||
| 39 | + | ||
| 40 | + memcpy(buffer, byteArray.data(), copyLength); | ||
| 41 | + buffer[copyLength] = '\0'; | ||
| 42 | + | ||
| 43 | + return byteArray.size() + 1; | ||
| 44 | +} | ||
| 45 | + | ||
| 30 | const char *br_about() | 46 | const char *br_about() |
| 31 | { | 47 | { |
| 48 | + static QMutex aboutLock; | ||
| 49 | + QMutexLocker lock(&aboutLock); | ||
| 32 | static QByteArray about = Context::about().toLocal8Bit(); | 50 | static QByteArray about = Context::about().toLocal8Bit(); |
| 51 | + | ||
| 33 | return about.data(); | 52 | return about.data(); |
| 34 | } | 53 | } |
| 35 | 54 | ||
| @@ -121,9 +140,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], | @@ -121,9 +140,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], | ||
| 121 | Fuse(QtUtils::toStringList(num_input_simmats, input_simmats), normalization, fusion, output_simmat); | 140 | Fuse(QtUtils::toStringList(num_input_simmats, input_simmats), normalization, fusion, output_simmat); |
| 122 | } | 141 | } |
| 123 | 142 | ||
| 124 | -void br_initialize(int &argc, char *argv[], const char *sdk_path) | 143 | +void br_initialize(int &argc, char *argv[], const char *sdk_path, bool use_gui) |
| 125 | { | 144 | { |
| 126 | - Context::initialize(argc, argv, sdk_path); | 145 | + Context::initialize(argc, argv, sdk_path, use_gui); |
| 127 | } | 146 | } |
| 128 | 147 | ||
| 129 | void br_initialize_default() | 148 | void br_initialize_default() |
| @@ -149,53 +168,14 @@ void br_make_pairwise_mask(const char *target_input, const char *query_input, co | @@ -149,53 +168,14 @@ void br_make_pairwise_mask(const char *target_input, const char *query_input, co | ||
| 149 | BEE::makePairwiseMask(target_input, query_input, mask); | 168 | BEE::makePairwiseMask(target_input, query_input, mask); |
| 150 | } | 169 | } |
| 151 | 170 | ||
| 152 | -const char *br_most_recent_message() | 171 | +int br_most_recent_message(char * buffer, int buffer_length) |
| 153 | { | 172 | { |
| 154 | - static QByteArray byteArray; | ||
| 155 | - byteArray = Globals->mostRecentMessage.toLocal8Bit(); | ||
| 156 | - return byteArray.data(); | 173 | + return partialCopy(Globals->mostRecentMessage, buffer, buffer_length); |
| 157 | } | 174 | } |
| 158 | 175 | ||
| 159 | -const char *br_objects(const char *abstractions, const char *implementations, bool parameters) | 176 | +int br_objects(char * buffer, int buffer_length, const char *abstractions, const char *implementations, bool parameters) |
| 160 | { | 177 | { |
| 161 | - static QByteArray objects; | ||
| 162 | - | ||
| 163 | - QStringList objectList; | ||
| 164 | - QRegExp abstractionsRegExp(abstractions); | ||
| 165 | - QRegExp implementationsRegExp(implementations); | ||
| 166 | - | ||
| 167 | - if (abstractionsRegExp.exactMatch("Abbreviation")) | ||
| 168 | - foreach (const QString &name, Globals->abbreviations.keys()) | ||
| 169 | - if (implementationsRegExp.exactMatch(name)) | ||
| 170 | - objectList.append(name + (parameters ? "\t" + Globals->abbreviations[name] : "")); | ||
| 171 | - | ||
| 172 | - if (abstractionsRegExp.exactMatch("Distance")) | ||
| 173 | - foreach (const QString &name, Factory<Distance>::names()) | ||
| 174 | - if (implementationsRegExp.exactMatch(name)) | ||
| 175 | - objectList.append(name + (parameters ? "\t" + Factory<Distance>::parameters(name) : "")); | ||
| 176 | - | ||
| 177 | - if (abstractionsRegExp.exactMatch("Format")) | ||
| 178 | - foreach (const QString &name, Factory<Format>::names()) | ||
| 179 | - if (implementationsRegExp.exactMatch(name)) | ||
| 180 | - objectList.append(name + (parameters ? "\t" + Factory<Format>::parameters(name) : "")); | ||
| 181 | - | ||
| 182 | - if (abstractionsRegExp.exactMatch("Initializer")) | ||
| 183 | - foreach (const QString &name, Factory<Initializer>::names()) | ||
| 184 | - if (implementationsRegExp.exactMatch(name)) | ||
| 185 | - objectList.append(name + (parameters ? "\t" + Factory<Initializer>::parameters(name) : "")); | ||
| 186 | - | ||
| 187 | - if (abstractionsRegExp.exactMatch("Output")) | ||
| 188 | - foreach (const QString &name, Factory<Output>::names()) | ||
| 189 | - if (implementationsRegExp.exactMatch(name)) | ||
| 190 | - objectList.append(name + (parameters ? "\t" + Factory<Output>::parameters(name) : "")); | ||
| 191 | - | ||
| 192 | - if (abstractionsRegExp.exactMatch("Transform")) | ||
| 193 | - foreach (const QString &name, Factory<Transform>::names()) | ||
| 194 | - if (implementationsRegExp.exactMatch(name)) | ||
| 195 | - objectList.append(name + (parameters ? "\t" + Factory<Transform>::parameters(name) : "")); | ||
| 196 | - | ||
| 197 | - objects = objectList.join("\n").toLocal8Bit(); | ||
| 198 | - return objects.data(); | 178 | + return partialCopy(br::Context::objects(abstractions, implementations, parameters).join('\n'), buffer, buffer_length); |
| 199 | } | 179 | } |
| 200 | 180 | ||
| 201 | bool br_plot(int num_files, const char *files[], const char *destination, bool show) | 181 | bool br_plot(int num_files, const char *files[], const char *destination, bool show) |
| @@ -250,15 +230,15 @@ void br_read_pipe(const char *pipe, int *argc, char ***argv) | @@ -250,15 +230,15 @@ void br_read_pipe(const char *pipe, int *argc, char ***argv) | ||
| 250 | *argv = rawCharArrayList.data(); | 230 | *argv = rawCharArrayList.data(); |
| 251 | } | 231 | } |
| 252 | 232 | ||
| 253 | -const char *br_scratch_path() | 233 | +int br_scratch_path(char * buffer, int buffer_length) |
| 254 | { | 234 | { |
| 255 | - static QByteArray byteArray; | ||
| 256 | - byteArray = Context::scratchPath().toLocal8Bit(); | ||
| 257 | - return byteArray.data(); | 235 | + return partialCopy(Context::scratchPath(), buffer, buffer_length); |
| 258 | } | 236 | } |
| 259 | 237 | ||
| 260 | const char *br_sdk_path() | 238 | const char *br_sdk_path() |
| 261 | { | 239 | { |
| 240 | + static QMutex sdkLock; | ||
| 241 | + QMutexLocker lock(&sdkLock); | ||
| 262 | static QByteArray sdkPath = QDir(Globals->sdkPath).absolutePath().toLocal8Bit(); | 242 | static QByteArray sdkPath = QDir(Globals->sdkPath).absolutePath().toLocal8Bit(); |
| 263 | return sdkPath.data(); | 243 | return sdkPath.data(); |
| 264 | } | 244 | } |
| @@ -302,6 +282,8 @@ void br_train_n(int num_inputs, const char *inputs[], const char *model) | @@ -302,6 +282,8 @@ void br_train_n(int num_inputs, const char *inputs[], const char *model) | ||
| 302 | 282 | ||
| 303 | const char *br_version() | 283 | const char *br_version() |
| 304 | { | 284 | { |
| 285 | + static QMutex versionLock; | ||
| 286 | + QMutexLocker lock(&versionLock); | ||
| 305 | static QByteArray version = Context::version().toLocal8Bit(); | 287 | static QByteArray version = Context::version().toLocal8Bit(); |
| 306 | return version.data(); | 288 | return version.data(); |
| 307 | } | 289 | } |
| @@ -379,10 +361,9 @@ bool br_img_is_empty(br_template tmpl) | @@ -379,10 +361,9 @@ bool br_img_is_empty(br_template tmpl) | ||
| 379 | return t->m().empty(); | 361 | return t->m().empty(); |
| 380 | } | 362 | } |
| 381 | 363 | ||
| 382 | -const char* br_get_filename(br_template tmpl) | 364 | +int br_get_filename(char * buffer, int buffer_length, br_template tmpl) |
| 383 | { | 365 | { |
| 384 | - Template *t = reinterpret_cast<Template*>(tmpl); | ||
| 385 | - return t->file.name.toStdString().c_str(); | 366 | + return partialCopy(reinterpret_cast<Template*>(tmpl)->file.name, buffer, buffer_length); |
| 386 | } | 367 | } |
| 387 | 368 | ||
| 388 | void br_set_filename(br_template tmpl, const char *filename) | 369 | void br_set_filename(br_template tmpl, const char *filename) |
| @@ -391,15 +372,11 @@ void br_set_filename(br_template tmpl, const char *filename) | @@ -391,15 +372,11 @@ void br_set_filename(br_template tmpl, const char *filename) | ||
| 391 | t->file.name = filename; | 372 | t->file.name = filename; |
| 392 | } | 373 | } |
| 393 | 374 | ||
| 394 | -const char* br_get_metadata_string(br_template tmpl, const char *key) | 375 | +int br_get_metadata_string(char * buffer, int buffer_length, br_template tmpl, const char *key) |
| 395 | { | 376 | { |
| 396 | Template *t = reinterpret_cast<Template*>(tmpl); | 377 | Template *t = reinterpret_cast<Template*>(tmpl); |
| 397 | - // need an object outside of this scope | ||
| 398 | - // so the char pointer is valid | ||
| 399 | - static QByteArray result; | ||
| 400 | QVariant qvar = t->file.value(key); | 378 | QVariant qvar = t->file.value(key); |
| 401 | - result = QtUtils::toString(qvar).toUtf8(); | ||
| 402 | - return result.data(); | 379 | + return partialCopy(QtUtils::toString(qvar), buffer, buffer_length); |
| 403 | } | 380 | } |
| 404 | 381 | ||
| 405 | br_template_list br_enroll_template(br_template tmpl) | 382 | br_template_list br_enroll_template(br_template tmpl) |
| @@ -470,3 +447,8 @@ void br_close_gallery(br_gallery gallery) | @@ -470,3 +447,8 @@ void br_close_gallery(br_gallery gallery) | ||
| 470 | Gallery *gal = reinterpret_cast<Gallery*>(gallery); | 447 | Gallery *gal = reinterpret_cast<Gallery*>(gallery); |
| 471 | delete gal; | 448 | delete gal; |
| 472 | } | 449 | } |
| 450 | + | ||
| 451 | +void br_deduplicate(const char *input_gallery, const char *output_gallery, const char *threshold) | ||
| 452 | +{ | ||
| 453 | + br::Deduplicate(input_gallery, output_gallery, threshold); | ||
| 454 | +} |
openbr/openbr.h
| @@ -41,6 +41,10 @@ extern "C" { | @@ -41,6 +41,10 @@ extern "C" { | ||
| 41 | * \section managed_return_value Managed Return Value | 41 | * \section managed_return_value Managed Return Value |
| 42 | * Memory for <tt>const char*</tt> return values is managed internally and guaranteed until the next call to the function. | 42 | * Memory for <tt>const char*</tt> return values is managed internally and guaranteed until the next call to the function. |
| 43 | * | 43 | * |
| 44 | + * \section input_string_buffer Input String Buffer | ||
| 45 | + * Users should input a char * buffer and the size of that buffer. String data will be copied into the buffer, if the buffer is too | ||
| 46 | + * small, only part of the string will be copied. Returns the buffer size required to contain the complete string. | ||
| 47 | + * | ||
| 44 | * \section examples Examples | 48 | * \section examples Examples |
| 45 | * - \ref c_face_recognition_evaluation | 49 | * - \ref c_face_recognition_evaluation |
| 46 | * | 50 | * |
| @@ -56,7 +60,6 @@ extern "C" { | @@ -56,7 +60,6 @@ extern "C" { | ||
| 56 | 60 | ||
| 57 | /*! | 61 | /*! |
| 58 | * \brief Wraps br::Context::about() | 62 | * \brief Wraps br::Context::about() |
| 59 | - * \note \ref managed_return_value | ||
| 60 | * \see br_version | 63 | * \see br_version |
| 61 | */ | 64 | */ |
| 62 | BR_EXPORT const char *br_about(); | 65 | BR_EXPORT const char *br_about(); |
| @@ -67,6 +70,17 @@ BR_EXPORT const char *br_about(); | @@ -67,6 +70,17 @@ BR_EXPORT const char *br_about(); | ||
| 67 | BR_EXPORT void br_cat(int num_input_galleries, const char *input_galleries[], const char *output_gallery); | 70 | BR_EXPORT void br_cat(int num_input_galleries, const char *input_galleries[], const char *output_gallery); |
| 68 | 71 | ||
| 69 | /*! | 72 | /*! |
| 73 | + * \brief Removes duplicate templates in a gallery. | ||
| 74 | + * \param input_gallery Gallery to be deduplicated. | ||
| 75 | + * \param output_gallery Deduplicated gallery. | ||
| 76 | + * \param threshold Comparisons with a match score >= this value are designated to be duplicates. | ||
| 77 | + * \note If a gallery contains n duplicates, the first n-1 duplicates in the gallery will be removed and the nth will be kept. | ||
| 78 | + * \note Users are encouraged to use binary gallery formats as the entire gallery is read into memory in one call to Gallery::read. | ||
| 79 | + */ | ||
| 80 | + | ||
| 81 | +BR_EXPORT void br_deduplicate(const char *input_gallery, const char *output_gallery, const char *threshold); | ||
| 82 | + | ||
| 83 | +/*! | ||
| 70 | * \brief Clusters one or more similarity matrices into a list of subjects. | 84 | * \brief Clusters one or more similarity matrices into a list of subjects. |
| 71 | * | 85 | * |
| 72 | * A similarity matrix is a type of br::Output. The current clustering algorithm is a simplified implementation of \cite zhu11. | 86 | * A similarity matrix is a type of br::Output. The current clustering algorithm is a simplified implementation of \cite zhu11. |
| @@ -213,7 +227,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], | @@ -213,7 +227,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], | ||
| 213 | * \brief Wraps br::Context::initialize() | 227 | * \brief Wraps br::Context::initialize() |
| 214 | * \see br_finalize | 228 | * \see br_finalize |
| 215 | */ | 229 | */ |
| 216 | -BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = ""); | 230 | +BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = "", bool use_gui = false); |
| 217 | /*! | 231 | /*! |
| 218 | * \brief Wraps br::Context::initialize() with default arguments. | 232 | * \brief Wraps br::Context::initialize() with default arguments. |
| 219 | * \see br_finalize | 233 | * \see br_finalize |
| @@ -245,10 +259,10 @@ BR_EXPORT void br_make_pairwise_mask(const char *target_input, const char *query | @@ -245,10 +259,10 @@ BR_EXPORT void br_make_pairwise_mask(const char *target_input, const char *query | ||
| 245 | 259 | ||
| 246 | /*! | 260 | /*! |
| 247 | * \brief Returns the most recent line sent to stderr. | 261 | * \brief Returns the most recent line sent to stderr. |
| 248 | - * \note \ref managed_return_value | 262 | + * \note \ref input_string_buffer |
| 249 | * \see br_progress br_time_remaining | 263 | * \see br_progress br_time_remaining |
| 250 | */ | 264 | */ |
| 251 | -BR_EXPORT const char *br_most_recent_message(); | 265 | +BR_EXPORT int br_most_recent_message(char * buffer, int buffer_length); |
| 252 | 266 | ||
| 253 | /*! | 267 | /*! |
| 254 | * \brief Returns names and parameters for the requested objects. | 268 | * \brief Returns names and parameters for the requested objects. |
| @@ -257,10 +271,10 @@ BR_EXPORT const char *br_most_recent_message(); | @@ -257,10 +271,10 @@ BR_EXPORT const char *br_most_recent_message(); | ||
| 257 | * \param abstractions Regular expression of the abstractions to search. | 271 | * \param abstractions Regular expression of the abstractions to search. |
| 258 | * \param implementations Regular expression of the implementations to search. | 272 | * \param implementations Regular expression of the implementations to search. |
| 259 | * \param parameters Include parameters after object name. | 273 | * \param parameters Include parameters after object name. |
| 260 | - * \note \ref managed_return_value | 274 | + * \note \ref input_string_buffer |
| 261 | * \note This function uses Qt's <a href="http://doc.qt.digia.com/stable/qregexp.html">QRegExp</a> syntax. | 275 | * \note This function uses Qt's <a href="http://doc.qt.digia.com/stable/qregexp.html">QRegExp</a> syntax. |
| 262 | */ | 276 | */ |
| 263 | -BR_EXPORT const char *br_objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true); | 277 | +BR_EXPORT int br_objects(char * buffer, int buffer_length, const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true); |
| 264 | 278 | ||
| 265 | /*! | 279 | /*! |
| 266 | * \brief Renders recognition performance figures for a set of <tt>.csv</tt> files created by \ref br_eval. | 280 | * \brief Renders recognition performance figures for a set of <tt>.csv</tt> files created by \ref br_eval. |
| @@ -365,14 +379,14 @@ BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv); | @@ -365,14 +379,14 @@ BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv); | ||
| 365 | 379 | ||
| 366 | /*! | 380 | /*! |
| 367 | * \brief Wraps br::Context::scratchPath() | 381 | * \brief Wraps br::Context::scratchPath() |
| 368 | - * \note \ref managed_return_value | 382 | + * \note \ref input_string_buffer |
| 369 | * \see br_version | 383 | * \see br_version |
| 370 | */ | 384 | */ |
| 371 | -BR_EXPORT const char *br_scratch_path(); | 385 | +BR_EXPORT int br_scratch_path(char * buffer, int buffer_length); |
| 386 | + | ||
| 372 | 387 | ||
| 373 | /*! | 388 | /*! |
| 374 | * \brief Returns the full path to the root of the SDK. | 389 | * \brief Returns the full path to the root of the SDK. |
| 375 | - * \note \ref managed_return_value | ||
| 376 | * \see br_initialize | 390 | * \see br_initialize |
| 377 | */ | 391 | */ |
| 378 | BR_EXPORT const char *br_sdk_path(); | 392 | BR_EXPORT const char *br_sdk_path(); |
| @@ -425,7 +439,6 @@ BR_EXPORT void br_train_n(int num_inputs, const char *inputs[], const char *mode | @@ -425,7 +439,6 @@ BR_EXPORT void br_train_n(int num_inputs, const char *inputs[], const char *mode | ||
| 425 | 439 | ||
| 426 | /*! | 440 | /*! |
| 427 | * \brief Wraps br::Context::version() | 441 | * \brief Wraps br::Context::version() |
| 428 | - * \note \ref managed_return_value | ||
| 429 | * \see br_about br_scratch_path | 442 | * \see br_about br_scratch_path |
| 430 | */ | 443 | */ |
| 431 | BR_EXPORT const char *br_version(); | 444 | BR_EXPORT const char *br_version(); |
| @@ -497,16 +510,18 @@ BR_EXPORT int br_img_channels(br_template tmpl); | @@ -497,16 +510,18 @@ BR_EXPORT int br_img_channels(br_template tmpl); | ||
| 497 | BR_EXPORT bool br_img_is_empty(br_template tmpl); | 510 | BR_EXPORT bool br_img_is_empty(br_template tmpl); |
| 498 | /*! | 511 | /*! |
| 499 | * \brief Get the filename for a br::Template | 512 | * \brief Get the filename for a br::Template |
| 513 | + * \note \ref input_string_buffer | ||
| 500 | */ | 514 | */ |
| 501 | -BR_EXPORT const char* br_get_filename(br_template tmpl); | 515 | +BR_EXPORT int br_get_filename(char * buffer, int buffer_length, br_template tmpl); |
| 502 | /*! | 516 | /*! |
| 503 | * \brief Set the filename for a br::Template. | 517 | * \brief Set the filename for a br::Template. |
| 504 | */ | 518 | */ |
| 505 | BR_EXPORT void br_set_filename(br_template tmpl, const char *filename); | 519 | BR_EXPORT void br_set_filename(br_template tmpl, const char *filename); |
| 506 | /*! | 520 | /*! |
| 507 | * \brief Get metadata as a string for the given key in the given template. | 521 | * \brief Get metadata as a string for the given key in the given template. |
| 522 | + * \note \ref input_string_buffer | ||
| 508 | */ | 523 | */ |
| 509 | -BR_EXPORT const char* br_get_metadata_string(br_template, const char *key); | 524 | +BR_EXPORT int br_get_metadata_string(char * buffer, int buffer_length, br_template tmpl, const char *key); |
| 510 | /*! | 525 | /*! |
| 511 | * \brief Enroll a br::Template from the C API! Returns a pointer to a br::TemplateList | 526 | * \brief Enroll a br::Template from the C API! Returns a pointer to a br::TemplateList |
| 512 | * \param tmpl Pointer to a br::Template. | 527 | * \param tmpl Pointer to a br::Template. |
openbr/openbr_plugin.cpp
| @@ -203,6 +203,13 @@ QList<QRectF> File::namedRects() const | @@ -203,6 +203,13 @@ QList<QRectF> File::namedRects() const | ||
| 203 | const QVariant &variant = m_metadata[key]; | 203 | const QVariant &variant = m_metadata[key]; |
| 204 | if (variant.canConvert<QRectF>()) | 204 | if (variant.canConvert<QRectF>()) |
| 205 | rects.append(variant.value<QRectF>()); | 205 | rects.append(variant.value<QRectF>()); |
| 206 | + else if(variant.canConvert<QList<QRectF> >()) { | ||
| 207 | + QList<QRectF> list = variant.value<QList<QRectF> >(); | ||
| 208 | + for (int i=0;i < list.size();i++) | ||
| 209 | + { | ||
| 210 | + rects.append(list[i]); | ||
| 211 | + } | ||
| 212 | + } | ||
| 206 | } | 213 | } |
| 207 | return rects; | 214 | return rects; |
| 208 | } | 215 | } |
| @@ -392,7 +399,12 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | @@ -392,7 +399,12 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | ||
| 392 | 399 | ||
| 393 | const int crossValidate = gallery.get<int>("crossValidate"); | 400 | const int crossValidate = gallery.get<int>("crossValidate"); |
| 394 | 401 | ||
| 395 | - if (gallery.getBool("leaveOneImageOut")) { | 402 | + // The leaveOneImageOut flag is used when we want to train on n-1 of a subject's images |
| 403 | + // Thus, we find all the images for a particular subject, and set their partitions based on | ||
| 404 | + // the crossValidate parameter | ||
| 405 | + // Note that when the number of images per subject varies from subject to subject | ||
| 406 | + // the number of subjects will decrease as the partition increases | ||
| 407 | + if (gallery.getBool("leaveOneImageOut") && crossValidate > 0) { | ||
| 396 | QStringList labels; | 408 | QStringList labels; |
| 397 | for (int i=newTemplates.size()-1; i>=0; i--) { | 409 | for (int i=newTemplates.size()-1; i>=0; i--) { |
| 398 | newTemplates[i].file.set("Index", i+templates.size()); | 410 | newTemplates[i].file.set("Index", i+templates.size()); |
| @@ -414,7 +426,7 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | @@ -414,7 +426,7 @@ TemplateList TemplateList::fromGallery(const br::File &gallery) | ||
| 414 | Template leaveOneImageOutTemplate = newTemplates[labelIndices[j]]; | 426 | Template leaveOneImageOutTemplate = newTemplates[labelIndices[j]]; |
| 415 | if (k!=leaveOneImageOutTemplate.file.get<int>("Partition")) { | 427 | if (k!=leaveOneImageOutTemplate.file.get<int>("Partition")) { |
| 416 | leaveOneImageOutTemplate.file.set("Partition", k); | 428 | leaveOneImageOutTemplate.file.set("Partition", k); |
| 417 | - leaveOneImageOutTemplate.file.set("testOnly", true); | 429 | + leaveOneImageOutTemplate.file.set("targetOnly", true); |
| 418 | newTemplates.insert(i+1,leaveOneImageOutTemplate); | 430 | newTemplates.insert(i+1,leaveOneImageOutTemplate); |
| 419 | } | 431 | } |
| 420 | } | 432 | } |
| @@ -899,8 +911,12 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useG | @@ -899,8 +911,12 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useG | ||
| 899 | { | 911 | { |
| 900 | qInstallMessageHandler(messageHandler); | 912 | qInstallMessageHandler(messageHandler); |
| 901 | 913 | ||
| 914 | + QString sep; | ||
| 902 | #ifndef _WIN32 | 915 | #ifndef _WIN32 |
| 903 | useGui = useGui && (getenv("DISPLAY") != NULL); | 916 | useGui = useGui && (getenv("DISPLAY") != NULL); |
| 917 | + sep = ":"; | ||
| 918 | +#else | ||
| 919 | + sep = ";"; | ||
| 904 | #endif // not _WIN32 | 920 | #endif // not _WIN32 |
| 905 | 921 | ||
| 906 | // We take in argc as a reference due to: | 922 | // We take in argc as a reference due to: |
| @@ -944,6 +960,7 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useG | @@ -944,6 +960,7 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useG | ||
| 944 | // Search for SDK | 960 | // Search for SDK |
| 945 | if (sdkPath.isEmpty()) { | 961 | if (sdkPath.isEmpty()) { |
| 946 | QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); | 962 | QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); |
| 963 | + checkPaths << QString(getenv("PATH")).split(sep, QString::SkipEmptyParts); | ||
| 947 | 964 | ||
| 948 | bool foundSDK = false; | 965 | bool foundSDK = false; |
| 949 | foreach (const QString &path, checkPaths) { | 966 | foreach (const QString &path, checkPaths) { |
| @@ -999,6 +1016,47 @@ QString br::Context::scratchPath() | @@ -999,6 +1016,47 @@ QString br::Context::scratchPath() | ||
| 999 | return QString("%1/%2-%3.%4").arg(QDir::homePath(), PRODUCT_NAME, QString::number(PRODUCT_VERSION_MAJOR), QString::number(PRODUCT_VERSION_MINOR)); | 1016 | return QString("%1/%2-%3.%4").arg(QDir::homePath(), PRODUCT_NAME, QString::number(PRODUCT_VERSION_MAJOR), QString::number(PRODUCT_VERSION_MINOR)); |
| 1000 | } | 1017 | } |
| 1001 | 1018 | ||
| 1019 | + | ||
| 1020 | +QStringList br::Context::objects(const char *abstractions, const char *implementations, bool parameters) | ||
| 1021 | +{ | ||
| 1022 | + QStringList objectList; | ||
| 1023 | + QRegExp abstractionsRegExp(abstractions); | ||
| 1024 | + QRegExp implementationsRegExp(implementations); | ||
| 1025 | + | ||
| 1026 | + if (abstractionsRegExp.exactMatch("Abbreviation")) | ||
| 1027 | + foreach (const QString &name, Globals->abbreviations.keys()) | ||
| 1028 | + if (implementationsRegExp.exactMatch(name)) | ||
| 1029 | + objectList.append(name + (parameters ? "\t" + Globals->abbreviations[name] : "")); | ||
| 1030 | + | ||
| 1031 | + if (abstractionsRegExp.exactMatch("Distance")) | ||
| 1032 | + foreach (const QString &name, Factory<Distance>::names()) | ||
| 1033 | + if (implementationsRegExp.exactMatch(name)) | ||
| 1034 | + objectList.append(name + (parameters ? "\t" + Factory<Distance>::parameters(name) : "")); | ||
| 1035 | + | ||
| 1036 | + if (abstractionsRegExp.exactMatch("Format")) | ||
| 1037 | + foreach (const QString &name, Factory<Format>::names()) | ||
| 1038 | + if (implementationsRegExp.exactMatch(name)) | ||
| 1039 | + objectList.append(name + (parameters ? "\t" + Factory<Format>::parameters(name) : "")); | ||
| 1040 | + | ||
| 1041 | + if (abstractionsRegExp.exactMatch("Initializer")) | ||
| 1042 | + foreach (const QString &name, Factory<Initializer>::names()) | ||
| 1043 | + if (implementationsRegExp.exactMatch(name)) | ||
| 1044 | + objectList.append(name + (parameters ? "\t" + Factory<Initializer>::parameters(name) : "")); | ||
| 1045 | + | ||
| 1046 | + if (abstractionsRegExp.exactMatch("Output")) | ||
| 1047 | + foreach (const QString &name, Factory<Output>::names()) | ||
| 1048 | + if (implementationsRegExp.exactMatch(name)) | ||
| 1049 | + objectList.append(name + (parameters ? "\t" + Factory<Output>::parameters(name) : "")); | ||
| 1050 | + | ||
| 1051 | + if (abstractionsRegExp.exactMatch("Transform")) | ||
| 1052 | + foreach (const QString &name, Factory<Transform>::names()) | ||
| 1053 | + if (implementationsRegExp.exactMatch(name)) | ||
| 1054 | + objectList.append(name + (parameters ? "\t" + Factory<Transform>::parameters(name) : "")); | ||
| 1055 | + | ||
| 1056 | + | ||
| 1057 | + return objectList; | ||
| 1058 | +} | ||
| 1059 | + | ||
| 1002 | void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) | 1060 | void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) |
| 1003 | { | 1061 | { |
| 1004 | // Something about this method is not thread safe, and will lead to crashes if qDebug | 1062 | // Something about this method is not thread safe, and will lead to crashes if qDebug |
openbr/openbr_plugin.h
| @@ -41,6 +41,7 @@ | @@ -41,6 +41,7 @@ | ||
| 41 | #include <QVector> | 41 | #include <QVector> |
| 42 | #include <opencv2/core/core.hpp> | 42 | #include <opencv2/core/core.hpp> |
| 43 | #include <openbr/openbr.h> | 43 | #include <openbr/openbr.h> |
| 44 | +#include <assert.h> | ||
| 44 | 45 | ||
| 45 | /*! | 46 | /*! |
| 46 | * \defgroup cpp_plugin_sdk C++ Plugin SDK | 47 | * \defgroup cpp_plugin_sdk C++ Plugin SDK |
| @@ -829,6 +830,18 @@ public: | @@ -829,6 +830,18 @@ public: | ||
| 829 | */ | 830 | */ |
| 830 | static QString scratchPath(); | 831 | static QString scratchPath(); |
| 831 | 832 | ||
| 833 | + /*! | ||
| 834 | + * \brief Returns names and parameters for the requested objects. | ||
| 835 | + * | ||
| 836 | + * Each object is \c \\n seperated. Arguments are seperated from the object name with a \c \\t. | ||
| 837 | + * \param abstractions Regular expression of the abstractions to search. | ||
| 838 | + * \param implementations Regular expression of the implementations to search. | ||
| 839 | + * \param parameters Include parameters after object name. | ||
| 840 | + * \note \ref managed_return_value | ||
| 841 | + * \note This function uses Qt's <a href="http://doc.qt.digia.com/stable/qregexp.html">QRegExp</a> syntax. | ||
| 842 | + */ | ||
| 843 | + static QStringList objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true); | ||
| 844 | + | ||
| 832 | private: | 845 | private: |
| 833 | static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); | 846 | static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); |
| 834 | }; | 847 | }; |
| @@ -1371,6 +1384,14 @@ BR_EXPORT void Convert(const File &fileType, const File &inputFile, const File & | @@ -1371,6 +1384,14 @@ BR_EXPORT void Convert(const File &fileType, const File &inputFile, const File & | ||
| 1371 | */ | 1384 | */ |
| 1372 | BR_EXPORT void Cat(const QStringList &inputGalleries, const QString &outputGallery); | 1385 | BR_EXPORT void Cat(const QStringList &inputGalleries, const QString &outputGallery); |
| 1373 | 1386 | ||
| 1387 | +/*! | ||
| 1388 | + * \brief Deduplicate a gallery. | ||
| 1389 | + * \param inputGallery Gallery to deduplicate. | ||
| 1390 | + * \param outputGallery Gallery to store the deduplicated result. | ||
| 1391 | + * \param threshold Match score threshold to determine duplicates. | ||
| 1392 | + */ | ||
| 1393 | +BR_EXPORT void Deduplicate(const File &inputGallery, const File &outputGallery, const QString &threshold); | ||
| 1394 | + | ||
| 1374 | /*! @}*/ | 1395 | /*! @}*/ |
| 1375 | 1396 | ||
| 1376 | } // namespace br | 1397 | } // namespace br |
openbr/plugins/algorithms.cpp
| @@ -50,6 +50,9 @@ class AlgorithmsInitializer : public Initializer | @@ -50,6 +50,9 @@ class AlgorithmsInitializer : public Initializer | ||
| 50 | Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)"); | 50 | Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)"); |
| 51 | Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)"); | 51 | Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)"); |
| 52 | Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)"); | 52 | Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)"); |
| 53 | + Globals->abbreviations.insert("ShowOpticalFlowField", "Stream(SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard)"); | ||
| 54 | + Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "Stream(AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard)"); | ||
| 55 | + Globals->abbreviations.insert("ShowMotionSegmentation", "Stream(DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard)"); | ||
| 53 | 56 | ||
| 54 | Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); | 57 | Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); |
| 55 | Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); | 58 | Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); |
| @@ -76,7 +79,7 @@ class AlgorithmsInitializer : public Initializer | @@ -76,7 +79,7 @@ class AlgorithmsInitializer : public Initializer | ||
| 76 | Globals->abbreviations.insert("ColoredLBP", "Open+Affine(128,128,0.37,0.45)+Cvt(Gray)+Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+ColoredU2"); | 79 | Globals->abbreviations.insert("ColoredLBP", "Open+Affine(128,128,0.37,0.45)+Cvt(Gray)+Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+ColoredU2"); |
| 77 | 80 | ||
| 78 | // Transforms | 81 | // Transforms |
| 79 | - Globals->abbreviations.insert("FaceDetection", "(Open+Cvt(Gray)+Cascade(FrontalFace))"); | 82 | + Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)"); |
| 80 | Globals->abbreviations.insert("DenseLBP", "(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))"); | 83 | Globals->abbreviations.insert("DenseLBP", "(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))"); |
| 81 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); | 84 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); |
| 82 | Globals->abbreviations.insert("FaceRecognitionRegistration", "(ASEFEyes+Affine(88,88,0.25,0.35)+DownsampleTraining(FTE(DFFS),instances=1))"); | 85 | Globals->abbreviations.insert("FaceRecognitionRegistration", "(ASEFEyes+Affine(88,88,0.25,0.35)+DownsampleTraining(FTE(DFFS),instances=1))"); |
openbr/plugins/cascade.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/objdetect/objdetect.hpp> | 17 | #include <opencv2/objdetect/objdetect.hpp> |
| 18 | +//#include <opencv2/objdetect/objdetect_c.h> | ||
| 18 | #include "openbr_internal.h" | 19 | #include "openbr_internal.h" |
| 19 | #include "openbr/core/opencvutils.h" | 20 | #include "openbr/core/opencvutils.h" |
| 20 | #include "openbr/core/resource.h" | 21 | #include "openbr/core/resource.h" |
| @@ -86,11 +87,11 @@ class CascadeTransform : public UntrainableMetaTransform | @@ -86,11 +87,11 @@ class CascadeTransform : public UntrainableMetaTransform | ||
| 86 | 87 | ||
| 87 | for (int i=0; i<t.size(); i++) { | 88 | for (int i=0; i<t.size(); i++) { |
| 88 | const Mat &m = t[i]; | 89 | const Mat &m = t[i]; |
| 89 | - vector<Rect> rects; | ||
| 90 | - vector<int> rejectLevels; | ||
| 91 | - vector<double> levelWeights; | ||
| 92 | - if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, 5, (enrollAll ? 0 : CV_HAAR_FIND_BIGGEST_OBJECT) | CV_HAAR_SCALE_IMAGE, Size(minSize, minSize), Size(), true); | ||
| 93 | - else cascade->detectMultiScale(m, rects, 1.2, 5, enrollAll ? 0 : CV_HAAR_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); | 90 | + std::vector<Rect> rects; |
| 91 | + std::vector<int> rejectLevels; | ||
| 92 | + std::vector<double> levelWeights; | ||
| 93 | + if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, 5, (enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT) | CASCADE_SCALE_IMAGE, Size(minSize, minSize), Size(), true); | ||
| 94 | + else cascade->detectMultiScale(m, rects, 1.2, 5, enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); | ||
| 94 | 95 | ||
| 95 | if (!enrollAll && rects.empty()) | 96 | if (!enrollAll && rects.empty()) |
| 96 | rects.push_back(Rect(0, 0, m.cols, m.rows)); | 97 | rects.push_back(Rect(0, 0, m.cols, m.rows)); |
openbr/plugins/cvt.cpp
| @@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
| 14 | * limitations under the License. * | 14 | * limitations under the License. * |
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 18 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | #include "openbr_internal.h" | 19 | #include "openbr_internal.h" |
| 19 | #include "openbr/core/opencvutils.h" | 20 | #include "openbr/core/opencvutils.h" |
| @@ -44,7 +45,8 @@ public: | @@ -44,7 +45,8 @@ public: | ||
| 44 | Luv = CV_BGR2Luv, | 45 | Luv = CV_BGR2Luv, |
| 45 | RGB = CV_BGR2RGB, | 46 | RGB = CV_BGR2RGB, |
| 46 | XYZ = CV_BGR2XYZ, | 47 | XYZ = CV_BGR2XYZ, |
| 47 | - YCrCb = CV_BGR2YCrCb }; | 48 | + YCrCb = CV_BGR2YCrCb, |
| 49 | + Color = CV_GRAY2BGR }; | ||
| 48 | 50 | ||
| 49 | private: | 51 | private: |
| 50 | BR_PROPERTY(ColorSpace, colorSpace, Gray) | 52 | BR_PROPERTY(ColorSpace, colorSpace, Gray) |
| @@ -52,8 +54,8 @@ private: | @@ -52,8 +54,8 @@ private: | ||
| 52 | 54 | ||
| 53 | void project(const Template &src, Template &dst) const | 55 | void project(const Template &src, Template &dst) const |
| 54 | { | 56 | { |
| 55 | - if (src.m().channels() > 1) cvtColor(src, dst, colorSpace); | ||
| 56 | - else dst = src; | 57 | + if (src.m().channels() > 1 || colorSpace == CV_GRAY2BGR) cvtColor(src, dst, colorSpace); |
| 58 | + else dst = src; | ||
| 57 | 59 | ||
| 58 | if (channel != -1) { | 60 | if (channel != -1) { |
| 59 | std::vector<Mat> mv; | 61 | std::vector<Mat> mv; |
openbr/plugins/distance.cpp
| @@ -18,10 +18,12 @@ | @@ -18,10 +18,12 @@ | ||
| 18 | #include <QtConcurrentRun> | 18 | #include <QtConcurrentRun> |
| 19 | #include <numeric> | 19 | #include <numeric> |
| 20 | #include <opencv2/imgproc/imgproc.hpp> | 20 | #include <opencv2/imgproc/imgproc.hpp> |
| 21 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 21 | #include "openbr_internal.h" | 22 | #include "openbr_internal.h" |
| 22 | 23 | ||
| 23 | #include "openbr/core/distance_sse.h" | 24 | #include "openbr/core/distance_sse.h" |
| 24 | #include "openbr/core/qtutils.h" | 25 | #include "openbr/core/qtutils.h" |
| 26 | +#include "openbr/core/opencvutils.h" | ||
| 25 | 27 | ||
| 26 | using namespace cv; | 28 | using namespace cv; |
| 27 | 29 | ||
| @@ -61,6 +63,7 @@ private: | @@ -61,6 +63,7 @@ private: | ||
| 61 | (a.m().type() != b.m().type())) | 63 | (a.m().type() != b.m().type())) |
| 62 | return -std::numeric_limits<float>::max(); | 64 | return -std::numeric_limits<float>::max(); |
| 63 | 65 | ||
| 66 | +// TODO: this max value is never returned based on the switch / default | ||
| 64 | float result = std::numeric_limits<float>::max(); | 67 | float result = std::numeric_limits<float>::max(); |
| 65 | switch (metric) { | 68 | switch (metric) { |
| 66 | case Correlation: | 69 | case Correlation: |
| @@ -386,5 +389,103 @@ class OnlineDistance : public Distance | @@ -386,5 +389,103 @@ class OnlineDistance : public Distance | ||
| 386 | 389 | ||
| 387 | BR_REGISTER(Distance, OnlineDistance) | 390 | BR_REGISTER(Distance, OnlineDistance) |
| 388 | 391 | ||
| 392 | +/*! | ||
| 393 | + * \ingroup distances | ||
| 394 | + * \brief Attenuation function based distance from attributes | ||
| 395 | + * \author Scott Klum \cite sklum | ||
| 396 | + */ | ||
| 397 | +class AttributeDistance : public Distance | ||
| 398 | +{ | ||
| 399 | + Q_OBJECT | ||
| 400 | + Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false) | ||
| 401 | + BR_PROPERTY(QString, attribute, QString()) | ||
| 402 | + | ||
| 403 | + float compare(const Template &target, const Template &query) const | ||
| 404 | + { | ||
| 405 | + float queryValue = query.file.get<float>(attribute); | ||
| 406 | + float targetValue = target.file.get<float>(attribute); | ||
| 407 | + | ||
| 408 | + // TODO: Set this magic number to something meaningful | ||
| 409 | + float stddev = 1; | ||
| 410 | + | ||
| 411 | + if (queryValue == targetValue) return 1; | ||
| 412 | + else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2)); | ||
| 413 | + } | ||
| 414 | +}; | ||
| 415 | + | ||
| 416 | +BR_REGISTER(Distance, AttributeDistance) | ||
| 417 | + | ||
| 418 | +/*! | ||
| 419 | + * \ingroup distances | ||
| 420 | + * \brief Sum match scores across multiple distances | ||
| 421 | + * \author Scott Klum \cite sklum | ||
| 422 | + */ | ||
| 423 | +class SumDistance : public Distance | ||
| 424 | +{ | ||
| 425 | + Q_OBJECT | ||
| 426 | + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | ||
| 427 | + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | ||
| 428 | + | ||
| 429 | + void train(const TemplateList &data) | ||
| 430 | + { | ||
| 431 | + QFutureSynchronizer<void> futures; | ||
| 432 | + foreach (br::Distance *distance, distances) | ||
| 433 | + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | ||
| 434 | + futures.waitForFinished(); | ||
| 435 | + } | ||
| 436 | + | ||
| 437 | + float compare(const Template &target, const Template &query) const | ||
| 438 | + { | ||
| 439 | + float result = 0; | ||
| 440 | + | ||
| 441 | + foreach (br::Distance *distance, distances) { | ||
| 442 | + result += distance->compare(target, query); | ||
| 443 | + | ||
| 444 | + if (result == -std::numeric_limits<float>::max()) | ||
| 445 | + return result; | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + return result; | ||
| 449 | + } | ||
| 450 | +}; | ||
| 451 | + | ||
| 452 | +BR_REGISTER(Distance, SumDistance) | ||
| 453 | + | ||
| 454 | +/*! | ||
| 455 | + * \ingroup transforms | ||
| 456 | + * \brief Compare each template to a fixed gallery (with name = galleryName), using the specified distance. | ||
| 457 | + * dst will contain a 1 by n vector of scores. | ||
| 458 | + * \author Charles Otto \cite caotto | ||
| 459 | + */ | ||
| 460 | +class GalleryCompareTransform : public Transform | ||
| 461 | +{ | ||
| 462 | + Q_OBJECT | ||
| 463 | + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | ||
| 464 | + Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) | ||
| 465 | + BR_PROPERTY(br::Distance*, distance, NULL) | ||
| 466 | + BR_PROPERTY(QString, galleryName, "") | ||
| 467 | + | ||
| 468 | + TemplateList gallery; | ||
| 469 | + | ||
| 470 | + void project(const Template &src, Template &dst) const | ||
| 471 | + { | ||
| 472 | + dst = src; | ||
| 473 | + if (gallery.isEmpty()) | ||
| 474 | + return; | ||
| 475 | + | ||
| 476 | + QList<float> line = distance->compare(gallery, src); | ||
| 477 | + dst.m() = OpenCVUtils::toMat(line, 1); | ||
| 478 | + } | ||
| 479 | + | ||
| 480 | + void init() | ||
| 481 | + { | ||
| 482 | + if (!galleryName.isEmpty()) | ||
| 483 | + gallery = TemplateList::fromGallery(galleryName); | ||
| 484 | + } | ||
| 485 | +}; | ||
| 486 | + | ||
| 487 | +BR_REGISTER(Transform, GalleryCompareTransform) | ||
| 488 | + | ||
| 489 | + | ||
| 389 | } // namespace br | 490 | } // namespace br |
| 390 | #include "distance.moc" | 491 | #include "distance.moc" |
openbr/plugins/draw.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/highgui/highgui.hpp> | 17 | #include <opencv2/highgui/highgui.hpp> |
| 18 | +#include <opencv2/highgui/highgui_c.h> | ||
| 18 | #include <opencv2/imgproc/imgproc.hpp> | 19 | #include <opencv2/imgproc/imgproc.hpp> |
| 19 | #include <vector> | 20 | #include <vector> |
| 20 | #include "openbr_internal.h" | 21 | #include "openbr_internal.h" |
| @@ -345,6 +346,75 @@ class AdjacentOverlayTransform : public Transform | @@ -345,6 +346,75 @@ class AdjacentOverlayTransform : public Transform | ||
| 345 | 346 | ||
| 346 | BR_REGISTER(Transform, AdjacentOverlayTransform) | 347 | BR_REGISTER(Transform, AdjacentOverlayTransform) |
| 347 | 348 | ||
| 349 | +/*! | ||
| 350 | + * \ingroup transforms | ||
| 351 | + * \brief Draw a line representing the direction and magnitude of optical flow at the specified points. | ||
| 352 | + * \author Austin Blanton \cite imaus10 | ||
| 353 | + */ | ||
| 354 | +class DrawOpticalFlow : public UntrainableTransform | ||
| 355 | +{ | ||
| 356 | + Q_OBJECT | ||
| 357 | + Q_PROPERTY(QString original READ get_original WRITE set_original RESET reset_original STORED false) | ||
| 358 | + BR_PROPERTY(QString, original, "original") | ||
| 359 | + | ||
| 360 | + void project(const Template &src, Template &dst) const | ||
| 361 | + { | ||
| 362 | + const Scalar color(0,255,0); | ||
| 363 | + Mat flow = src.m(); | ||
| 364 | + dst = src; | ||
| 365 | + if (!dst.file.contains(original)) qFatal("The original img must be saved in the metadata with SaveMat."); | ||
| 366 | + dst.m() = dst.file.get<Mat>(original); | ||
| 367 | + dst.file.remove(original); | ||
| 368 | + foreach (const Point2f &pt, OpenCVUtils::toPoints(dst.file.points())) { | ||
| 369 | + Point2f dxy = flow.at<Point2f>(pt.y, pt.x); | ||
| 370 | + Point2f newPt(pt.x+dxy.x, pt.y+dxy.y); | ||
| 371 | + line(dst, pt, newPt, color); | ||
| 372 | + } | ||
| 373 | + } | ||
| 374 | +}; | ||
| 375 | +BR_REGISTER(Transform, DrawOpticalFlow) | ||
| 376 | + | ||
| 377 | +/*! | ||
| 378 | + * \ingroup transforms | ||
| 379 | + * \brief Fill in the segmentations or draw a line between intersecting segments. | ||
| 380 | + * \author Austin Blanton \cite imaus10 | ||
| 381 | + */ | ||
| 382 | +class DrawSegmentation : public UntrainableTransform | ||
| 383 | +{ | ||
| 384 | + Q_OBJECT | ||
| 385 | + Q_PROPERTY(bool fillSegment READ get_fillSegment WRITE set_fillSegment RESET reset_fillSegment STORED false) | ||
| 386 | + BR_PROPERTY(bool, fillSegment, true) | ||
| 387 | + | ||
| 388 | + void project(const Template &src, Template &dst) const | ||
| 389 | + { | ||
| 390 | + if (!src.file.contains("SegmentsMask") || !src.file.contains("NumSegments")) qFatal("Must supply a Contours object in the metadata to drawContours."); | ||
| 391 | + Mat segments = src.file.get<Mat>("SegmentsMask"); | ||
| 392 | + int numSegments = src.file.get<int>("NumSegments"); | ||
| 393 | + | ||
| 394 | + dst.file = src.file; | ||
| 395 | + Mat drawn = fillSegment ? Mat(segments.size(), CV_8UC3, Scalar::all(0)) : src.m(); | ||
| 396 | + | ||
| 397 | + for (int i=1; i<numSegments+1; i++) { | ||
| 398 | + Mat mask = segments == i; | ||
| 399 | + if (fillSegment) { // color the whole segment | ||
| 400 | + // set to a random color - get ready for a craaaazy acid trip | ||
| 401 | + int b = theRNG().uniform(0, 255); | ||
| 402 | + int g = theRNG().uniform(0, 255); | ||
| 403 | + int r = theRNG().uniform(0, 255); | ||
| 404 | + drawn.setTo(Scalar(r,g,b), mask); | ||
| 405 | + } else { // draw lines where there's a color change | ||
| 406 | + vector<vector<Point> > contours; | ||
| 407 | + Scalar color(0,255,0); | ||
| 408 | + findContours(mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); | ||
| 409 | + drawContours(drawn, contours, -1, color); | ||
| 410 | + } | ||
| 411 | + } | ||
| 412 | + | ||
| 413 | + dst.m() = drawn; | ||
| 414 | + } | ||
| 415 | +}; | ||
| 416 | +BR_REGISTER(Transform, DrawSegmentation) | ||
| 417 | + | ||
| 348 | // TODO: re-implement EditTransform using Qt | 418 | // TODO: re-implement EditTransform using Qt |
| 349 | #if 0 | 419 | #if 0 |
| 350 | /*! | 420 | /*! |
openbr/plugins/eyes.cpp
| @@ -34,6 +34,7 @@ | @@ -34,6 +34,7 @@ | ||
| 34 | */ | 34 | */ |
| 35 | 35 | ||
| 36 | #include <opencv2/imgproc/imgproc.hpp> | 36 | #include <opencv2/imgproc/imgproc.hpp> |
| 37 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 37 | #include "openbr_internal.h" | 38 | #include "openbr_internal.h" |
| 38 | #include "openbr/core/opencvutils.h" | 39 | #include "openbr/core/opencvutils.h" |
| 39 | 40 |
openbr/plugins/format.cpp
| @@ -16,10 +16,12 @@ | @@ -16,10 +16,12 @@ | ||
| 16 | 16 | ||
| 17 | #include <QDate> | 17 | #include <QDate> |
| 18 | #include <QSize> | 18 | #include <QSize> |
| 19 | +#include <QChar> | ||
| 19 | #ifndef BR_EMBEDDED | 20 | #ifndef BR_EMBEDDED |
| 20 | #include <QtXml> | 21 | #include <QtXml> |
| 21 | #endif // BR_EMBEDDED | 22 | #endif // BR_EMBEDDED |
| 22 | #include <opencv2/highgui/highgui.hpp> | 23 | #include <opencv2/highgui/highgui.hpp> |
| 24 | +#include <opencv2/highgui/highgui_c.h> | ||
| 23 | #include "openbr_internal.h" | 25 | #include "openbr_internal.h" |
| 24 | 26 | ||
| 25 | #include "openbr/core/bee.h" | 27 | #include "openbr/core/bee.h" |
| @@ -33,7 +35,7 @@ namespace br | @@ -33,7 +35,7 @@ namespace br | ||
| 33 | 35 | ||
| 34 | /*! | 36 | /*! |
| 35 | * \ingroup formats | 37 | * \ingroup formats |
| 36 | - * \brief Read all frames of a video using OpenCV | 38 | + * \brief Read all frames of a video using OpenCV |
| 37 | * \author Charles Otto \cite caotto | 39 | * \author Charles Otto \cite caotto |
| 38 | */ | 40 | */ |
| 39 | class videoFormat : public Format | 41 | class videoFormat : public Format |
| @@ -45,11 +47,11 @@ public: | @@ -45,11 +47,11 @@ public: | ||
| 45 | { | 47 | { |
| 46 | if (!file.exists() ) | 48 | if (!file.exists() ) |
| 47 | return Template(); | 49 | return Template(); |
| 48 | - | 50 | + |
| 49 | VideoCapture videoSource(file.name.toStdString()); | 51 | VideoCapture videoSource(file.name.toStdString()); |
| 50 | videoSource.open(file.name.toStdString() ); | 52 | videoSource.open(file.name.toStdString() ); |
| 51 | - | ||
| 52 | - | 53 | + |
| 54 | + | ||
| 53 | Template frames; | 55 | Template frames; |
| 54 | if (!videoSource.isOpened()) { | 56 | if (!videoSource.isOpened()) { |
| 55 | qWarning("video file open failed"); | 57 | qWarning("video file open failed"); |
| @@ -71,7 +73,7 @@ public: | @@ -71,7 +73,7 @@ public: | ||
| 71 | 73 | ||
| 72 | void write(const Template &t) const | 74 | void write(const Template &t) const |
| 73 | { | 75 | { |
| 74 | - int fourcc = OpenCVUtils::getFourcc(); | 76 | + int fourcc = OpenCVUtils::getFourcc(); |
| 75 | VideoWriter videoSink(file.name.toStdString(), fourcc, 30, t.begin()->size()); | 77 | VideoWriter videoSink(file.name.toStdString(), fourcc, 30, t.begin()->size()); |
| 76 | 78 | ||
| 77 | // Did we successfully open the output file? | 79 | // Did we successfully open the output file? |
| @@ -719,7 +721,7 @@ BR_REGISTER(Format, xmlFormat) | @@ -719,7 +721,7 @@ BR_REGISTER(Format, xmlFormat) | ||
| 719 | /*! | 721 | /*! |
| 720 | * \ingroup formats | 722 | * \ingroup formats |
| 721 | * \brief Reads in scores or ground truth from a text table. | 723 | * \brief Reads in scores or ground truth from a text table. |
| 722 | - * \author Josh Klontz | 724 | + * \author Josh Klontz \cite jklontz |
| 723 | * | 725 | * |
| 724 | * Example of the format: | 726 | * Example of the format: |
| 725 | * \code | 727 | * \code |
| @@ -768,6 +770,191 @@ class scoresFormat : public Format | @@ -768,6 +770,191 @@ class scoresFormat : public Format | ||
| 768 | 770 | ||
| 769 | BR_REGISTER(Format, scoresFormat) | 771 | BR_REGISTER(Format, scoresFormat) |
| 770 | 772 | ||
| 773 | +/*! | ||
| 774 | + * \ingroup formats | ||
| 775 | + * \brief Reads FBI EBTS transactions. | ||
| 776 | + * \author Scott Klum \cite sklum | ||
| 777 | + * https://www.fbibiospecs.org/ebts.html | ||
| 778 | + */ | ||
| 779 | +class ebtsFormat : public Format | ||
| 780 | +{ | ||
| 781 | + Q_OBJECT | ||
| 782 | + | ||
| 783 | + struct Field { | ||
| 784 | + int type; | ||
| 785 | + QList<QByteArray> data; | ||
| 786 | + }; | ||
| 787 | + | ||
| 788 | + struct Record { | ||
| 789 | + int type; | ||
| 790 | + quint32 bytes; | ||
| 791 | + int position; // Starting position of record | ||
| 792 | + | ||
| 793 | + QHash<int,QList<QByteArray> > fields; | ||
| 794 | + }; | ||
| 795 | + | ||
| 796 | + quint32 recordBytes(const QByteArray &byteArray, const float recordType, int from) const | ||
| 797 | + { | ||
| 798 | + bool ok; | ||
| 799 | + quint32 size; | ||
| 800 | + | ||
| 801 | + if (recordType == 4 || recordType == 7) { | ||
| 802 | + // read first four bytes | ||
| 803 | + ok = true; | ||
| 804 | + size = qFromBigEndian<quint32>((const uchar*)byteArray.mid(from,4).constData()); | ||
| 805 | + } else { | ||
| 806 | + int index = byteArray.indexOf(QChar(0x1D), from); | ||
| 807 | + size = byteArray.mid(from, index-from).split(':').last().toInt(&ok); | ||
| 808 | + } | ||
| 809 | + | ||
| 810 | + return ok ? size : -1; | ||
| 811 | + } | ||
| 812 | + | ||
| 813 | + void parseRecord(const QByteArray &byteArray, Record &record) const | ||
| 814 | + { | ||
| 815 | + if (record.type == 4 || record.type == 7) { | ||
| 816 | + // Just a binary blob | ||
| 817 | + // Read everything after the first four bytes | ||
| 818 | + // Not current supported | ||
| 819 | + } else { | ||
| 820 | + // Continue reading fields until we get all the data | ||
| 821 | + unsigned int position = record.position; | ||
| 822 | + while (position < record.position + record.bytes) { | ||
| 823 | + int index = byteArray.indexOf(QChar(0x1D), position); | ||
| 824 | + Field field = parseField(byteArray.mid(position, index-position),QChar(0x1F)); | ||
| 825 | + if (field.type == 999 ) { | ||
| 826 | + // Data begin after the field identifier and the colon | ||
| 827 | + int dataBegin = byteArray.indexOf(':', position)+1; | ||
| 828 | + field.data.clear(); | ||
| 829 | + field.data.append(byteArray.mid(dataBegin, record.bytes-(dataBegin-record.position))); | ||
| 830 | + | ||
| 831 | + // Data fields are always last in the record | ||
| 832 | + record.fields.insert(field.type,field.data); | ||
| 833 | + break; | ||
| 834 | + } | ||
| 835 | + // Advance the position accounting for the separator | ||
| 836 | + position += index-position+1; | ||
| 837 | + record.fields.insert(field.type,field.data); | ||
| 838 | + } | ||
| 839 | + } | ||
| 840 | + } | ||
| 841 | + | ||
| 842 | + Field parseField(const QByteArray &byteArray, const QChar &sep) const | ||
| 843 | + { | ||
| 844 | + bool ok; | ||
| 845 | + Field f; | ||
| 846 | + | ||
| 847 | + QList<QByteArray> data = byteArray.split(':'); | ||
| 848 | + | ||
| 849 | + f.type = data.first().split('.').last().toInt(&ok); | ||
| 850 | + f.data = data.last().split(sep.toLatin1()); | ||
| 851 | + | ||
| 852 | + return f; | ||
| 853 | + } | ||
| 854 | + | ||
| 855 | + Template read() const | ||
| 856 | + { | ||
| 857 | + QByteArray byteArray; | ||
| 858 | + QtUtils::readFile(file, byteArray); | ||
| 859 | + | ||
| 860 | + Template t; | ||
| 861 | + | ||
| 862 | + Mat m; | ||
| 863 | + | ||
| 864 | + QList<Record> records; | ||
| 865 | + | ||
| 866 | + // Read the type one record (every EBTS file will have one of these) | ||
| 867 | + Record r1; | ||
| 868 | + r1.type = 1; | ||
| 869 | + r1.position = 0; | ||
| 870 | + r1.bytes = recordBytes(byteArray,r1.type,r1.position); | ||
| 871 | + | ||
| 872 | + // The fields in a type 1 record are strictly defined | ||
| 873 | + QList<QByteArray> data = byteArray.mid(r1.position,r1.bytes).split(QChar(0x1D).toLatin1()); | ||
| 874 | + foreach (const QByteArray &datum, data) { | ||
| 875 | + Field f = parseField(datum,QChar(0x1F)); | ||
| 876 | + r1.fields.insert(f.type,f.data); | ||
| 877 | + } | ||
| 878 | + | ||
| 879 | + records.append(r1); | ||
| 880 | + | ||
| 881 | + // Read the type two record (every EBTS file will have one of these) | ||
| 882 | + Record r2; | ||
| 883 | + r2.type = 2; | ||
| 884 | + r2.position = r1.bytes; | ||
| 885 | + r2.bytes = recordBytes(byteArray,r2.type,r2.position); | ||
| 886 | + | ||
| 887 | + // The fields in a type 2 record are strictly defined | ||
| 888 | + data = byteArray.mid(r2.position,r2.bytes).split(QChar(0x1D).toLatin1()); | ||
| 889 | + foreach (const QByteArray &datum, data) { | ||
| 890 | + Field f = parseField(datum,QChar(0x1F)); | ||
| 891 | + r2.fields.insert(f.type,f.data); | ||
| 892 | + } | ||
| 893 | + | ||
| 894 | + // Demographics | ||
| 895 | + if (r2.fields.contains(18)) { | ||
| 896 | + QString name = r2.fields.value(18).first(); | ||
| 897 | + QStringList names = name.split(','); | ||
| 898 | + t.file.set("FIRSTNAME", names.at(1)); | ||
| 899 | + t.file.set("LASTNAME", names.at(0)); | ||
| 900 | + } | ||
| 901 | + | ||
| 902 | + if (r2.fields.contains(22)) t.file.set("DOB", r2.fields.value(22).first().toInt()); | ||
| 903 | + if (r2.fields.contains(24)) t.file.set("GENDER", QString(r2.fields.value(24).first())); | ||
| 904 | + if (r2.fields.contains(25)) t.file.set("RACE", QString(r2.fields.value(25).first())); | ||
| 905 | + | ||
| 906 | + if (t.file.contains("DOB")) { | ||
| 907 | + const QDate dob = QDate::fromString(t.file.get<QString>("DOB"), "yyyyMMdd"); | ||
| 908 | + const QDate current = QDate::currentDate(); | ||
| 909 | + int age = current.year() - dob.year(); | ||
| 910 | + if (current.month() < dob.month()) age--; | ||
| 911 | + t.file.set("Age", age); | ||
| 912 | + } | ||
| 913 | + | ||
| 914 | + records.append(r2); | ||
| 915 | + | ||
| 916 | + // The third field of the first record contains informations about all the remaining records in the transaction | ||
| 917 | + // We don't care about the first two and the final items | ||
| 918 | + QList<QByteArray> recordTypes = r1.fields.value(3); | ||
| 919 | + for (int i=2; i<recordTypes.size()-1; i++) { | ||
| 920 | + // The first two bytes indicate the record index (and we don't want the separator), but we only care about the type | ||
| 921 | + QByteArray recordType = recordTypes[i].mid(3); | ||
| 922 | + Record r; | ||
| 923 | + r.type = recordType.toInt(); | ||
| 924 | + records.append(r); | ||
| 925 | + } | ||
| 926 | + | ||
| 927 | + QList<int> frontalIdxs; | ||
| 928 | + int position = r1.bytes + r2.bytes; | ||
| 929 | + for (int i=2; i<records.size(); i++) { | ||
| 930 | + records[i].position = position; | ||
| 931 | + records[i].bytes = recordBytes(byteArray,records[i].type,position); | ||
| 932 | + | ||
| 933 | + parseRecord(byteArray, records[i]); | ||
| 934 | + if (records[i].type == 10) frontalIdxs.append(i); | ||
| 935 | + position += records[i].bytes; | ||
| 936 | + } | ||
| 937 | + | ||
| 938 | + if (!frontalIdxs.isEmpty()) { | ||
| 939 | + // We use the first type 10 record to get the frontal | ||
| 940 | + QByteArray frontal = records[frontalIdxs.first()].fields.value(999).first(); | ||
| 941 | + m = imdecode(Mat(3, frontal.size(), CV_8UC3, frontal.data()), CV_LOAD_IMAGE_COLOR); | ||
| 942 | + if (!m.data) qWarning("ebtsFormat::read failed to decode image data."); | ||
| 943 | + t.m() = m; | ||
| 944 | + } else qWarning("ebtsFormat::cannot find image data within file."); | ||
| 945 | + | ||
| 946 | + return t; | ||
| 947 | + } | ||
| 948 | + | ||
| 949 | + void write(const Template &t) const | ||
| 950 | + { | ||
| 951 | + (void) t; | ||
| 952 | + qFatal("Writing EBTS files is not supported."); | ||
| 953 | + } | ||
| 954 | +}; | ||
| 955 | + | ||
| 956 | +BR_REGISTER(Format, ebtsFormat) | ||
| 957 | + | ||
| 771 | } // namespace br | 958 | } // namespace br |
| 772 | 959 | ||
| 773 | #include "format.moc" | 960 | #include "format.moc" |
openbr/plugins/gallery.cpp
| @@ -985,7 +985,7 @@ class vbbGallery : public Gallery | @@ -985,7 +985,7 @@ class vbbGallery : public Gallery | ||
| 985 | void init() | 985 | void init() |
| 986 | { | 986 | { |
| 987 | MatlabIO matio; | 987 | MatlabIO matio; |
| 988 | - QString filename = file.name; | 988 | + QString filename = (Globals->path.isEmpty() ? "" : Globals->path + "/") + file.name; |
| 989 | bool ok = matio.open(filename.toStdString(), "r"); | 989 | bool ok = matio.open(filename.toStdString(), "r"); |
| 990 | if (!ok) qFatal("Couldn't open the vbb file"); | 990 | if (!ok) qFatal("Couldn't open the vbb file"); |
| 991 | 991 |
openbr/plugins/gui.cpp
| 1 | #include <QApplication> | 1 | #include <QApplication> |
| 2 | #include <QLabel> | 2 | #include <QLabel> |
| 3 | #include <QElapsedTimer> | 3 | #include <QElapsedTimer> |
| 4 | +#include <QInputDialog> | ||
| 4 | #include <QWaitCondition> | 5 | #include <QWaitCondition> |
| 5 | #include <QMutex> | 6 | #include <QMutex> |
| 6 | #include <QMouseEvent> | 7 | #include <QMouseEvent> |
| @@ -12,6 +13,7 @@ | @@ -12,6 +13,7 @@ | ||
| 12 | #include <QLineEdit> | 13 | #include <QLineEdit> |
| 13 | 14 | ||
| 14 | #include <opencv2/imgproc/imgproc.hpp> | 15 | #include <opencv2/imgproc/imgproc.hpp> |
| 16 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 15 | #include "openbr_internal.h" | 17 | #include "openbr_internal.h" |
| 16 | #include "openbr/gui/utility.h" | 18 | #include "openbr/gui/utility.h" |
| 17 | 19 | ||
| @@ -181,6 +183,149 @@ public slots: | @@ -181,6 +183,149 @@ public slots: | ||
| 181 | } | 183 | } |
| 182 | }; | 184 | }; |
| 183 | 185 | ||
| 186 | +class RectMarkingWindow : public DisplayWindow | ||
| 187 | +{ | ||
| 188 | +public: | ||
| 189 | + RectMarkingWindow() : DisplayWindow() | ||
| 190 | + { | ||
| 191 | + drawingRect = false; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + bool drawingRect; | ||
| 195 | + QVector<QRectF> rects; | ||
| 196 | + QList<QString> rectLabels; | ||
| 197 | + | ||
| 198 | + QPointF rectOrigin; | ||
| 199 | + QPointF currentEnd; | ||
| 200 | + QRectF currentRect; | ||
| 201 | + bool disableAccept; | ||
| 202 | + | ||
| 203 | + bool eventFilter(QObject *obj, QEvent *event) | ||
| 204 | + { | ||
| 205 | + if (disableAccept) | ||
| 206 | + return QObject::eventFilter(obj, event); | ||
| 207 | + | ||
| 208 | + | ||
| 209 | + if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseMove) | ||
| 210 | + { | ||
| 211 | + event->accept(); | ||
| 212 | + | ||
| 213 | + QMouseEvent *mouseEvent = (QMouseEvent*)event; | ||
| 214 | + | ||
| 215 | + if (event->type() == QEvent::MouseButtonPress) | ||
| 216 | + { | ||
| 217 | + | ||
| 218 | + if (mouseEvent->button() == Qt::LeftButton) { | ||
| 219 | + if (!drawingRect) | ||
| 220 | + { | ||
| 221 | + drawingRect = true; | ||
| 222 | + rectOrigin = mouseEvent->pos(); | ||
| 223 | + return true; | ||
| 224 | + } | ||
| 225 | + else | ||
| 226 | + { | ||
| 227 | + drawingRect = false; | ||
| 228 | + | ||
| 229 | + rects.append(QRectF(rectOrigin, mouseEvent->pos())); | ||
| 230 | + rects.last() = rects.last().normalized(); | ||
| 231 | + // If no labels were provided, we store everything as anonymous rectangles | ||
| 232 | + if (promptKeys.empty()) | ||
| 233 | + rectLabels.append("rects"); | ||
| 234 | + // otherwise, prompt the user to select a label | ||
| 235 | + else | ||
| 236 | + { | ||
| 237 | + // get a label from the user | ||
| 238 | + bool ok = false; | ||
| 239 | + | ||
| 240 | + // Don't intercept events while the sub-dialog is up (if we take the events, then it will not work correctly) | ||
| 241 | + disableAccept = true; | ||
| 242 | + QString res = QInputDialog::getItem(this, "Select a label", "", promptKeys, next_idx, false, &ok); | ||
| 243 | + | ||
| 244 | + disableAccept = false; | ||
| 245 | + if (ok) { | ||
| 246 | + rectLabels.append(res); | ||
| 247 | + for (int i=0; i < promptKeys.size(); i++) | ||
| 248 | + { | ||
| 249 | + if (res == promptKeys[i]) { | ||
| 250 | + next_idx = (i + 1) % promptKeys.size(); | ||
| 251 | + break; | ||
| 252 | + } | ||
| 253 | + } | ||
| 254 | + } | ||
| 255 | + else { | ||
| 256 | + rects.remove(rects.size()-1); | ||
| 257 | + } | ||
| 258 | + } | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + // rclick -- reset state if drawing, remove last rect if done | ||
| 262 | + else if (mouseEvent->button() == Qt::RightButton && (!rects.isEmpty() || drawingRect)) | ||
| 263 | + { | ||
| 264 | + if(drawingRect) | ||
| 265 | + drawingRect = false; | ||
| 266 | + else | ||
| 267 | + { | ||
| 268 | + rects.remove(rects.size()-1); | ||
| 269 | + rectLabels.removeLast(); | ||
| 270 | + } | ||
| 271 | + } | ||
| 272 | + } | ||
| 273 | + else | ||
| 274 | + currentEnd = mouseEvent->pos(); | ||
| 275 | + QPixmap pixmapBuffer = pixmap; | ||
| 276 | + | ||
| 277 | + QPainter painter(&pixmapBuffer); | ||
| 278 | + painter.setPen(Qt::red); | ||
| 279 | + | ||
| 280 | + painter.drawRects(rects); | ||
| 281 | + | ||
| 282 | + if (drawingRect) | ||
| 283 | + { | ||
| 284 | + currentRect = QRectF(rectOrigin, currentEnd); | ||
| 285 | + painter.setPen(Qt::green); | ||
| 286 | + painter.drawRect(currentRect); | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + setPixmap(pixmapBuffer); | ||
| 290 | + | ||
| 291 | + return true; | ||
| 292 | + } else { | ||
| 293 | + if (event->type() == QEvent::KeyPress) | ||
| 294 | + { | ||
| 295 | + QKeyEvent * kevent = (QKeyEvent *) event; | ||
| 296 | + if (kevent->key() == Qt::Key_Enter || kevent->key() == Qt::Key_Return) { | ||
| 297 | + event->accept(); | ||
| 298 | + return true; | ||
| 299 | + } | ||
| 300 | + } | ||
| 301 | + return DisplayWindow::eventFilter(obj, event); | ||
| 302 | + } | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + | ||
| 306 | + QList<QPointF> waitForKey() | ||
| 307 | + { | ||
| 308 | + | ||
| 309 | + rects.clear(); | ||
| 310 | + drawingRect = false; | ||
| 311 | + disableAccept = false; | ||
| 312 | + next_idx = 0; | ||
| 313 | + DisplayWindow::waitForKey(); | ||
| 314 | + | ||
| 315 | + return QList<QPointF>(); | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + void setKeys(const QStringList & keys) | ||
| 319 | + { | ||
| 320 | + promptKeys = keys; | ||
| 321 | + } | ||
| 322 | + | ||
| 323 | + int next_idx; | ||
| 324 | +private: | ||
| 325 | + QStringList promptKeys; | ||
| 326 | + | ||
| 327 | +}; | ||
| 328 | + | ||
| 184 | class PointMarkingWindow : public DisplayWindow | 329 | class PointMarkingWindow : public DisplayWindow |
| 185 | { | 330 | { |
| 186 | bool eventFilter(QObject *obj, QEvent *event) | 331 | bool eventFilter(QObject *obj, QEvent *event) |
| @@ -555,6 +700,91 @@ BR_REGISTER(Transform, ManualTransform) | @@ -555,6 +700,91 @@ BR_REGISTER(Transform, ManualTransform) | ||
| 555 | 700 | ||
| 556 | /*! | 701 | /*! |
| 557 | * \ingroup transforms | 702 | * \ingroup transforms |
| 703 | + * \brief Manual select rectangular regions on an image. | ||
| 704 | + * Stores marked rectangles as anonymous rectangles, or if a set of labels is provided, prompt the user | ||
| 705 | + * to select one of those labels after drawing each rectangle. | ||
| 706 | + * \author Charles Otto \cite caotto | ||
| 707 | + */ | ||
| 708 | +class ManualRectsTransform : public ShowTransform | ||
| 709 | +{ | ||
| 710 | + Q_OBJECT | ||
| 711 | + | ||
| 712 | +public: | ||
| 713 | + | ||
| 714 | + Q_PROPERTY(QStringList labels READ get_labels WRITE set_labels RESET reset_labels STORED false) | ||
| 715 | + BR_PROPERTY(QStringList, labels, QStringList()) | ||
| 716 | + | ||
| 717 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 718 | + { | ||
| 719 | + | ||
| 720 | + dst = src; | ||
| 721 | + | ||
| 722 | + if (!Globals->useGui) | ||
| 723 | + return; | ||
| 724 | + if (src.empty()) | ||
| 725 | + return; | ||
| 726 | + | ||
| 727 | + for (int i = 0; i < dst.size(); i++) { | ||
| 728 | + foreach(const cv::Mat &m, dst[i]) { | ||
| 729 | + qImageBuffer = toQImage(m); | ||
| 730 | + displayBuffer->convertFromImage(qImageBuffer); | ||
| 731 | + | ||
| 732 | + emit updateImage(displayBuffer->copy(displayBuffer->rect())); | ||
| 733 | + | ||
| 734 | + // Blocking wait for a key-press | ||
| 735 | + if (this->waitInput) { | ||
| 736 | + window->waitForKey(); | ||
| 737 | + QVector<QRectF> rectSet = trueWindow->rects; | ||
| 738 | + QList<QString> labelSet= trueWindow->rectLabels; | ||
| 739 | + | ||
| 740 | + for (int idx = 0; idx < rectSet.size(); idx++) | ||
| 741 | + { | ||
| 742 | + if (dst[i].file.contains(labelSet[idx])) | ||
| 743 | + { | ||
| 744 | + QVariant currentProp = dst[i].file.value(labelSet[idx]); | ||
| 745 | + QList<QVariant> currentPropList; | ||
| 746 | + | ||
| 747 | + if (currentProp.canConvert<QList<QVariant> >() ) | ||
| 748 | + { | ||
| 749 | + currentPropList = currentProp.toList(); | ||
| 750 | + } | ||
| 751 | + else if (currentProp.canConvert<QRectF>()) | ||
| 752 | + { | ||
| 753 | + currentPropList.append(currentProp); | ||
| 754 | + } | ||
| 755 | + else | ||
| 756 | + { | ||
| 757 | + qFatal("Unknown type of property"); | ||
| 758 | + } | ||
| 759 | + | ||
| 760 | + currentPropList.append(rectSet[idx]); | ||
| 761 | + dst[i].file.set(labelSet[idx], QVariant::fromValue(currentPropList)); | ||
| 762 | + } | ||
| 763 | + else | ||
| 764 | + { | ||
| 765 | + dst[i].file.set(labelSet[idx], rectSet[idx]); | ||
| 766 | + } | ||
| 767 | + } | ||
| 768 | + } | ||
| 769 | + | ||
| 770 | + } | ||
| 771 | + } | ||
| 772 | + } | ||
| 773 | + RectMarkingWindow * trueWindow; | ||
| 774 | + void init() | ||
| 775 | + { | ||
| 776 | + if (!Globals->useGui) | ||
| 777 | + return; | ||
| 778 | + initActual<RectMarkingWindow>(); | ||
| 779 | + trueWindow = dynamic_cast<RectMarkingWindow *> (this->window); | ||
| 780 | + trueWindow->setKeys(this->keys); | ||
| 781 | + } | ||
| 782 | +}; | ||
| 783 | + | ||
| 784 | +BR_REGISTER(Transform, ManualRectsTransform) | ||
| 785 | + | ||
| 786 | +/*! | ||
| 787 | + * \ingroup transforms | ||
| 558 | * \brief Elicits metadata for templates in a pretty GUI | 788 | * \brief Elicits metadata for templates in a pretty GUI |
| 559 | * \author Scott Klum \cite sklum | 789 | * \author Scott Klum \cite sklum |
| 560 | */ | 790 | */ |
openbr/plugins/hist.cpp
| @@ -94,7 +94,7 @@ class BinTransform : public UntrainableTransform | @@ -94,7 +94,7 @@ class BinTransform : public UntrainableTransform | ||
| 94 | } else if (channels == 2) { | 94 | } else if (channels == 2) { |
| 95 | // If there are two channels, the first is channel is assumed to be a weight vector | 95 | // If there are two channels, the first is channel is assumed to be a weight vector |
| 96 | // and the second channel contains the vectors we would like to bin. | 96 | // and the second channel contains the vectors we would like to bin. |
| 97 | - vector<Mat> mv; | 97 | + std::vector<Mat> mv; |
| 98 | cv::split(src, mv); | 98 | cv::split(src, mv); |
| 99 | weights = mv[0]; | 99 | weights = mv[0]; |
| 100 | weights.convertTo(weights, CV_32F); | 100 | weights.convertTo(weights, CV_32F); |
openbr/plugins/integral.cpp
| 1 | #include <opencv2/imgproc/imgproc.hpp> | 1 | #include <opencv2/imgproc/imgproc.hpp> |
| 2 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 2 | #include <Eigen/Core> | 3 | #include <Eigen/Core> |
| 3 | #include "openbr_internal.h" | 4 | #include "openbr_internal.h" |
| 4 | 5 | ||
| @@ -293,7 +294,7 @@ private: | @@ -293,7 +294,7 @@ private: | ||
| 293 | Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR); | 294 | Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR); |
| 294 | Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR); | 295 | Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR); |
| 295 | cartToPolar(dx, dy, magnitude, angle, true); | 296 | cartToPolar(dx, dy, magnitude, angle, true); |
| 296 | - vector<Mat> mv; | 297 | + std::vector<Mat> mv; |
| 297 | if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) { | 298 | if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) { |
| 298 | const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f)); | 299 | const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f)); |
| 299 | mv.push_back(magnitude / theoreticalMaxMagnitude); | 300 | mv.push_back(magnitude / theoreticalMaxMagnitude); |
openbr/plugins/landmarks.cpp
| @@ -290,16 +290,18 @@ class DrawDelaunayTransform : public UntrainableTransform | @@ -290,16 +290,18 @@ class DrawDelaunayTransform : public UntrainableTransform | ||
| 290 | 290 | ||
| 291 | void project(const Template &src, Template &dst) const | 291 | void project(const Template &src, Template &dst) const |
| 292 | { | 292 | { |
| 293 | - QList<Point2f> validTriangles = OpenCVUtils::toPoints(src.file.getList<QPointF>("DelaunayTriangles")); | 293 | + dst = src; |
| 294 | 294 | ||
| 295 | - // Clone the matrix do draw on it | ||
| 296 | - dst.m() = src.m().clone(); | 295 | + if (src.file.contains("DelaunayTriangles")) { |
| 296 | + QList<Point2f> validTriangles = OpenCVUtils::toPoints(src.file.getList<QPointF>("DelaunayTriangles")); | ||
| 297 | 297 | ||
| 298 | - for (int i = 0; i < validTriangles.size(); i+=3) { | ||
| 299 | - line(dst.m(), validTriangles[i], validTriangles[i+1], Scalar(0,0,0), 1); | ||
| 300 | - line(dst.m(), validTriangles[i+1], validTriangles[i+2], Scalar(0,0,0), 1); | ||
| 301 | - line(dst.m(), validTriangles[i+2], validTriangles[i], Scalar(0,0,0), 1); | ||
| 302 | - } | 298 | + // Clone the matrix do draw on it |
| 299 | + for (int i = 0; i < validTriangles.size(); i+=3) { | ||
| 300 | + line(dst, validTriangles[i], validTriangles[i+1], Scalar(0,0,0), 1); | ||
| 301 | + line(dst, validTriangles[i+1], validTriangles[i+2], Scalar(0,0,0), 1); | ||
| 302 | + line(dst, validTriangles[i+2], validTriangles[i], Scalar(0,0,0), 1); | ||
| 303 | + } | ||
| 304 | + } else qWarning("Template does not contain Delaunay triangulation."); | ||
| 303 | } | 305 | } |
| 304 | }; | 306 | }; |
| 305 | 307 |
openbr/plugins/lbp.cpp
| @@ -15,7 +15,9 @@ | @@ -15,7 +15,9 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 18 | #include <opencv2/highgui/highgui.hpp> | 19 | #include <opencv2/highgui/highgui.hpp> |
| 20 | +#include <opencv2/highgui/highgui_c.h> | ||
| 19 | #include <limits> | 21 | #include <limits> |
| 20 | #include "openbr_internal.h" | 22 | #include "openbr_internal.h" |
| 21 | 23 |
openbr/plugins/ltp.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 18 | #include <limits> | 19 | #include <limits> |
| 19 | #include "openbr_internal.h" | 20 | #include "openbr_internal.h" |
| 20 | 21 |
openbr/plugins/mask.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 18 | #include "openbr_internal.h" | 19 | #include "openbr_internal.h" |
| 19 | 20 | ||
| 20 | using namespace cv; | 21 | using namespace cv; |
| @@ -164,7 +165,7 @@ class LargestConvexAreaTransform : public UntrainableTransform | @@ -164,7 +165,7 @@ class LargestConvexAreaTransform : public UntrainableTransform | ||
| 164 | void project(const Template &src, Template &dst) const | 165 | void project(const Template &src, Template &dst) const |
| 165 | { | 166 | { |
| 166 | std::vector< std::vector<Point> > contours; | 167 | std::vector< std::vector<Point> > contours; |
| 167 | - findContours(src.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); | 168 | + findContours(src.m().clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); |
| 168 | double maxArea = 0; | 169 | double maxArea = 0; |
| 169 | foreach (const std::vector<Point> &contour, contours) { | 170 | foreach (const std::vector<Point> &contour, contours) { |
| 170 | std::vector<Point> hull; | 171 | std::vector<Point> hull; |
openbr/plugins/misc.cpp
| @@ -537,7 +537,7 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -537,7 +537,7 @@ class ProgressCounterTransform : public TimeVaryingTransform | ||
| 537 | { | 537 | { |
| 538 | (void) data; | 538 | (void) data; |
| 539 | float p = br_progress(); | 539 | float p = br_progress(); |
| 540 | - qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100., QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); | 540 | + qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | void init() | 543 | void init() |
openbr/plugins/motion.cpp
| @@ -23,6 +23,7 @@ class OpticalFlowTransform : public UntrainableMetaTransform | @@ -23,6 +23,7 @@ class OpticalFlowTransform : public UntrainableMetaTransform | ||
| 23 | Q_PROPERTY(int poly_n READ get_poly_n WRITE set_poly_n RESET reset_poly_n STORED false) | 23 | Q_PROPERTY(int poly_n READ get_poly_n WRITE set_poly_n RESET reset_poly_n STORED false) |
| 24 | Q_PROPERTY(double poly_sigma READ get_poly_sigma WRITE set_poly_sigma RESET reset_poly_sigma STORED false) | 24 | Q_PROPERTY(double poly_sigma READ get_poly_sigma WRITE set_poly_sigma RESET reset_poly_sigma STORED false) |
| 25 | Q_PROPERTY(int flags READ get_flags WRITE set_flags RESET reset_flags STORED false) | 25 | Q_PROPERTY(int flags READ get_flags WRITE set_flags RESET reset_flags STORED false) |
| 26 | + Q_PROPERTY(bool useMagnitude READ get_useMagnitude WRITE set_useMagnitude RESET reset_useMagnitude STORED false) | ||
| 26 | // these defaults are optimized for KTH | 27 | // these defaults are optimized for KTH |
| 27 | BR_PROPERTY(double, pyr_scale, 0.1) | 28 | BR_PROPERTY(double, pyr_scale, 0.1) |
| 28 | BR_PROPERTY(int, levels, 1) | 29 | BR_PROPERTY(int, levels, 1) |
| @@ -31,22 +32,27 @@ class OpticalFlowTransform : public UntrainableMetaTransform | @@ -31,22 +32,27 @@ class OpticalFlowTransform : public UntrainableMetaTransform | ||
| 31 | BR_PROPERTY(int, poly_n, 7) | 32 | BR_PROPERTY(int, poly_n, 7) |
| 32 | BR_PROPERTY(double, poly_sigma, 1.1) | 33 | BR_PROPERTY(double, poly_sigma, 1.1) |
| 33 | BR_PROPERTY(int, flags, 0) | 34 | BR_PROPERTY(int, flags, 0) |
| 35 | + BR_PROPERTY(bool, useMagnitude, true) | ||
| 34 | 36 | ||
| 35 | void project(const Template &src, Template &dst) const | 37 | void project(const Template &src, Template &dst) const |
| 36 | { | 38 | { |
| 37 | // get the two images put there by AggregateFrames | 39 | // get the two images put there by AggregateFrames |
| 38 | if (src.size() != 2) qFatal("Optical Flow requires two images."); | 40 | if (src.size() != 2) qFatal("Optical Flow requires two images."); |
| 39 | - Mat prevImg = src[0], nextImg = src[1], flow, flowOneCh; | 41 | + Mat prevImg = src[0], nextImg = src[1], flow; |
| 40 | if (src[0].channels() != 1) OpenCVUtils::cvtGray(src[0], prevImg); | 42 | if (src[0].channels() != 1) OpenCVUtils::cvtGray(src[0], prevImg); |
| 41 | if (src[1].channels() != 1) OpenCVUtils::cvtGray(src[1], nextImg); | 43 | if (src[1].channels() != 1) OpenCVUtils::cvtGray(src[1], nextImg); |
| 42 | calcOpticalFlowFarneback(prevImg, nextImg, flow, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags); | 44 | calcOpticalFlowFarneback(prevImg, nextImg, flow, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags); |
| 43 | 45 | ||
| 44 | - // the result is two channels | ||
| 45 | - std::vector<Mat> channels(2); | ||
| 46 | - split(flow, channels); | ||
| 47 | - magnitude(channels[0], channels[1], flowOneCh); | ||
| 48 | - | ||
| 49 | - dst += flowOneCh; | 46 | + if (useMagnitude) { |
| 47 | + // the result is two channels | ||
| 48 | + Mat flowOneCh; | ||
| 49 | + std::vector<Mat> channels(2); | ||
| 50 | + split(flow, channels); | ||
| 51 | + magnitude(channels[0], channels[1], flowOneCh); | ||
| 52 | + dst += flowOneCh; | ||
| 53 | + } else { | ||
| 54 | + dst += flow; | ||
| 55 | + } | ||
| 50 | dst.file = src.file; | 56 | dst.file = src.file; |
| 51 | } | 57 | } |
| 52 | }; | 58 | }; |
| @@ -62,7 +68,8 @@ class SubtractBackgroundTransform : public TimeVaryingTransform | @@ -62,7 +68,8 @@ class SubtractBackgroundTransform : public TimeVaryingTransform | ||
| 62 | { | 68 | { |
| 63 | Q_OBJECT | 69 | Q_OBJECT |
| 64 | 70 | ||
| 65 | - BackgroundSubtractorMOG2 mog; | 71 | + // TODO: This is broken. |
| 72 | + // BackgroundSubtractorMOG2 mog; | ||
| 66 | 73 | ||
| 67 | public: | 74 | public: |
| 68 | SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {} | 75 | SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {} |
| @@ -72,7 +79,8 @@ private: | @@ -72,7 +79,8 @@ private: | ||
| 72 | { | 79 | { |
| 73 | dst = src; | 80 | dst = src; |
| 74 | Mat mask; | 81 | Mat mask; |
| 75 | - mog(src, mask); | 82 | + // TODO: broken |
| 83 | + // mog(src, mask); | ||
| 76 | erode(mask, mask, Mat()); | 84 | erode(mask, mask, Mat()); |
| 77 | dilate(mask, mask, Mat()); | 85 | dilate(mask, mask, Mat()); |
| 78 | dst.file.set("Mask", QVariant::fromValue(mask)); | 86 | dst.file.set("Mask", QVariant::fromValue(mask)); |
| @@ -86,7 +94,8 @@ private: | @@ -86,7 +94,8 @@ private: | ||
| 86 | void finalize(TemplateList &output) | 94 | void finalize(TemplateList &output) |
| 87 | { | 95 | { |
| 88 | (void) output; | 96 | (void) output; |
| 89 | - mog = BackgroundSubtractorMOG2(); | 97 | + // TODO: Broken |
| 98 | + // mog = BackgroundSubtractorMOG2(); | ||
| 90 | } | 99 | } |
| 91 | }; | 100 | }; |
| 92 | 101 |
openbr/plugins/normalize.cpp
| @@ -60,24 +60,29 @@ class NormalizeTransform : public UntrainableTransform | @@ -60,24 +60,29 @@ class NormalizeTransform : public UntrainableTransform | ||
| 60 | 60 | ||
| 61 | Q_PROPERTY(bool ByRow READ get_ByRow WRITE set_ByRow RESET reset_ByRow STORED false) | 61 | Q_PROPERTY(bool ByRow READ get_ByRow WRITE set_ByRow RESET reset_ByRow STORED false) |
| 62 | BR_PROPERTY(bool, ByRow, false) | 62 | BR_PROPERTY(bool, ByRow, false) |
| 63 | + Q_PROPERTY(int alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | ||
| 64 | + BR_PROPERTY(int, alpha, 1) | ||
| 65 | + Q_PROPERTY(int beta READ get_beta WRITE set_beta RESET reset_beta STORED false) | ||
| 66 | + BR_PROPERTY(int, beta, 0) | ||
| 63 | 67 | ||
| 64 | public: | 68 | public: |
| 65 | /*!< */ | 69 | /*!< */ |
| 66 | enum NormType { Inf = NORM_INF, | 70 | enum NormType { Inf = NORM_INF, |
| 67 | L1 = NORM_L1, | 71 | L1 = NORM_L1, |
| 68 | - L2 = NORM_L2 }; | 72 | + L2 = NORM_L2, |
| 73 | + Range = NORM_MINMAX }; | ||
| 69 | 74 | ||
| 70 | private: | 75 | private: |
| 71 | BR_PROPERTY(NormType, normType, L2) | 76 | BR_PROPERTY(NormType, normType, L2) |
| 72 | 77 | ||
| 73 | void project(const Template &src, Template &dst) const | 78 | void project(const Template &src, Template &dst) const |
| 74 | { | 79 | { |
| 75 | - if (!ByRow) normalize(src, dst, 1, 0, normType, CV_32F); | 80 | + if (!ByRow) normalize(src, dst, alpha, beta, normType, CV_32F); |
| 76 | else { | 81 | else { |
| 77 | dst = src; | 82 | dst = src; |
| 78 | for (int i=0; i<dst.m().rows; i++) { | 83 | for (int i=0; i<dst.m().rows; i++) { |
| 79 | Mat temp; | 84 | Mat temp; |
| 80 | - cv::normalize(dst.m().row(i), temp, 1, 0, normType); | 85 | + cv::normalize(dst.m().row(i), temp, alpha, beta, normType); |
| 81 | temp.copyTo(dst.m().row(i)); | 86 | temp.copyTo(dst.m().row(i)); |
| 82 | } | 87 | } |
| 83 | } | 88 | } |
| @@ -132,7 +137,7 @@ private: | @@ -132,7 +137,7 @@ private: | ||
| 132 | const QList<int> labels = data.indexProperty(inputVariable); | 137 | const QList<int> labels = data.indexProperty(inputVariable); |
| 133 | const int dims = m.cols; | 138 | const int dims = m.cols; |
| 134 | 139 | ||
| 135 | - vector<Mat> mv, av, bv; | 140 | + std::vector<Mat> mv, av, bv; |
| 136 | split(m, mv); | 141 | split(m, mv); |
| 137 | for (size_t c = 0; c < mv.size(); c++) { | 142 | for (size_t c = 0; c < mv.size(); c++) { |
| 138 | av.push_back(Mat(1, dims, CV_64FC1)); | 143 | av.push_back(Mat(1, dims, CV_64FC1)); |
openbr/plugins/output.cpp
| @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput | @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput | ||
| 268 | 268 | ||
| 269 | for (int i=0; i<queryFiles.size(); i++) { | 269 | for (int i=0; i<queryFiles.size(); i++) { |
| 270 | QStringList files; | 270 | QStringList files; |
| 271 | - if (simple) files.append(queryFiles[i]); | 271 | + if (simple) files.append(queryFiles[i].fileName()); |
| 272 | 272 | ||
| 273 | typedef QPair<float,int> Pair; | 273 | typedef QPair<float,int> Pair; |
| 274 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true, limit)) { | 274 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true, limit)) { |
| @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput | @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput | ||
| 276 | if (pair.first < threshold) break; | 276 | if (pair.first < threshold) break; |
| 277 | File target = targetFiles[pair.second]; | 277 | File target = targetFiles[pair.second]; |
| 278 | target.set("Score", QString::number(pair.first)); | 278 | target.set("Score", QString::number(pair.first)); |
| 279 | - if (simple) files.append(target.baseName() + " " + QString::number(pair.first)); | 279 | + if (simple) files.append(target.fileName() + " " + QString::number(pair.first)); |
| 280 | else files.append(target.flat()); | 280 | else files.append(target.flat()); |
| 281 | } | 281 | } |
| 282 | } | 282 | } |
| @@ -528,7 +528,7 @@ class tailOutput : public Output | @@ -528,7 +528,7 @@ class tailOutput : public Output | ||
| 528 | } else { | 528 | } else { |
| 529 | // General case | 529 | // General case |
| 530 | for (int k=0; k<comparisons.size(); k++) { | 530 | for (int k=0; k<comparisons.size(); k++) { |
| 531 | - if (comparisons[k].value < value) { | 531 | + if (comparisons[k].value <= value) { |
| 532 | comparisons.insert(k, Comparison(queryFiles[i], targetFiles[j], value)); | 532 | comparisons.insert(k, Comparison(queryFiles[i], targetFiles[j], value)); |
| 533 | break; | 533 | break; |
| 534 | } | 534 | } |
| @@ -539,6 +539,7 @@ class tailOutput : public Output | @@ -539,6 +539,7 @@ class tailOutput : public Output | ||
| 539 | comparisons.removeLast(); | 539 | comparisons.removeLast(); |
| 540 | while ((comparisons.size() > atLeast) && (comparisons.last().value < threshold)) | 540 | while ((comparisons.size() > atLeast) && (comparisons.last().value < threshold)) |
| 541 | comparisons.removeLast(); | 541 | comparisons.removeLast(); |
| 542 | + | ||
| 542 | lastValue = comparisons.last().value; | 543 | lastValue = comparisons.last().value; |
| 543 | comparisonsLock.unlock(); | 544 | comparisonsLock.unlock(); |
| 544 | } | 545 | } |
openbr/plugins/segmentation.cpp
0 → 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | +#include "openbr_internal.h" | ||
| 3 | +#include "openbr/core/opencvutils.h" | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Applies watershed segmentation. | ||
| 13 | + * \author Austin Blanton \cite imaus10 | ||
| 14 | + */ | ||
| 15 | +class WatershedSegmentationTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + void project(const Template &src, Template &dst) const | ||
| 19 | + { | ||
| 20 | + dst = src; | ||
| 21 | + | ||
| 22 | + Mat mod; | ||
| 23 | +// adaptiveThreshold(src.m(), src.m(), 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 33, 5); | ||
| 24 | + threshold(src.m(), mod, 0, 255, THRESH_BINARY+THRESH_OTSU); | ||
| 25 | + | ||
| 26 | + // findContours requires an 8-bit 1-channel image | ||
| 27 | + // and modifies its source image | ||
| 28 | + if (mod.depth() != CV_8U) OpenCVUtils::cvtUChar(mod, mod); | ||
| 29 | + if (mod.channels() != 1) OpenCVUtils::cvtGray(mod, mod); | ||
| 30 | + vector<vector<Point> > contours; | ||
| 31 | + vector<Vec4i> hierarchy; | ||
| 32 | + findContours(mod, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); | ||
| 33 | + | ||
| 34 | + // draw the contour delineations as 1,2,3... for input to watershed | ||
| 35 | + Mat markers = Mat::zeros(mod.size(), CV_32S); | ||
| 36 | + int compCount=0; | ||
| 37 | + for (int idx=0; idx>=0; idx=hierarchy[idx][0], compCount++) { | ||
| 38 | + drawContours(markers, contours, idx, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + Mat orig = src.m(); | ||
| 42 | + // watershed requires a 3-channel 8-bit image | ||
| 43 | + if (orig.channels() == 1) cvtColor(orig, orig, CV_GRAY2BGR); | ||
| 44 | + watershed(orig, markers); | ||
| 45 | + dst.file.set("SegmentsMask", QVariant::fromValue(markers)); | ||
| 46 | + dst.file.set("NumSegments", compCount); | ||
| 47 | + } | ||
| 48 | +}; | ||
| 49 | +BR_REGISTER(Transform, WatershedSegmentationTransform) | ||
| 50 | + | ||
| 51 | +} // namespace br | ||
| 52 | + | ||
| 53 | +#include "segmentation.moc" |
openbr/plugins/stasm4.cpp
| @@ -38,8 +38,10 @@ class StasmInitializer : public Initializer | @@ -38,8 +38,10 @@ class StasmInitializer : public Initializer | ||
| 38 | Globals->abbreviations.insert("RectFromStasmEyes","RectFromPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47],0.3,5.3)"); | 38 | Globals->abbreviations.insert("RectFromStasmEyes","RectFromPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47],0.3,5.3)"); |
| 39 | Globals->abbreviations.insert("RectFromStasmBrow","RectFromPoints([16,17,18,19,20,21,22,23,24,25,26,27],0.15,5)"); | 39 | Globals->abbreviations.insert("RectFromStasmBrow","RectFromPoints([16,17,18,19,20,21,22,23,24,25,26,27],0.15,5)"); |
| 40 | Globals->abbreviations.insert("RectFromStasmNose","RectFromPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],0.15,1.15)"); | 40 | Globals->abbreviations.insert("RectFromStasmNose","RectFromPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],0.15,1.15)"); |
| 41 | + Globals->abbreviations.insert("RectFromStasmNoseWithBridge", "RectFromPoints([21, 22, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],0.15,.6)"); | ||
| 41 | Globals->abbreviations.insert("RectFromStasmMouth","RectFromPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76],0.3,2)"); | 42 | Globals->abbreviations.insert("RectFromStasmMouth","RectFromPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76],0.3,2)"); |
| 42 | Globals->abbreviations.insert("RectFromStasmHair", "RectFromPoints([13,14,15],1.75,1.5)"); | 43 | Globals->abbreviations.insert("RectFromStasmHair", "RectFromPoints([13,14,15],1.75,1.5)"); |
| 44 | + Globals->abbreviations.insert("RectFromStasmJaw", "RectFromPoints([2,3,4,5,6,7,8,9,10],.25,1.6)"); | ||
| 43 | } | 45 | } |
| 44 | }; | 46 | }; |
| 45 | 47 |
openbr/plugins/stream.cpp
| @@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
| 7 | #include <QQueue> | 7 | #include <QQueue> |
| 8 | #include <QtConcurrent> | 8 | #include <QtConcurrent> |
| 9 | #include <opencv/highgui.h> | 9 | #include <opencv/highgui.h> |
| 10 | +#include <opencv2/highgui/highgui.hpp> | ||
| 10 | #include "openbr_internal.h" | 11 | #include "openbr_internal.h" |
| 11 | #include "openbr/core/common.h" | 12 | #include "openbr/core/common.h" |
| 12 | #include "openbr/core/opencvutils.h" | 13 | #include "openbr/core/opencvutils.h" |
| @@ -346,10 +347,11 @@ public: | @@ -346,10 +347,11 @@ public: | ||
| 346 | } | 347 | } |
| 347 | 348 | ||
| 348 | // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq ' | 349 | // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq ' |
| 349 | - char *firstFour = new char[4], *nextTwentyFour; | 350 | + char firstFour[4]; |
| 350 | seqFile.seekg(0, ios::beg); | 351 | seqFile.seekg(0, ios::beg); |
| 351 | seqFile.read(firstFour, 4); | 352 | seqFile.read(firstFour, 4); |
| 352 | - nextTwentyFour = readText(24); | 353 | + char nextTwentyFour[24]; |
| 354 | + readText(24, nextTwentyFour); | ||
| 353 | if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) { | 355 | if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) { |
| 354 | qDebug("Invalid header in seq file"); | 356 | qDebug("Invalid header in seq file"); |
| 355 | return false; | 357 | return false; |
| @@ -362,7 +364,8 @@ public: | @@ -362,7 +364,8 @@ public: | ||
| 362 | qDebug("Invalid header size"); | 364 | qDebug("Invalid header size"); |
| 363 | return false; | 365 | return false; |
| 364 | } | 366 | } |
| 365 | - char *desc = readText(512); | 367 | + char desc[512]; |
| 368 | + readText(512, desc); | ||
| 366 | basis.file.set("Description", QString(desc)); | 369 | basis.file.set("Description", QString(desc)); |
| 367 | 370 | ||
| 368 | width = readInt(); | 371 | width = readInt(); |
| @@ -413,9 +416,9 @@ public: | @@ -413,9 +416,9 @@ public: | ||
| 413 | // but there might be 16 extra bytes instead of 8... | 416 | // but there might be 16 extra bytes instead of 8... |
| 414 | if (i == 1) { | 417 | if (i == 1) { |
| 415 | seqFile.seekg(s, ios::beg); | 418 | seqFile.seekg(s, ios::beg); |
| 416 | - char *zero = new char[1]; | ||
| 417 | - seqFile.read(zero, 1); | ||
| 418 | - if (zero[0] == 0) { | 419 | + char zero; |
| 420 | + seqFile.read(&zero, 1); | ||
| 421 | + if (zero == 0) { | ||
| 419 | s += 8; | 422 | s += 8; |
| 420 | extra += 8; | 423 | extra += 8; |
| 421 | } | 424 | } |
| @@ -430,10 +433,12 @@ public: | @@ -430,10 +433,12 @@ public: | ||
| 430 | } | 433 | } |
| 431 | 434 | ||
| 432 | #ifdef CVMATIO | 435 | #ifdef CVMATIO |
| 433 | - QString f = basis.file.name; | ||
| 434 | - QString vbb = f.replace(f.lastIndexOf("."), 4, ".vbb"); | ||
| 435 | - vbb.replace(vbb.lastIndexOf("vid"), 3, "annotations"); | ||
| 436 | - annotations = TemplateList::fromGallery(File(vbb)); | 436 | + if (basis.file.contains("vbb")) { |
| 437 | + QString vbb = basis.file.get<QString>("vbb"); | ||
| 438 | + annotations = TemplateList::fromGallery(File(vbb)); | ||
| 439 | + } | ||
| 440 | +#else | ||
| 441 | + qWarning("cvmatio not installed, bounding boxes will not be available. Add -DBR_WITH_CVMATIO cmake flag to install."); | ||
| 437 | #endif | 442 | #endif |
| 438 | 443 | ||
| 439 | return true; | 444 | return true; |
| @@ -497,14 +502,13 @@ private: | @@ -497,14 +502,13 @@ private: | ||
| 497 | // apparently the text in seq files is 16 bit characters (UTF-16?) | 502 | // apparently the text in seq files is 16 bit characters (UTF-16?) |
| 498 | // since we don't really need the last byte, snad since it gets interpreted as | 503 | // since we don't really need the last byte, snad since it gets interpreted as |
| 499 | // a terminating char, let's just grab the first byte for storage | 504 | // a terminating char, let's just grab the first byte for storage |
| 500 | - char* readText(int bytes) | 505 | + void readText(int bytes, char * buffer) |
| 501 | { | 506 | { |
| 502 | - char *text = new char[bytes], *ret = new char[bytes/2]; | ||
| 503 | - seqFile.read(text, bytes); | 507 | + seqFile.read(buffer, bytes); |
| 504 | for (int i=0; i<bytes; i+=2) { | 508 | for (int i=0; i<bytes; i+=2) { |
| 505 | - ret[i/2] = text[i]; | 509 | + buffer[i/2] = buffer[i]; |
| 506 | } | 510 | } |
| 507 | - return ret; | 511 | + buffer[bytes/2] = '\0'; |
| 508 | } | 512 | } |
| 509 | 513 | ||
| 510 | protected: | 514 | protected: |
| @@ -736,7 +740,6 @@ protected: | @@ -736,7 +740,6 @@ protected: | ||
| 736 | frameSource = new VideoReader(); | 740 | frameSource = new VideoReader(); |
| 737 | } | 741 | } |
| 738 | } | 742 | } |
| 739 | - | ||
| 740 | open_res = frameSource->open(curr); | 743 | open_res = frameSource->open(curr); |
| 741 | if (!open_res) | 744 | if (!open_res) |
| 742 | { | 745 | { |
| @@ -1420,6 +1423,7 @@ public: | @@ -1420,6 +1423,7 @@ public: | ||
| 1420 | { | 1423 | { |
| 1421 | // Delete all the stages | 1424 | // Delete all the stages |
| 1422 | for (int i = 0; i < processingStages.size(); i++) { | 1425 | for (int i = 0; i < processingStages.size(); i++) { |
| 1426 | +// TODO: Are we releasing memory which is already freed? | ||
| 1423 | delete processingStages[i]; | 1427 | delete processingStages[i]; |
| 1424 | } | 1428 | } |
| 1425 | processingStages.clear(); | 1429 | processingStages.clear(); |
openbr/plugins/validate.cpp
| @@ -65,9 +65,9 @@ class CrossValidateTransform : public MetaTransform | @@ -65,9 +65,9 @@ class CrossValidateTransform : public MetaTransform | ||
| 65 | const QString label = partitionedData.at(j).file.get<QString>("Label"); | 65 | const QString label = partitionedData.at(j).file.get<QString>("Label"); |
| 66 | QList<int> subjectIndices = partitionedData.find("Label",label); | 66 | QList<int> subjectIndices = partitionedData.find("Label",label); |
| 67 | QList<int> removed; | 67 | QList<int> removed; |
| 68 | - // Remove test only data | 68 | + // Remove target only data |
| 69 | for (int k=subjectIndices.size()-1; k>=0; k--) | 69 | for (int k=subjectIndices.size()-1; k>=0; k--) |
| 70 | - if (partitionedData[subjectIndices[k]].file.getBool("testOnly")) { | 70 | + if (partitionedData[subjectIndices[k]].file.getBool("targetOnly")) { |
| 71 | removed.append(subjectIndices[k]); | 71 | removed.append(subjectIndices[k]); |
| 72 | subjectIndices.removeAt(k); | 72 | subjectIndices.removeAt(k); |
| 73 | } | 73 | } |
| @@ -108,6 +108,7 @@ class CrossValidateTransform : public MetaTransform | @@ -108,6 +108,7 @@ class CrossValidateTransform : public MetaTransform | ||
| 108 | // If we want to duplicate templates but use the same training data | 108 | // If we want to duplicate templates but use the same training data |
| 109 | // for all partitions (i.e. transforms.size() == 1), we need to | 109 | // for all partitions (i.e. transforms.size() == 1), we need to |
| 110 | // restrict the partition | 110 | // restrict the partition |
| 111 | + | ||
| 111 | int partition = src.file.get<int>("Partition", 0); | 112 | int partition = src.file.get<int>("Partition", 0); |
| 112 | partition = (partition >= transforms.size()) ? 0 : partition; | 113 | partition = (partition >= transforms.size()) ? 0 : partition; |
| 113 | transforms[partition]->project(src, dst); | 114 | transforms[partition]->project(src, dst); |
scripts/brpy/__init__.py
| @@ -12,6 +12,14 @@ def _var_string_args(n): | @@ -12,6 +12,14 @@ def _var_string_args(n): | ||
| 12 | s.extend(_string_args(n)) | 12 | s.extend(_string_args(n)) |
| 13 | return s | 13 | return s |
| 14 | 14 | ||
| 15 | +def _handle_string_func(func): | ||
| 16 | + def call_func(*args): | ||
| 17 | + howlong = func('', 0, *args) | ||
| 18 | + msg = 'x'*(howlong-1) | ||
| 19 | + func(msg, howlong, *args) | ||
| 20 | + return msg | ||
| 21 | + return call_func | ||
| 22 | + | ||
| 15 | def init_brpy(br_loc='/usr/local/lib'): | 23 | def init_brpy(br_loc='/usr/local/lib'): |
| 16 | """Takes the ctypes lib object for br and initializes all function inputs and outputs""" | 24 | """Takes the ctypes lib object for br and initializes all function inputs and outputs""" |
| 17 | br_loc += '/libopenbr.%s' | 25 | br_loc += '/libopenbr.%s' |
| @@ -48,9 +56,14 @@ def init_brpy(br_loc='/usr/local/lib'): | @@ -48,9 +56,14 @@ def init_brpy(br_loc='/usr/local/lib'): | ||
| 48 | br.br_is_classifier.restype = c_bool | 56 | br.br_is_classifier.restype = c_bool |
| 49 | br.br_make_mask.argtypes = _string_args(3) | 57 | br.br_make_mask.argtypes = _string_args(3) |
| 50 | br.br_make_pairwise_mask.argtypes = _string_args(3) | 58 | br.br_make_pairwise_mask.argtypes = _string_args(3) |
| 51 | - br.br_most_recent_message.restype = c_char_p | ||
| 52 | - br.br_objects.argtypes = _string_args(2) + [c_bool] | ||
| 53 | - br.br_objects.restype = c_char_p | 59 | + br.br_most_recent_message.argtypes = [c_char_p, c_int] |
| 60 | + br.br_most_recent_message.restype = c_int | ||
| 61 | + func = br.br_most_recent_message.__call__ | ||
| 62 | + br.br_most_recent_message = _handle_string_func(func) | ||
| 63 | + br.br_objects.argtypes = [c_char_p, c_int] + _string_args(2) + [c_bool] | ||
| 64 | + br.br_objects.restype = c_int | ||
| 65 | + func2 = br.br_objects.__call__ | ||
| 66 | + br.br_objects = _handle_string_func(func2) | ||
| 54 | br.br_plot.argtypes = plot_args | 67 | br.br_plot.argtypes = plot_args |
| 55 | br.br_plot.restype = c_bool | 68 | br.br_plot.restype = c_bool |
| 56 | br.br_plot_detection.argtypes = plot_args | 69 | br.br_plot_detection.argtypes = plot_args |
| @@ -61,7 +74,10 @@ def init_brpy(br_loc='/usr/local/lib'): | @@ -61,7 +74,10 @@ def init_brpy(br_loc='/usr/local/lib'): | ||
| 61 | br.br_plot_metadata.restype = c_bool | 74 | br.br_plot_metadata.restype = c_bool |
| 62 | br.br_progress.restype = c_float | 75 | br.br_progress.restype = c_float |
| 63 | br.br_read_pipe.argtypes = [c_char_p, POINTER(c_int), POINTER(POINTER(c_char_p))] | 76 | br.br_read_pipe.argtypes = [c_char_p, POINTER(c_int), POINTER(POINTER(c_char_p))] |
| 64 | - br.br_scratch_path.restype = c_char_p | 77 | + br.br_scratch_path.argtypes = [c_char_p, c_int] |
| 78 | + br.br_scratch_path.restype = c_int | ||
| 79 | + func3 = br.br_scratch_path.__call__ | ||
| 80 | + br.br_scratch_path = _handle_string_func(func3) | ||
| 65 | br.br_sdk_path.restype = c_char_p | 81 | br.br_sdk_path.restype = c_char_p |
| 66 | br.br_get_header.argtypes = [c_char_p, POINTER(c_char_p), POINTER(c_char_p)] | 82 | br.br_get_header.argtypes = [c_char_p, POINTER(c_char_p), POINTER(c_char_p)] |
| 67 | br.br_set_header.argtypes = _string_args(3) | 83 | br.br_set_header.argtypes = _string_args(3) |
| @@ -88,11 +104,15 @@ def init_brpy(br_loc='/usr/local/lib'): | @@ -88,11 +104,15 @@ def init_brpy(br_loc='/usr/local/lib'): | ||
| 88 | br.br_img_channels.restype = c_int | 104 | br.br_img_channels.restype = c_int |
| 89 | br.br_img_is_empty.argtypes = [c_void_p] | 105 | br.br_img_is_empty.argtypes = [c_void_p] |
| 90 | br.br_img_is_empty.restype = c_bool | 106 | br.br_img_is_empty.restype = c_bool |
| 91 | - br.br_get_filename.argtypes = [c_void_p] | ||
| 92 | - br.br_get_filename.restype = c_char_p | 107 | + br.br_get_filename.argtypes = [c_char_p, c_int, c_void_p] |
| 108 | + br.br_get_filename.restype = c_int | ||
| 109 | + func4 = br.br_get_filename.__call__ | ||
| 110 | + br.br_get_filename = _handle_string_func(func4) | ||
| 93 | br.br_set_filename.argtypes = [c_void_p, c_char_p] | 111 | br.br_set_filename.argtypes = [c_void_p, c_char_p] |
| 94 | - br.br_get_metadata_string.argtypes = [c_void_p, c_char_p] | ||
| 95 | - br.br_get_metadata_string.restype = c_char_p | 112 | + br.br_get_metadata_string.argtypes = [c_char_p, c_int, c_void_p, c_char_p] |
| 113 | + br.br_get_metadata_string.restype = c_int | ||
| 114 | + func5 = br.br_get_metadata_string.__call__ | ||
| 115 | + br.br_get_metadata_string = _handle_string_func(func5) | ||
| 96 | br.br_enroll_template.argtypes = [c_void_p] | 116 | br.br_enroll_template.argtypes = [c_void_p] |
| 97 | br.br_enroll_template.restype = c_void_p | 117 | br.br_enroll_template.restype = c_void_p |
| 98 | br.br_enroll_template_list.argtypes = [c_void_p] | 118 | br.br_enroll_template_list.argtypes = [c_void_p] |
scripts/downloadDatasets.sh
| @@ -51,6 +51,8 @@ if [ ! -d ../data/CaltechPedestrians/vid ]; then | @@ -51,6 +51,8 @@ if [ ! -d ../data/CaltechPedestrians/vid ]; then | ||
| 51 | tar -xf $fname | 51 | tar -xf $fname |
| 52 | done | 52 | done |
| 53 | rm *.tar | 53 | rm *.tar |
| 54 | + ./writeCaltechPedestrianSigset.sh 0 5 train > ../data/CaltechPedestrians/train.xml | ||
| 55 | + ./writeCaltechPedestrianSigset.sh 6 10 test > ../data/CaltechPedestrians/test.xml | ||
| 54 | mv set* ../data/CaltechPedestrians/vid | 56 | mv set* ../data/CaltechPedestrians/vid |
| 55 | if hash curl 2>/dev/null; then | 57 | if hash curl 2>/dev/null; then |
| 56 | curl -OL "$prefix/annotations.zip" | 58 | curl -OL "$prefix/annotations.zip" |
scripts/writeCaltechPedestrianSigset.sh
0 → 100755
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +echo '<?xml version="1.0" encoding="UTF-8"?>' | ||
| 4 | +echo '<biometric-signature-set>' | ||
| 5 | +for ((set=$1; set <= $2; set++)); do | ||
| 6 | + echo -e "\t<biometric-signature name=\"\">" | ||
| 7 | + for vid in `printf "set%02d/*.seq" $set`; do | ||
| 8 | + if [ $3 == "train" ]; then | ||
| 9 | + vbb=`echo "vbb=\"annotations/$vid\"" | sed s/seq/vbb/` | ||
| 10 | + fi | ||
| 11 | + printf "\t\t<presentation file-name=\"vid/$vid\" $vbb />\n" | ||
| 12 | + done | ||
| 13 | + echo -e "\t</biometric-signature>" | ||
| 14 | +done | ||
| 15 | +echo '</biometric-signature-set>' |
scripts/writeKTHSigset.sh
100644 → 100755
share/openbr/cmake/Findcvmatio.cmake
| 1 | set(CVMATIO_DIR "${BR_THIRDPARTY_DIR}/cvmatio") | 1 | set(CVMATIO_DIR "${BR_THIRDPARTY_DIR}/cvmatio") |
| 2 | if(NOT EXISTS ${CVMATIO_DIR}) | 2 | if(NOT EXISTS ${CVMATIO_DIR}) |
| 3 | # download source from github | 3 | # download source from github |
| 4 | - execute_process(COMMAND "git" "clone" "https://github.com/biometrics/cvmatio.git" WORKING_DIRECTORY ${BR_THIRDPARTY_DIR}) | 4 | + execute_process(COMMAND "git" "clone" "https://github.com/hbristow/cvmatio.git" WORKING_DIRECTORY ${BR_THIRDPARTY_DIR}) |
| 5 | else() | 5 | else() |
| 6 | # update the source | 6 | # update the source |
| 7 | execute_process(COMMAND "git" "pull" WORKING_DIRECTORY ${CVMATIO_DIR}) | 7 | execute_process(COMMAND "git" "pull" WORKING_DIRECTORY ${CVMATIO_DIR}) |