Commit 40b8933df3fc1355305961c5bd0d99de8f9eca9d

Authored by sklum
2 parents 8917c959 0e316414

Merge branch 'master' of https://github.com/biometrics/openbr

Showing 62 changed files with 1010 additions and 282 deletions
.gitignore
1 ### Repository Specific ### 1 ### Repository Specific ###
2 3rdparty/LatentSDK* 2 3rdparty/LatentSDK*
3 3rdparty/pittpatt* 3 3rdparty/pittpatt*
  4 +3rdparty/cvmatio
4 data/*/img 5 data/*/img
5 data/*/vid 6 data/*/vid
6 data/PCSO/* 7 data/PCSO/*
@@ -39,4 +40,10 @@ scripts/results @@ -39,4 +40,10 @@ scripts/results
39 ### autogenerated sigsets ### 40 ### autogenerated sigsets ###
40 data/INRIAPerson/sigset 41 data/INRIAPerson/sigset
41 data/KTH/sigset 42 data/KTH/sigset
  43 +data/CaltechPedestrians/annotations
  44 +data/CaltechPedestrians/*.xml
42 45
  46 +### Sublime ###
  47 +*.check_cache
  48 +*.sublime-project
  49 +*.sublime-workspace
CMakeLists.txt
@@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 2.8.9) @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 2.8.9)
4 # Global settings 4 # Global settings
5 set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr") 5 set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr")
6 set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") 6 set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts")
  7 +set(BR_THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty")
7 set(CMAKE_AUTOMOC ON) 8 set(CMAKE_AUTOMOC ON)
8 set(CPACK_PACKAGE_NAME "OpenBR") 9 set(CPACK_PACKAGE_NAME "OpenBR")
9 set(CPACK_PACKAGE_VENDOR "OpenBiometrics") 10 set(CPACK_PACKAGE_VENDOR "OpenBiometrics")
@@ -90,6 +91,18 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS}) @@ -90,6 +91,18 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS})
90 # Find Alphanum 91 # Find Alphanum
91 find_package(Alphanum REQUIRED) 92 find_package(Alphanum REQUIRED)
92 93
  94 +# Find cvmatio (if using it)
  95 +set(BR_WITH_CVMATIO OFF CACHE BOOL "Build with cvmatio library to read Matlab data files (required to use Caltech Pedestrians dataset)")
  96 +if(${BR_WITH_CVMATIO})
  97 + find_package(cvmatio REQUIRED)
  98 + add_definitions(-DCVMATIO)
  99 + add_subdirectory(${CVMATIO_DIR})
  100 + include_directories(${CVMATIO_DIR}/include)
  101 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${CVMATIO_DIR}/src/MatlabIO.cpp)
  102 + link_directories(${CVMATIO_LIB_DIR})
  103 + set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} cvmatio)
  104 +endif()
  105 +
93 # Compiler flags 106 # Compiler flags
94 if(UNIX) 107 if(UNIX)
95 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-strict-overflow -fvisibility=hidden -fno-omit-frame-pointer") 108 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-strict-overflow -fvisibility=hidden -fno-omit-frame-pointer")
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 [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/biometrics/openbr/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 16 [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/biometrics/openbr/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
17 -  
app/CMakeLists.txt
@@ -5,4 +5,6 @@ add_subdirectory(br) @@ -5,4 +5,6 @@ add_subdirectory(br)
5 add_subdirectory(examples) 5 add_subdirectory(examples)
6 6
7 # Build OpenBR GUI application 7 # Build OpenBR GUI application
8 -add_subdirectory(br-gui) 8 +if(NOT ${BR_EMBEDDED})
  9 + add_subdirectory(br-gui)
  10 +endif()
app/br/br.cpp
@@ -158,12 +158,17 @@ public: @@ -158,12 +158,17 @@ 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 printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*"));
@@ -177,11 +182,10 @@ public: @@ -177,11 +182,10 @@ public:
177 check(parc == 1, "Incorrect parameter count for 'daemon'."); 182 check(parc == 1, "Incorrect parameter count for 'daemon'.");
178 daemon = true; 183 daemon = true;
179 daemon_pipe = parv[0]; 184 daemon_pipe = parv[0];
180 - } else if (!strcmp(fun,"slave")) { 185 + } else if (!strcmp(fun, "slave")) {
181 check(parc == 1, "Incorrect parameter count for 'slave'"); 186 check(parc == 1, "Incorrect parameter count for 'slave'");
182 br_slave_process(parv[0]); 187 br_slave_process(parv[0]);
183 - }  
184 - else if (!strcmp(fun, "exit")) { 188 + } else if (!strcmp(fun, "exit")) {
185 check(parc == 0, "No parameters expected for 'exit'."); 189 check(parc == 0, "No parameters expected for 'exit'.");
186 daemon = false; 190 daemon = false;
187 } else if (!strcmp(fun, "getHeader")) { 191 } else if (!strcmp(fun, "getHeader")) {
@@ -245,6 +249,7 @@ private: @@ -245,6 +249,7 @@ private:
245 "\n" 249 "\n"
246 "==== Miscellaneous ====\n" 250 "==== Miscellaneous ====\n"
247 "-help\n" 251 "-help\n"
  252 + "-gui\n"
248 "-objects [abstraction [implementation]]\n" 253 "-objects [abstraction [implementation]]\n"
249 "-about\n" 254 "-about\n"
250 "-version\n" 255 "-version\n"
@@ -255,7 +260,7 @@ private: @@ -255,7 +260,7 @@ private:
255 260
256 int main(int argc, char *argv[]) 261 int main(int argc, char *argv[])
257 { 262 {
258 - br_initialize(argc, argv); 263 + br_initialize(argc, argv, "", argc >= 2 && !strcmp(argv[1], "-gui"));
259 264
260 FakeMain *fakeMain = new FakeMain(argc, argv); 265 FakeMain *fakeMain = new FakeMain(argc, argv);
261 QThreadPool::globalInstance()->start(fakeMain); 266 QThreadPool::globalInstance()->start(fakeMain);
data/CaltechPedestrians/README.md 0 โ†’ 100644
  1 +## Caltech Pedestrians Dataset
  2 +The Caltech Pedestrian Dataset consists of approximately 10 hours of 640x480 30Hz video taken from a vehicle driving through regular traffic in an urban environment. About 250,000 frames (in 137 approximately minute long segments) with a total of 350,000 bounding boxes and 2300 unique pedestrians were annotated. The annotation includes temporal correspondence between bounding boxes and detailed occlusion labels.
  3 +* [Website](http://www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/)
openbr/CMakeLists.txt
@@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL &quot;Build Janus implementatio @@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL &quot;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 &amp;matrix, QString *targetSigset, QString *querySi @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &amp;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;
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/common.cpp
@@ -63,3 +63,16 @@ QList&lt;int&gt; Common::RandSample(int n, const QSet&lt;int&gt; &amp;values, bool unique) @@ -63,3 +63,16 @@ QList&lt;int&gt; Common::RandSample(int n, const QSet&lt;int&gt; &amp;values, bool unique)
63 } 63 }
64 return samples; 64 return samples;
65 } 65 }
  66 +
  67 +QList<float> Common::linspace(float start, float stop, int n) {
  68 + float delta = (stop - start) / (n - 1);
  69 + float curValue = start;
  70 + QList<float> spaced;
  71 + spaced.reserve(n);
  72 + spaced.append(start);
  73 + for (int i = 1; i < (n - 1); i++) {
  74 + spaced.append(curValue += delta);
  75 + }
  76 + spaced.append(stop);
  77 + return spaced;
  78 +}
openbr/core/common.h
@@ -253,6 +253,11 @@ QList&lt;int&gt; RandSample(int n, const QList&lt;T&gt; &amp;weights, bool unique = false) @@ -253,6 +253,11 @@ QList&lt;int&gt; RandSample(int n, const QList&lt;T&gt; &amp;weights, bool unique = false)
253 } 253 }
254 254
255 /*! 255 /*!
  256 + * \brief See Matlab function linspace() for documentation.
  257 + */
  258 +QList<float> linspace(float start, float stop, int n);
  259 +
  260 +/*!
256 * \brief See Matlab function unique() for documentation. 261 * \brief See Matlab function unique() for documentation.
257 */ 262 */
258 template <typename T> 263 template <typename T>
openbr/core/core.cpp
@@ -254,6 +254,56 @@ struct AlgorithmCore @@ -254,6 +254,56 @@ struct AlgorithmCore
254 Globals->blockSize = old_block_size; 254 Globals->blockSize = old_block_size;
255 } 255 }
256 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 +
257 void compare(File targetGallery, File queryGallery, File output) 307 void compare(File targetGallery, File queryGallery, File output)
258 { 308 {
259 qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), 309 qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()),
@@ -499,6 +549,14 @@ void br::Cat(const QStringList &amp;inputGalleries, const QString &amp;outputGallery) @@ -499,6 +549,14 @@ void br::Cat(const QStringList &amp;inputGalleries, const QString &amp;outputGallery)
499 } 549 }
500 } 550 }
501 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 +
502 QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess) 560 QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess)
503 { 561 {
504 if (!preprocess) 562 if (!preprocess)
openbr/core/eigenutils.cpp
@@ -54,3 +54,16 @@ void printEigen(Eigen::MatrixXd X) { @@ -54,3 +54,16 @@ void printEigen(Eigen::MatrixXd X) {
54 qDebug() << str; 54 qDebug() << str;
55 } 55 }
56 } 56 }
  57 +void printEigen(Eigen::MatrixXf X) {
  58 + for (int i = 0; i < X.rows(); i++) {
  59 + QString str;
  60 + for (int j = 0; j < X.cols(); j++) {
  61 + str.append(QString::number(X(i,j)) + " ");
  62 + }
  63 + qDebug() << str;
  64 + }
  65 +}
  66 +
  67 +void printSize(Eigen::MatrixXf X) {
  68 + qDebug() << "Rows=" << X.rows() << "\tCols=" << X.cols();
  69 +}
openbr/core/eigenutils.h
@@ -26,6 +26,8 @@ void writeEigen(Eigen::MatrixXd X, QString filename); @@ -26,6 +26,8 @@ void writeEigen(Eigen::MatrixXd X, QString filename);
26 void writeEigen(Eigen::VectorXd X, QString filename); 26 void writeEigen(Eigen::VectorXd X, QString filename);
27 void writeEigen(Eigen::VectorXf X, QString filename); 27 void writeEigen(Eigen::VectorXf X, QString filename);
28 void printEigen(Eigen::MatrixXd X); 28 void printEigen(Eigen::MatrixXd X);
  29 +void printEigen(Eigen::MatrixXf X);
  30 +void printSize(Eigen::MatrixXf X);
29 31
30 template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> 32 template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
31 inline QDataStream &operator<<(QDataStream &stream, const Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > &mat) 33 inline QDataStream &operator<<(QDataStream &stream, const Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > &mat)
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
@@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
22 #include <QString> 22 #include <QString>
23 #include <QStringList> 23 #include <QStringList>
24 #include <opencv2/core/core.hpp> 24 #include <opencv2/core/core.hpp>
  25 +#include <assert.h>
25 26
26 namespace OpenCVUtils 27 namespace OpenCVUtils
27 { 28 {
openbr/gui/tail.cpp
1 #include <QtConcurrentRun> 1 #include <QtConcurrentRun>
2 2
3 #include "tail.h" 3 #include "tail.h"
  4 +#include <assert.h>
4 5
5 using namespace br; 6 using namespace br;
6 7
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;
1 -Subproject commit 0eaa00f19256fee2f24033ff68b526ea6320624d 1 +Subproject commit f8d9c869c821cc032d092ab1274da8f3cabf5eb7
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,6 +24,7 @@ @@ -24,6 +24,7 @@
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
@@ -121,9 +122,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], @@ -121,9 +122,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); 122 Fuse(QtUtils::toStringList(num_input_simmats, input_simmats), normalization, fusion, output_simmat);
122 } 123 }
123 124
124 -void br_initialize(int &argc, char *argv[], const char *sdk_path) 125 +void br_initialize(int &argc, char *argv[], const char *sdk_path, bool use_gui)
125 { 126 {
126 - Context::initialize(argc, argv, sdk_path); 127 + Context::initialize(argc, argv, sdk_path, use_gui);
127 } 128 }
128 129
129 void br_initialize_default() 130 void br_initialize_default()
@@ -381,8 +382,9 @@ bool br_img_is_empty(br_template tmpl) @@ -381,8 +382,9 @@ bool br_img_is_empty(br_template tmpl)
381 382
382 const char* br_get_filename(br_template tmpl) 383 const char* br_get_filename(br_template tmpl)
383 { 384 {
384 - Template *t = reinterpret_cast<Template*>(tmpl);  
385 - return t->file.name.toStdString().c_str(); 385 + static QByteArray buffer;
  386 + buffer = reinterpret_cast<Template*>(tmpl)->file.name.toLocal8Bit();
  387 + return buffer.data();
386 } 388 }
387 389
388 void br_set_filename(br_template tmpl, const char *filename) 390 void br_set_filename(br_template tmpl, const char *filename)
@@ -470,3 +472,8 @@ void br_close_gallery(br_gallery gallery) @@ -470,3 +472,8 @@ void br_close_gallery(br_gallery gallery)
470 Gallery *gal = reinterpret_cast<Gallery*>(gallery); 472 Gallery *gal = reinterpret_cast<Gallery*>(gallery);
471 delete gal; 473 delete gal;
472 } 474 }
  475 +
  476 +void br_deduplicate(const char *input_gallery, const char *output_gallery, const char *threshold)
  477 +{
  478 + br::Deduplicate(input_gallery, output_gallery, threshold);
  479 +}
openbr/openbr.h
@@ -67,6 +67,17 @@ BR_EXPORT const char *br_about(); @@ -67,6 +67,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); 67 BR_EXPORT void br_cat(int num_input_galleries, const char *input_galleries[], const char *output_gallery);
68 68
69 /*! 69 /*!
  70 + * \brief Removes duplicate templates in a gallery.
  71 + * \param input_gallery Gallery to be deduplicated.
  72 + * \param output_gallery Deduplicated gallery.
  73 + * \param threshold Comparisons with a match score >= this value are designated to be duplicates.
  74 + * \note If a gallery contains n duplicates, the first n-1 duplicates in the gallery will be removed and the nth will be kept.
  75 + * \note Users are encouraged to use binary gallery formats as the entire gallery is read into memory in one call to Gallery::read.
  76 + */
  77 +
  78 +BR_EXPORT void br_deduplicate(const char *input_gallery, const char *output_gallery, const char *threshold);
  79 +
  80 +/*!
70 * \brief Clusters one or more similarity matrices into a list of subjects. 81 * \brief Clusters one or more similarity matrices into a list of subjects.
71 * 82 *
72 * A similarity matrix is a type of br::Output. The current clustering algorithm is a simplified implementation of \cite zhu11. 83 * A similarity matrix is a type of br::Output. The current clustering algorithm is a simplified implementation of \cite zhu11.
@@ -213,7 +224,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], @@ -213,7 +224,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[],
213 * \brief Wraps br::Context::initialize() 224 * \brief Wraps br::Context::initialize()
214 * \see br_finalize 225 * \see br_finalize
215 */ 226 */
216 -BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = ""); 227 +BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = "", bool use_gui = false);
217 /*! 228 /*!
218 * \brief Wraps br::Context::initialize() with default arguments. 229 * \brief Wraps br::Context::initialize() with default arguments.
219 * \see br_finalize 230 * \see br_finalize
openbr/openbr_plugin.cpp
@@ -44,12 +44,6 @@ using namespace cv; @@ -44,12 +44,6 @@ using namespace cv;
44 44
45 Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState) 45 Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState)
46 46
47 -// Some globals used to transfer data to Context::messageHandler so that  
48 -// we can restart the process if we try and fail to create a QApplication.  
49 -static bool creating_qapp = false;  
50 -static int * argc_ptr = NULL;  
51 -static char ** argv_ptr = NULL;  
52 -  
53 /* File - public methods */ 47 /* File - public methods */
54 // Note that the convention for displaying metadata is as follows: 48 // Note that the convention for displaying metadata is as follows:
55 // [] for lists in which argument order does not matter (e.g. [FTO=false, Index=0]), 49 // [] for lists in which argument order does not matter (e.g. [FTO=false, Index=0]),
@@ -848,13 +842,7 @@ int br::Context::blocks(int size) const @@ -848,13 +842,7 @@ int br::Context::blocks(int size) const
848 842
849 bool br::Context::contains(const QString &name) 843 bool br::Context::contains(const QString &name)
850 { 844 {
851 - QByteArray bytes = name.toLocal8Bit();  
852 - const char * c_name = bytes.constData();  
853 -  
854 - for (int i=0; i<metaObject()->propertyCount(); i++)  
855 - if (!strcmp(c_name, metaObject()->property(i).name()))  
856 - return true;  
857 - return false; 845 + return property(qPrintable(name)).isValid();
858 } 846 }
859 847
860 void br::Context::printStatus() 848 void br::Context::printStatus()
@@ -907,42 +895,30 @@ bool br::Context::checkSDKPath(const QString &amp;sdkPath) @@ -907,42 +895,30 @@ bool br::Context::checkSDKPath(const QString &amp;sdkPath)
907 // We create our own when the user hasn't 895 // We create our own when the user hasn't
908 static QCoreApplication *application = NULL; 896 static QCoreApplication *application = NULL;
909 897
910 -void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool use_gui) 898 +void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useGui)
911 { 899 {
912 - for (int i=0; i < argc; i ++)  
913 - {  
914 - if (strcmp("-useGui", argv[i]) == 0) {  
915 - const char * val = i+1 < argc ? argv[i+1] : "";  
916 - if (strcmp(val, "false") ==0 || strcmp(val, "0") == 0)  
917 - use_gui = false;  
918 - break;  
919 - }  
920 - }  
921 -  
922 qInstallMessageHandler(messageHandler); 900 qInstallMessageHandler(messageHandler);
923 901
  902 + QString sep;
  903 +#ifndef _WIN32
  904 + useGui = useGui && (getenv("DISPLAY") != NULL);
  905 + sep = ":";
  906 +#else
  907 + sep = ";";
  908 +#endif // not _WIN32
  909 +
924 // We take in argc as a reference due to: 910 // We take in argc as a reference due to:
925 // https://bugreports.qt-project.org/browse/QTBUG-5637 911 // https://bugreports.qt-project.org/browse/QTBUG-5637
926 // QApplication should be initialized before anything else. 912 // QApplication should be initialized before anything else.
927 // Since we can't ensure that it gets deleted last, we never delete it. 913 // Since we can't ensure that it gets deleted last, we never delete it.
928 if (QCoreApplication::instance() == NULL) { 914 if (QCoreApplication::instance() == NULL) {
929 #ifndef BR_EMBEDDED 915 #ifndef BR_EMBEDDED
930 - if (use_gui) {  
931 - // Set up variables to be used in the message handler if this fails.  
932 - // Just so you know, we  
933 - creating_qapp = true;  
934 - argc_ptr = &argc;  
935 - argv_ptr = argv;  
936 -  
937 - application = new QApplication(argc, argv);  
938 - creating_qapp = false;  
939 - }  
940 - else {  
941 - application = new QCoreApplication(argc, argv);  
942 - }  
943 -#else 916 + if (useGui) application = new QApplication(argc, argv);
  917 + else application = new QCoreApplication(argc, argv);
  918 +#else // not BR_EMBEDDED
  919 + useGui = false;
944 application = new QCoreApplication(argc, argv); 920 application = new QCoreApplication(argc, argv);
945 -#endif 921 +#endif // BR_EMBEDDED
946 } 922 }
947 923
948 QCoreApplication::setOrganizationName(COMPANY_NAME); 924 QCoreApplication::setOrganizationName(COMPANY_NAME);
@@ -965,14 +941,14 @@ void br::Context::initialize(int &amp;argc, char *argv[], QString sdkPath, bool use_ @@ -965,14 +941,14 @@ void br::Context::initialize(int &amp;argc, char *argv[], QString sdkPath, bool use_
965 941
966 Globals = new Context(); 942 Globals = new Context();
967 Globals->init(File()); 943 Globals->init(File());
968 - Globals->useGui = use_gui;  
969 - 944 + Globals->useGui = useGui;
970 945
971 Common::seedRNG(); 946 Common::seedRNG();
972 947
973 // Search for SDK 948 // Search for SDK
974 if (sdkPath.isEmpty()) { 949 if (sdkPath.isEmpty()) {
975 QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); 950 QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath();
  951 + checkPaths << QString(getenv("PATH")).split(sep, QString::SkipEmptyParts);
976 952
977 bool foundSDK = false; 953 bool foundSDK = false;
978 foreach (const QString &path, checkPaths) { 954 foreach (const QString &path, checkPaths) {
@@ -1035,26 +1011,6 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte @@ -1035,26 +1011,6 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte
1035 static QMutex generalLock; 1011 static QMutex generalLock;
1036 QMutexLocker locker(&generalLock); 1012 QMutexLocker locker(&generalLock);
1037 1013
1038 - // If we are trying to create a QApplication, and get a fatal, then restart the process  
1039 - // with useGui set to 0.  
1040 - if (creating_qapp && type == QtFatalMsg)  
1041 - {  
1042 - // re-launch process with useGui = 0  
1043 - std::cout << "Failed to initialize gui, restarting with -useGui 0" << std::endl;  
1044 - QStringList arguments;  
1045 - arguments.append("-useGui");  
1046 - arguments.append("0");  
1047 - for (int i=1; i < *argc_ptr; i++)  
1048 - {  
1049 - arguments.append(argv_ptr[i]);  
1050 - }  
1051 - // QProcess::execute blocks until the other process completes.  
1052 - QProcess::execute(argv_ptr[0], arguments);  
1053 - // have to unlock this for some reason  
1054 - locker.unlock();  
1055 - std::exit(0);  
1056 - }  
1057 -  
1058 QString txt; 1014 QString txt;
1059 if (type == QtDebugMsg) { 1015 if (type == QtDebugMsg) {
1060 if (Globals->quiet) return; 1016 if (Globals->quiet) return;
@@ -1076,8 +1032,13 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte @@ -1076,8 +1032,13 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte
1076 Globals->logFile.flush(); 1032 Globals->logFile.flush();
1077 } 1033 }
1078 1034
1079 - if (type == QtFatalMsg) 1035 + if (type == QtFatalMsg) {
  1036 +#ifdef _WIN32
  1037 + QCoreApplication::quit(); // abort() hangs the console on Windows for some reason related to the event loop not being exited
  1038 +#else // not _WIN32
1080 abort(); // We abort so we can get a stack trace back to the code that triggered the message. 1039 abort(); // We abort so we can get a stack trace back to the code that triggered the message.
  1040 +#endif // _WIN32
  1041 + }
1081 } 1042 }
1082 1043
1083 Context *br::Globals = NULL; 1044 Context *br::Globals = NULL;
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
@@ -794,12 +795,12 @@ public: @@ -794,12 +795,12 @@ public:
794 * By default <tt>share/openbr/openbr.bib</tt> will be searched for relative to: 795 * By default <tt>share/openbr/openbr.bib</tt> will be searched for relative to:
795 * -# The working directory 796 * -# The working directory
796 * -# The executable's location 797 * -# The executable's location
797 - * \param use_gui Create a QApplication instead of a QCoreApplication. 798 + * \param useGui Create a QApplication instead of a QCoreApplication.
798 * \note Tiggers \em abort() on failure to locate <tt>share/openbr/openbr.bib</tt>. 799 * \note Tiggers \em abort() on failure to locate <tt>share/openbr/openbr.bib</tt>.
799 * \note <a href="http://qt-project.org/">Qt</a> users should instead call this <i>after</i> initializing QApplication. 800 * \note <a href="http://qt-project.org/">Qt</a> users should instead call this <i>after</i> initializing QApplication.
800 * \see finalize 801 * \see finalize
801 */ 802 */
802 - static void initialize(int &argc, char *argv[], QString sdkPath = "", bool use_gui = true); 803 + static void initialize(int &argc, char *argv[], QString sdkPath = "", bool useGui = true);
803 804
804 /*! 805 /*!
805 * \brief Call \em once at the end of the application to deallocate global variables. 806 * \brief Call \em once at the end of the application to deallocate global variables.
@@ -1371,6 +1372,14 @@ BR_EXPORT void Convert(const File &amp;fileType, const File &amp;inputFile, const File &amp; @@ -1371,6 +1372,14 @@ BR_EXPORT void Convert(const File &amp;fileType, const File &amp;inputFile, const File &amp;
1371 */ 1372 */
1372 BR_EXPORT void Cat(const QStringList &inputGalleries, const QString &outputGallery); 1373 BR_EXPORT void Cat(const QStringList &inputGalleries, const QString &outputGallery);
1373 1374
  1375 +/*!
  1376 + * \brief Deduplicate a gallery.
  1377 + * \param inputGallery Gallery to deduplicate.
  1378 + * \param outputGallery Gallery to store the deduplicated result.
  1379 + * \param threshold Match score threshold to determine duplicates.
  1380 + */
  1381 +BR_EXPORT void Deduplicate(const File &inputGallery, const File &outputGallery, const QString &threshold);
  1382 +
1374 /*! @}*/ 1383 /*! @}*/
1375 1384
1376 } // namespace br 1385 } // 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,6 +18,7 @@ @@ -18,6 +18,7 @@
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"
@@ -61,6 +62,7 @@ private: @@ -61,6 +62,7 @@ private:
61 (a.m().type() != b.m().type())) 62 (a.m().type() != b.m().type()))
62 return -std::numeric_limits<float>::max(); 63 return -std::numeric_limits<float>::max();
63 64
  65 +// TODO: this max value is never returned based on the switch / default
64 float result = std::numeric_limits<float>::max(); 66 float result = std::numeric_limits<float>::max();
65 switch (metric) { 67 switch (metric) {
66 case Correlation: 68 case Correlation:
@@ -386,5 +388,67 @@ class OnlineDistance : public Distance @@ -386,5 +388,67 @@ class OnlineDistance : public Distance
386 388
387 BR_REGISTER(Distance, OnlineDistance) 389 BR_REGISTER(Distance, OnlineDistance)
388 390
  391 +/*!
  392 + * \ingroup distances
  393 + * \brief Attenuation function based distance from attributes
  394 + * \author Scott Klum \cite sklum
  395 + */
  396 +class AttributeDistance : public Distance
  397 +{
  398 + Q_OBJECT
  399 + Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false)
  400 + BR_PROPERTY(QString, attribute, QString())
  401 +
  402 + float compare(const Template &target, const Template &query) const
  403 + {
  404 + float queryValue = query.file.get<float>(attribute);
  405 + float targetValue = target.file.get<float>(attribute);
  406 +
  407 + // TODO: Set this magic number to something meaningful
  408 + float stddev = 1;
  409 +
  410 + if (queryValue == targetValue) return 1;
  411 + else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2));
  412 + }
  413 +};
  414 +
  415 +BR_REGISTER(Distance, AttributeDistance)
  416 +
  417 +/*!
  418 + * \ingroup distances
  419 + * \brief Sum match scores across multiple distances
  420 + * \author Scott Klum \cite sklum
  421 + */
  422 +class SumDistance : public Distance
  423 +{
  424 + Q_OBJECT
  425 + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances)
  426 + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>())
  427 +
  428 + void train(const TemplateList &data)
  429 + {
  430 + QFutureSynchronizer<void> futures;
  431 + foreach (br::Distance *distance, distances)
  432 + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data));
  433 + futures.waitForFinished();
  434 + }
  435 +
  436 + float compare(const Template &target, const Template &query) const
  437 + {
  438 + float result = 0;
  439 +
  440 + foreach (br::Distance *distance, distances) {
  441 + result += distance->compare(target, query);
  442 +
  443 + if (result == -std::numeric_limits<float>::max())
  444 + return result;
  445 + }
  446 +
  447 + return result;
  448 + }
  449 +};
  450 +
  451 +BR_REGISTER(Distance, SumDistance)
  452 +
389 } // namespace br 453 } // namespace br
390 #include "distance.moc" 454 #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"
@@ -40,10 +41,12 @@ class DrawTransform : public UntrainableTransform @@ -40,10 +41,12 @@ class DrawTransform : public UntrainableTransform
40 Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false) 41 Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false)
41 Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) 42 Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false)
42 Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) 43 Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false)
  44 + Q_PROPERTY(int lineThickness READ get_lineThickness WRITE set_lineThickness RESET reset_lineThickness STORED false)
43 BR_PROPERTY(bool, verbose, false) 45 BR_PROPERTY(bool, verbose, false)
44 BR_PROPERTY(bool, points, true) 46 BR_PROPERTY(bool, points, true)
45 BR_PROPERTY(bool, rects, true) 47 BR_PROPERTY(bool, rects, true)
46 BR_PROPERTY(bool, inPlace, false) 48 BR_PROPERTY(bool, inPlace, false)
  49 + BR_PROPERTY(int, lineThickness, 1)
47 50
48 void project(const Template &src, Template &dst) const 51 void project(const Template &src, Template &dst) const
49 { 52 {
@@ -61,7 +64,7 @@ class DrawTransform : public UntrainableTransform @@ -61,7 +64,7 @@ class DrawTransform : public UntrainableTransform
61 } 64 }
62 if (rects) { 65 if (rects) {
63 foreach (const Rect &rect, OpenCVUtils::toRects(src.file.namedRects() + src.file.rects())) 66 foreach (const Rect &rect, OpenCVUtils::toRects(src.file.namedRects() + src.file.rects()))
64 - rectangle(dst, rect, color); 67 + rectangle(dst, rect, color, lineThickness);
65 } 68 }
66 } 69 }
67 }; 70 };
@@ -343,6 +346,75 @@ class AdjacentOverlayTransform : public Transform @@ -343,6 +346,75 @@ class AdjacentOverlayTransform : public Transform
343 346
344 BR_REGISTER(Transform, AdjacentOverlayTransform) 347 BR_REGISTER(Transform, AdjacentOverlayTransform)
345 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 +
346 // TODO: re-implement EditTransform using Qt 418 // TODO: re-implement EditTransform using Qt
347 #if 0 419 #if 0
348 /*! 420 /*!
openbr/plugins/eigen3.cpp
@@ -302,8 +302,8 @@ class LDATransform : public Transform @@ -302,8 +302,8 @@ class LDATransform : public Transform
302 Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false) 302 Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false)
303 Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false) 303 Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false)
304 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) 304 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
305 - Q_PROPERTY(bool isBinary READ get_isBinary WRITE set_isBinary RESET reset_isBinary STORED true)  
306 - Q_PROPERTY(bool normalize READ get_normalize WRITE set_normalize RESET reset_normalize STORED true) 305 + Q_PROPERTY(bool isBinary READ get_isBinary WRITE set_isBinary RESET reset_isBinary STORED false)
  306 + Q_PROPERTY(bool normalize READ get_normalize WRITE set_normalize RESET reset_normalize STORED false)
307 BR_PROPERTY(float, pcaKeep, 0.98) 307 BR_PROPERTY(float, pcaKeep, 0.98)
308 BR_PROPERTY(bool, pcaWhiten, false) 308 BR_PROPERTY(bool, pcaWhiten, false)
309 BR_PROPERTY(int, directLDA, 0) 309 BR_PROPERTY(int, directLDA, 0)
@@ -316,12 +316,6 @@ class LDATransform : public Transform @@ -316,12 +316,6 @@ class LDATransform : public Transform
316 Eigen::VectorXf mean; 316 Eigen::VectorXf mean;
317 Eigen::MatrixXf projection; 317 Eigen::MatrixXf projection;
318 float stdDev; 318 float stdDev;
319 - bool trained;  
320 -  
321 - void init()  
322 - {  
323 - trained = false;  
324 - }  
325 319
326 void train(const TemplateList &_trainingSet) 320 void train(const TemplateList &_trainingSet)
327 { 321 {
@@ -461,9 +455,9 @@ class LDATransform : public Transform @@ -461,9 +455,9 @@ class LDATransform : public Transform
461 projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose(); 455 projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose();
462 dimsOut = dim2; 456 dimsOut = dim2;
463 457
  458 + stdDev = 1; // default initialize
464 if (isBinary) { 459 if (isBinary) {
465 assert(dimsOut == 1); 460 assert(dimsOut == 1);
466 - TemplateList projected;  
467 float posVal = 0; 461 float posVal = 0;
468 float negVal = 0; 462 float negVal = 0;
469 Eigen::MatrixXf results(trainingSet.size(),1); 463 Eigen::MatrixXf results(trainingSet.size(),1);
@@ -493,8 +487,6 @@ class LDATransform : public Transform @@ -493,8 +487,6 @@ class LDATransform : public Transform
493 if (normalize) 487 if (normalize)
494 stdDev = sqrt(results.array().square().sum() / trainingSet.size()); 488 stdDev = sqrt(results.array().square().sum() / trainingSet.size());
495 } 489 }
496 -  
497 - trained = true;  
498 } 490 }
499 491
500 void project(const Template &src, Template &dst) const 492 void project(const Template &src, Template &dst) const
@@ -508,18 +500,22 @@ class LDATransform : public Transform @@ -508,18 +500,22 @@ class LDATransform : public Transform
508 // Do projection 500 // Do projection
509 outMap = projection.transpose() * (inMap - mean); 501 outMap = projection.transpose() * (inMap - mean);
510 502
511 - if (normalize && isBinary && trained) 503 + if (normalize && isBinary)
512 dst.m().at<float>(0,0) = dst.m().at<float>(0,0) / stdDev; 504 dst.m().at<float>(0,0) = dst.m().at<float>(0,0) / stdDev;
513 } 505 }
514 506
515 void store(QDataStream &stream) const 507 void store(QDataStream &stream) const
516 { 508 {
517 - stream << pcaKeep << directLDA << directDrop << dimsOut << mean << projection << stdDev << normalize << isBinary << trained; 509 + stream << pcaKeep << directLDA << directDrop << dimsOut << mean << projection;
  510 + if (normalize && isBinary)
  511 + stream << stdDev;
518 } 512 }
519 513
520 void load(QDataStream &stream) 514 void load(QDataStream &stream)
521 { 515 {
522 - stream >> pcaKeep >> directLDA >> directDrop >> dimsOut >> mean >> projection >> stdDev >> normalize >> isBinary >> trained; 516 + stream >> pcaKeep >> directLDA >> directDrop >> dimsOut >> mean >> projection;
  517 + if (normalize && isBinary)
  518 + stream >> stdDev;
523 } 519 }
524 }; 520 };
525 521
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"
@@ -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,90 @@ class scoresFormat : public Format @@ -768,6 +770,90 @@ 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 + * \note This will fail if a binary blob contains any of the fields attempt to locate within the file
  779 + */
  780 +class ebtsFormat : public Format
  781 +{
  782 + Q_OBJECT
  783 +
  784 + QString textFieldValue(const QByteArray &byteArray, const QString &fieldNumber, int from = 0) const
  785 + {
  786 + // Find the field, skip the number bytes, and account for the semicolon
  787 + int fieldPosition = byteArray.indexOf(fieldNumber, from) + fieldNumber.size() + 1;
  788 + int sepPosition = byteArray.indexOf(QChar(0x1D),fieldPosition);
  789 +
  790 + return byteArray.mid(fieldPosition,sepPosition-fieldPosition);
  791 + }
  792 +
  793 + Template read() const
  794 + {
  795 + QByteArray byteArray;
  796 + QtUtils::readFile(file, byteArray);
  797 +
  798 + Template t;
  799 +
  800 + Mat m;
  801 +
  802 + // Demographics
  803 + {
  804 + QString name = textFieldValue(byteArray, "2.018");
  805 + QStringList names = name.split(',');
  806 + t.file.set("FIRSTNAME", names.at(1));
  807 + t.file.set("LASTNAME", names.at(0));
  808 + t.file.set("DOB", textFieldValue(byteArray, "2.022").toInt());
  809 + t.file.set("GENDER", textFieldValue(byteArray, "2.024"));
  810 + t.file.set("RACE", textFieldValue(byteArray, "2.025"));
  811 + }
  812 +
  813 + // Mugshot (first in file used)
  814 + // Todo: Check for face designation
  815 + {
  816 + const QString imageRecord = "10.001:";
  817 + const QString imageDataRecord = "10.999:";
  818 +
  819 + int fieldPosition = byteArray.indexOf(imageRecord);
  820 +
  821 + if (fieldPosition != -1) {
  822 + int sepPosition = byteArray.indexOf(QChar(0x1D),fieldPosition);
  823 + int dataPosition = byteArray.indexOf(imageDataRecord,sepPosition);
  824 +
  825 + int recordBytes = byteArray.mid(fieldPosition,sepPosition-fieldPosition).toInt();
  826 + int headerBytes = byteArray.mid(fieldPosition,dataPosition-fieldPosition).size() + imageDataRecord.size();
  827 +
  828 + QByteArray data = byteArray.mid(dataPosition+imageRecord.size(),recordBytes-headerBytes);
  829 +
  830 + m = imdecode(Mat(3, data.size(), CV_8UC3, data.data()), CV_LOAD_IMAGE_COLOR);
  831 + if (!m.data) qWarning("ebtsFormat::read failed to decode image data.");
  832 + t.m() = m;
  833 + } else qWarning("ebtsFormat::cannot find image data within file.");
  834 +
  835 + }
  836 +
  837 + if (t.file.contains("DOB")) {
  838 + const QDate dob = QDate::fromString(t.file.get<QString>("DOB"), "yyyyMMdd");
  839 + const QDate current = QDate::currentDate();
  840 + int age = current.year() - dob.year();
  841 + if (current.month() < dob.month()) age--;
  842 + t.file.set("Age", age);
  843 + }
  844 +
  845 + return t;
  846 + }
  847 +
  848 + void write(const Template &t) const
  849 + {
  850 + (void) t;
  851 + qFatal("Writing EBTS files is not supported.");
  852 + }
  853 +};
  854 +
  855 +BR_REGISTER(Format, ebtsFormat)
  856 +
771 } // namespace br 857 } // namespace br
772 858
773 #include "format.moc" 859 #include "format.moc"
openbr/plugins/gallery.cpp
@@ -32,6 +32,11 @@ @@ -32,6 +32,11 @@
32 #include "openbr/core/opencvutils.h" 32 #include "openbr/core/opencvutils.h"
33 #include "openbr/core/qtutils.h" 33 #include "openbr/core/qtutils.h"
34 34
  35 +#ifdef CVMATIO
  36 +#include "MatlabIO.hpp"
  37 +#include "MatlabIOContainer.hpp"
  38 +#endif
  39 +
35 namespace br 40 namespace br
36 { 41 {
37 42
@@ -969,6 +974,74 @@ class landmarksGallery : public Gallery @@ -969,6 +974,74 @@ class landmarksGallery : public Gallery
969 974
970 BR_REGISTER(Gallery, landmarksGallery) 975 BR_REGISTER(Gallery, landmarksGallery)
971 976
  977 +#ifdef CVMATIO
  978 +
  979 +using namespace cv;
  980 +
  981 +class vbbGallery : public Gallery
  982 +{
  983 + Q_OBJECT
  984 +
  985 + void init()
  986 + {
  987 + MatlabIO matio;
  988 + QString filename = (Globals->path.isEmpty() ? "" : Globals->path + "/") + file.name;
  989 + bool ok = matio.open(filename.toStdString(), "r");
  990 + if (!ok) qFatal("Couldn't open the vbb file");
  991 +
  992 + vector<MatlabIOContainer> variables;
  993 + variables = matio.read();
  994 + matio.close();
  995 +
  996 + double vers = variables[1].data<Mat>().at<double>(0,0);
  997 + if (vers != 1.4) qFatal("This is an old vbb version, we don't mess with that.");
  998 +
  999 + A = variables[0].data<vector<vector<MatlabIOContainer> > >().at(0);
  1000 + objLists = A.at(1).data<vector<MatlabIOContainer> >();
  1001 +
  1002 + // start at the first frame (duh!)
  1003 + currFrame = 0;
  1004 + }
  1005 +
  1006 + TemplateList readBlock(bool *done)
  1007 + {
  1008 + *done = false;
  1009 + Template rects(file);
  1010 + if (objLists[currFrame].typeEquals<vector<vector<MatlabIOContainer> > >()) {
  1011 + vector<vector<MatlabIOContainer> > bbs = objLists[currFrame].data<vector<vector<MatlabIOContainer> > >();
  1012 + for (unsigned int i=0; i<bbs.size(); i++) {
  1013 + vector<MatlabIOContainer> bb = bbs[i];
  1014 + Mat pos = bb[1].data<Mat>();
  1015 + double left = pos.at<double>(0,0);
  1016 + double top = pos.at<double>(0,1);
  1017 + double width = pos.at<double>(0,2);
  1018 + double height = pos.at<double>(0,3);
  1019 + rects.file.appendRect(QRectF(left, top, width, height));
  1020 + }
  1021 + }
  1022 + TemplateList tl;
  1023 + tl.append(rects);
  1024 + if (++currFrame == (int)objLists.size()) *done = true;
  1025 + return tl;
  1026 + }
  1027 +
  1028 + void write(const Template &t)
  1029 + {
  1030 + (void)t; qFatal("Not implemented");
  1031 + }
  1032 +
  1033 +private:
  1034 + // this holds a bunch of stuff, maybe we'll use it all later
  1035 + vector<MatlabIOContainer> A;
  1036 + // this, a field in A, holds bounding boxes for each frame
  1037 + vector<MatlabIOContainer> objLists;
  1038 + int currFrame;
  1039 +};
  1040 +
  1041 +BR_REGISTER(Gallery, vbbGallery)
  1042 +
  1043 +#endif
  1044 +
972 } // namespace br 1045 } // namespace br
973 1046
974 #include "gallery.moc" 1047 #include "gallery.moc"
openbr/plugins/gui.cpp
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 #include <QLineEdit> 12 #include <QLineEdit>
13 13
14 #include <opencv2/imgproc/imgproc.hpp> 14 #include <opencv2/imgproc/imgproc.hpp>
  15 +#include <opencv2/imgproc/imgproc_c.h>
15 #include "openbr_internal.h" 16 #include "openbr_internal.h"
16 #include "openbr/gui/utility.h" 17 #include "openbr/gui/utility.h"
17 18
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/process.cpp
@@ -531,8 +531,6 @@ class ProcessWrapperTransform : public TimeVaryingTransform @@ -531,8 +531,6 @@ class ProcessWrapperTransform : public TimeVaryingTransform
531 baseKey = id.toString(); 531 baseKey = id.toString();
532 532
533 QStringList argumentList; 533 QStringList argumentList;
534 - argumentList.append("-useGui");  
535 - argumentList.append("0");  
536 argumentList.append("-algorithm"); 534 argumentList.append("-algorithm");
537 argumentList.append(transform); 535 argumentList.append(transform);
538 if (!Globals->path.isEmpty()) { 536 if (!Globals->path.isEmpty()) {
openbr/plugins/quality.cpp
@@ -272,92 +272,75 @@ BR_REGISTER(Distance, ZScoreDistance) @@ -272,92 +272,75 @@ BR_REGISTER(Distance, ZScoreDistance)
272 272
273 /*! 273 /*!
274 * \ingroup distances 274 * \ingroup distances
275 - * \brief Match Probability modification for heat maps \cite klare12 275 + * \brief 1v1 heat map comparison
276 * \author Scott Klum \cite sklum 276 * \author Scott Klum \cite sklum
277 */ 277 */
278 class HeatMapDistance : public Distance 278 class HeatMapDistance : public Distance
279 { 279 {
280 Q_OBJECT 280 Q_OBJECT
281 - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)  
282 - Q_PROPERTY(bool gaussian READ get_gaussian WRITE set_gaussian RESET reset_gaussian STORED false)  
283 - Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false) 281 + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
284 Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false) 282 Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false)
285 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) 283 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
286 - BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))  
287 - BR_PROPERTY(bool, gaussian, true)  
288 - BR_PROPERTY(bool, crossModality, false) 284 + BR_PROPERTY(QString, description, "IdenticalDistance")
289 BR_PROPERTY(int, step, 1) 285 BR_PROPERTY(int, step, 1)
290 BR_PROPERTY(QString, inputVariable, "Label") 286 BR_PROPERTY(QString, inputVariable, "Label")
291 287
292 - QList<MP> mp; 288 + QList<br::Distance*> distances;
293 289
294 void train(const TemplateList &src) 290 void train(const TemplateList &src)
295 { 291 {
296 - distance->train(src);  
297 -  
298 - const QList<int> labels = src.indexProperty(inputVariable);  
299 -  
300 QList<TemplateList> patches; 292 QList<TemplateList> patches;
301 293
302 // Split src into list of TemplateLists of corresponding patches across all Templates 294 // Split src into list of TemplateLists of corresponding patches across all Templates
303 for (int i=0; i<step; i++) { 295 for (int i=0; i<step; i++) {
304 TemplateList patchBuffer; 296 TemplateList patchBuffer;
305 - for (int j=i; j<src.size(); j+=step) {  
306 - patchBuffer.append(src[j]);  
307 - } 297 + for (int j=0; j<src.size(); j++)
  298 + patchBuffer.append(Template(src[j].file, src[j][i]));
308 patches.append(patchBuffer); 299 patches.append(patchBuffer);
309 patchBuffer.clear(); 300 patchBuffer.clear();
310 } 301 }
311 302
312 - QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(patches[0].size()), FileList(patches[0].size()))); 303 + while (distances.size() < patches.size())
  304 + distances.append(make(description));
313 305
314 - for (int i=0; i<step; i++) {  
315 - distance->compare(patches[i], patches[i], matrixOutput.data());  
316 - QList<float> genuineScores, impostorScores;  
317 - genuineScores.reserve(step);  
318 - impostorScores.reserve(step);  
319 - for (int j=0; j<matrixOutput.data()->data.rows; j++) {  
320 - for (int k=0; k<j; k++) {  
321 - const float score = matrixOutput.data()->data.at<float>(j, k);  
322 - if (score == -std::numeric_limits<float>::max()) continue;  
323 - if (crossModality) if(src[j*step].file.get<QString>("MODALITY") == src[k*step].file.get<QString>("MODALITY")) continue;  
324 - if (labels[j*step] == labels[k*step]) genuineScores.append(score);  
325 - else impostorScores.append(score);  
326 - }  
327 - }  
328 -  
329 - mp.append(MP(genuineScores, impostorScores));  
330 - } 306 + // Train on a distance for each patch
  307 + for (int i=0; i<distances.size(); i++)
  308 + distances[i]->train(patches[i]);
331 } 309 }
332 310
333 float compare(const Template &target, const Template &query) const 311 float compare(const Template &target, const Template &query) const
334 { 312 {
335 (void) target; 313 (void) target;
336 (void) query; 314 (void) query;
337 - qFatal("You did this wrong"); 315 + qFatal("Heatmap Distance not compatible with Template to Template comparison.");
338 316
339 return 0; 317 return 0;
340 } 318 }
341 319
342 void compare(const TemplateList &target, const TemplateList &query, Output *output) const 320 void compare(const TemplateList &target, const TemplateList &query, Output *output) const
343 { 321 {
344 - for (int i=0; i<step; i++) {  
345 - float rawScore = distance->compare(target[i],query[i]);  
346 - if (rawScore == -std::numeric_limits<float>::max()) output->setRelative(rawScore, i, 0);  
347 - else output->setRelative(mp[i](rawScore, gaussian), i, 0); 322 + for (int i=0; i<target.size(); i++) {
  323 + if (target[i].size() != step || query[i].size() != step) qFatal("Heatmap step not equal to the number of patches.");
  324 + for (int j=0; j<step; j++)
  325 + output->setRelative(distances[j]->compare(target[i][j],query[i][j]), j, 0);
348 } 326 }
349 } 327 }
350 328
351 void store(QDataStream &stream) const 329 void store(QDataStream &stream) const
352 { 330 {
353 - distance->store(stream);  
354 - stream << mp; 331 + stream << distances.size();
  332 + foreach (Distance *distance, distances)
  333 + distance->store(stream);
355 } 334 }
356 335
357 void load(QDataStream &stream) 336 void load(QDataStream &stream)
358 { 337 {
359 - distance->load(stream);  
360 - stream >> mp; 338 + int numDistances;
  339 + stream >> numDistances;
  340 + while (distances.size() < numDistances)
  341 + distances.append(make(description));
  342 + foreach (Distance *distance, distances)
  343 + distance->load(stream);
361 } 344 }
362 }; 345 };
363 346
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
@@ -35,7 +35,7 @@ class StasmInitializer : public Initializer @@ -35,7 +35,7 @@ class StasmInitializer : public Initializer
35 35
36 void initialize() const 36 void initialize() const
37 { 37 {
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.15,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("RectFromStasmMouth","RectFromPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76],0.3,2)"); 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)");
openbr/plugins/stream.cpp
  1 +#include <fstream>
1 #include <QReadWriteLock> 2 #include <QReadWriteLock>
2 #include <QWaitCondition> 3 #include <QWaitCondition>
3 #include <QThreadPool> 4 #include <QThreadPool>
4 #include <QSemaphore> 5 #include <QSemaphore>
5 #include <QMap> 6 #include <QMap>
6 -#include <opencv/highgui.h> 7 +#include <QQueue>
7 #include <QtConcurrent> 8 #include <QtConcurrent>
  9 +#include <opencv/highgui.h>
  10 +#include <opencv2/highgui/highgui.hpp>
8 #include "openbr_internal.h" 11 #include "openbr_internal.h"
9 -  
10 #include "openbr/core/common.h" 12 #include "openbr/core/common.h"
11 #include "openbr/core/opencvutils.h" 13 #include "openbr/core/opencvutils.h"
12 #include "openbr/core/qtutils.h" 14 #include "openbr/core/qtutils.h"
13 15
14 using namespace cv; 16 using namespace cv;
  17 +using namespace std;
15 18
16 namespace br 19 namespace br
17 { 20 {
@@ -203,6 +206,13 @@ public: @@ -203,6 +206,13 @@ public:
203 virtual bool getNextTemplate(Template & output)=0; 206 virtual bool getNextTemplate(Template & output)=0;
204 protected: 207 protected:
205 Template basis; 208 Template basis;
  209 + string getAbsolutePath(QString filename)
  210 + {
  211 + // Yes, we should specify absolute path:
  212 + // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python
  213 + QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + filename;
  214 + return QFileInfo(fileName).absoluteFilePath().toStdString();
  215 + }
206 }; 216 };
207 217
208 static QMutex openLock; 218 static QMutex openLock;
@@ -236,12 +246,9 @@ public: @@ -236,12 +246,9 @@ public:
236 qDebug("Video not open!"); 246 qDebug("Video not open!");
237 } 247 }
238 } else { 248 } else {
239 - // Yes, we should specify absolute path:  
240 - // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python  
241 - QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + input.file.name;  
242 // On windows, this appears to not be thread-safe 249 // On windows, this appears to not be thread-safe
243 QMutexLocker lock(&openLock); 250 QMutexLocker lock(&openLock);
244 - video.open(QFileInfo(fileName).absoluteFilePath().toStdString()); 251 + video.open(getAbsolutePath(input.file.name));
245 } 252 }
246 253
247 return video.isOpened(); 254 return video.isOpened();
@@ -319,6 +326,198 @@ protected: @@ -319,6 +326,198 @@ protected:
319 bool data_ok; 326 bool data_ok;
320 }; 327 };
321 328
  329 +class SeqReader : public TemplateProcessor
  330 +{
  331 +public:
  332 + SeqReader() {}
  333 +
  334 + bool open(Template &input)
  335 + {
  336 + basis = input;
  337 +
  338 + seqFile.open(getAbsolutePath(input.file.name).c_str(), ios::in | ios::binary | ios::ate);
  339 + if (!isOpen()) return false;
  340 +
  341 + int headSize = 1024;
  342 + // start at end of file to get full size
  343 + int fileSize = seqFile.tellg();
  344 + if (fileSize < headSize) {
  345 + qDebug("No header in seq file");
  346 + return false;
  347 + }
  348 +
  349 + // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq '
  350 + char firstFour[4];
  351 + seqFile.seekg(0, ios::beg);
  352 + seqFile.read(firstFour, 4);
  353 + char nextTwentyFour[24];
  354 + readText(24, nextTwentyFour);
  355 + if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) {
  356 + qDebug("Invalid header in seq file");
  357 + return false;
  358 + }
  359 +
  360 + // next 8 bytes for version (skipped below) and header size (1024), then 512 for descr
  361 + seqFile.seekg(4, ios::cur);
  362 + int hSize = readInt();
  363 + if (hSize != headSize) {
  364 + qDebug("Invalid header size");
  365 + return false;
  366 + }
  367 + char desc[512];
  368 + readText(512, desc);
  369 + basis.file.set("Description", QString(desc));
  370 +
  371 + width = readInt();
  372 + height = readInt();
  373 + // get # channels from bit depth
  374 + numChan = readInt()/8;
  375 + int imageBitDepthReal = readInt();
  376 + if (imageBitDepthReal != 8) {
  377 + qDebug("Invalid bit depth");
  378 + return false;
  379 + }
  380 + // the size of just the image part of a raw img
  381 + imgSizeBytes = readInt();
  382 +
  383 + int imgFormatInt = readInt();
  384 + if (imgFormatInt == 100 || imgFormatInt == 200 || imgFormatInt == 101) {
  385 + imgFormat = "raw";
  386 + } else if (imgFormatInt == 102 || imgFormatInt == 201 || imgFormatInt == 103 ||
  387 + imgFormatInt == 1 || imgFormatInt == 2) {
  388 + imgFormat = "compressed";
  389 + } else {
  390 + qFatal("unsupported image format");
  391 + }
  392 +
  393 + numFrames = readInt();
  394 + // skip empty int
  395 + seqFile.seekg(4, ios::cur);
  396 + // the size of a full raw file, with extra crap after img data
  397 + trueImgSizeBytes = readInt();
  398 +
  399 + // gather all the frame positions in an array
  400 + seekPos.reserve(numFrames);
  401 + // start at end of header
  402 + seekPos.append(headSize);
  403 + // extra 8 bytes at end of img
  404 + int extra = 8;
  405 + for (int i=1; i<numFrames; i++) {
  406 + int s;
  407 + // compressed images have different sizes
  408 + // the first byte at the beginning of the file
  409 + // says how big the current img is
  410 + if (imgFormat == "compressed") {
  411 + int lastPos = seekPos[i-1];
  412 + seqFile.seekg(lastPos, ios::beg);
  413 + int currSize = readInt();
  414 + s = lastPos + currSize + extra;
  415 +
  416 + // but there might be 16 extra bytes instead of 8...
  417 + if (i == 1) {
  418 + seqFile.seekg(s, ios::beg);
  419 + char zero;
  420 + seqFile.read(&zero, 1);
  421 + if (zero == 0) {
  422 + s += 8;
  423 + extra += 8;
  424 + }
  425 + }
  426 + }
  427 + // raw images are all the same size
  428 + else {
  429 + s = headSize + (i*trueImgSizeBytes);
  430 + }
  431 +
  432 + seekPos.enqueue(s);
  433 + }
  434 +
  435 +#ifdef CVMATIO
  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.");
  442 +#endif
  443 +
  444 + return true;
  445 + }
  446 +
  447 + bool isOpen()
  448 + {
  449 + return seqFile.is_open();
  450 + }
  451 +
  452 + void close()
  453 + {
  454 + seqFile.close();
  455 + }
  456 +
  457 + bool getNextTemplate(Template &output)
  458 + {
  459 + if (!isOpen()) {
  460 + qDebug("Seq not open");
  461 + return false;
  462 + }
  463 + // if we've reached the last frame, we're done
  464 + if (seekPos.size() == 0) return false;
  465 +
  466 + seqFile.seekg(seekPos.dequeue(), ios::beg);
  467 +
  468 + Mat temp;
  469 + // let imdecode do all the work to decode the compressed img
  470 + if (imgFormat == "compressed") {
  471 + int imgSize = readInt() - 4;
  472 + vector<char> imgBuf(imgSize);
  473 + seqFile.read(&imgBuf[0], imgSize);
  474 + // flags < 0 means load image as-is (keep color info if available)
  475 + imdecode(imgBuf, -1, &temp);
  476 + }
  477 + // raw images can be loaded straight into a Mat
  478 + else {
  479 + char *imgBuf = new char[imgSizeBytes];
  480 + seqFile.read(imgBuf, imgSizeBytes);
  481 + int type = (numChan == 1 ? CV_8UC1 : CV_8UC3);
  482 + temp = Mat(height, width, type, imgBuf);
  483 + }
  484 +
  485 + output.file = basis.file;
  486 + if (!annotations.empty()) {
  487 + output.file.setRects(annotations.first().file.rects());
  488 + annotations.removeFirst();
  489 + }
  490 + output.m() = temp;
  491 +
  492 + return true;
  493 + }
  494 +private:
  495 + int readInt()
  496 + {
  497 + int num;
  498 + seqFile.read((char*)&num, 4);
  499 + return num;
  500 + }
  501 +
  502 + // apparently the text in seq files is 16 bit characters (UTF-16?)
  503 + // since we don't really need the last byte, snad since it gets interpreted as
  504 + // a terminating char, let's just grab the first byte for storage
  505 + void readText(int bytes, char * buffer)
  506 + {
  507 + seqFile.read(buffer, bytes);
  508 + for (int i=0; i<bytes; i+=2) {
  509 + buffer[i/2] = buffer[i];
  510 + }
  511 + buffer[bytes/2] = '\0';
  512 + }
  513 +
  514 +protected:
  515 + ifstream seqFile;
  516 + QQueue<int> seekPos;
  517 + int width, height, numChan, imgSizeBytes, trueImgSizeBytes, numFrames;
  518 + QString imgFormat;
  519 + TemplateList annotations;
  520 +};
322 521
323 // Interface for sequentially getting data from some data source. 522 // Interface for sequentially getting data from some data source.
324 // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor 523 // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor
@@ -514,11 +713,16 @@ protected: @@ -514,11 +713,16 @@ protected:
514 if (frameSource) 713 if (frameSource)
515 frameSource->close(); 714 frameSource->close();
516 715
  716 + Template curr = this->templates[current_template_idx];
517 if (mode == br::Idiocy::Auto) 717 if (mode == br::Idiocy::Auto)
518 { 718 {
519 delete frameSource; 719 delete frameSource;
520 - if (this->templates[this->current_template_idx].empty())  
521 - frameSource = new VideoReader(); 720 + if (curr.empty()) {
  721 + if (curr.file.name.right(3) == "seq")
  722 + frameSource = new SeqReader();
  723 + else
  724 + frameSource = new VideoReader();
  725 + }
522 else 726 else
523 frameSource = new DirectReturn(); 727 frameSource = new DirectReturn();
524 } 728 }
@@ -529,11 +733,14 @@ protected: @@ -529,11 +733,14 @@ protected:
529 } 733 }
530 else if (mode == br::Idiocy::StreamVideo) 734 else if (mode == br::Idiocy::StreamVideo)
531 { 735 {
532 - if (!frameSource)  
533 - frameSource = new VideoReader(); 736 + if (!frameSource) {
  737 + if (curr.file.name.right(3) == "seq")
  738 + frameSource = new SeqReader();
  739 + else
  740 + frameSource = new VideoReader();
  741 + }
534 } 742 }
535 -  
536 - open_res = frameSource->open(this->templates[current_template_idx]); 743 + open_res = frameSource->open(curr);
537 if (!open_res) 744 if (!open_res)
538 { 745 {
539 current_template_idx++; 746 current_template_idx++;
@@ -1079,8 +1286,7 @@ public: @@ -1079,8 +1286,7 @@ public:
1079 1286
1080 // Wait for the stream to process the last frame available from 1287 // Wait for the stream to process the last frame available from
1081 // the data source. 1288 // the data source.
1082 - bool wait_res = false;  
1083 - wait_res = readStage->dataSource.waitLast(); 1289 + readStage->dataSource.waitLast();
1084 1290
1085 // Now that there are no more incoming frames, call finalize 1291 // Now that there are no more incoming frames, call finalize
1086 // on each transform in turn to collect any last templates 1292 // on each transform in turn to collect any last templates
@@ -1217,6 +1423,7 @@ public: @@ -1217,6 +1423,7 @@ public:
1217 { 1423 {
1218 // Delete all the stages 1424 // Delete all the stages
1219 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?
1220 delete processingStages[i]; 1427 delete processingStages[i];
1221 } 1428 }
1222 processingStages.clear(); 1429 processingStages.clear();
scripts/downloadDatasets.sh
@@ -35,6 +35,35 @@ if [ ! -d ../data/BioID/img ]; then @@ -35,6 +35,35 @@ if [ ! -d ../data/BioID/img ]; then
35 rm *.eye description.txt BioID-FaceDatabase-V1.2.zip 35 rm *.eye description.txt BioID-FaceDatabase-V1.2.zip
36 fi 36 fi
37 37
  38 +# Caltech Pedestrian
  39 +if [ ! -d ../data/CaltechPedestrians/vid ]; then
  40 + mkdir ../data/CaltechPedestrians/vid
  41 + echo "Downloading Caltech Pedestrians dataset..."
  42 + prefix="http://www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/datasets/USA"
  43 + for seq in {0..10}; do
  44 + fname=`printf "set%02d.tar" $seq`
  45 + dlpath="$prefix/$fname"
  46 + if hash curl 2>/dev/null; then
  47 + curl -OL $dlpath
  48 + else
  49 + wget $dlpath
  50 + fi
  51 + tar -xf $fname
  52 + done
  53 + rm *.tar
  54 + ./writeCaltechPedestrianSigset.sh 0 5 train > ../data/CaltechPedestrians/train.xml
  55 + ./writeCaltechPedestrianSigset.sh 6 10 test > ../data/CaltechPedestrians/test.xml
  56 + mv set* ../data/CaltechPedestrians/vid
  57 + if hash curl 2>/dev/null; then
  58 + curl -OL "$prefix/annotations.zip"
  59 + else
  60 + wget "$prefix/annotations.zip"
  61 + fi
  62 + unzip annotations.zip
  63 + rm annotations.zip
  64 + mv annotations ../data/CaltechPedestrians
  65 +fi
  66 +
38 # INRIA person 67 # INRIA person
39 if [ ! -d ../data/INRIAPerson/img ]; then 68 if [ ! -d ../data/INRIAPerson/img ]; then
40 echo "Downloading INRIA person dataset..." 69 echo "Downloading INRIA person dataset..."
@@ -66,7 +95,7 @@ if [ ! -d ../data/KTH/vid ]; then @@ -66,7 +95,7 @@ if [ ! -d ../data/KTH/vid ]; then
66 fi 95 fi
67 mkdir ../data/KTH/vid/${vidclass} 96 mkdir ../data/KTH/vid/${vidclass}
68 unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass} 97 unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass}
69 - rm ${vidclass}.zip 98 + rm ${vidclass}.zip
70 done 99 done
71 # this file is corrupted 100 # this file is corrupted
72 rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi 101 rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi
scripts/evalAgeRegression-PCSO.sh
@@ -4,7 +4,7 @@ if [ ! -f evalAgeRegression-PCSO.sh ]; then @@ -4,7 +4,7 @@ if [ ! -f evalAgeRegression-PCSO.sh ]; then
4 exit 4 exit
5 fi 5 fi
6 6
7 -export BR="../build/app/br/br -useGui 0" 7 +export BR=../build/app/br/br
8 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ 8 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/
9 export ageAlg=AgeRegression 9 export ageAlg=AgeRegression
10 10
scripts/evalFaceRecognition-LFW.sh
@@ -20,7 +20,7 @@ if [ ! -e Algorithm_Dataset ]; then @@ -20,7 +20,7 @@ if [ ! -e Algorithm_Dataset ]; then
20 fi 20 fi
21 21
22 # Run the LFW test protocol 22 # Run the LFW test protocol
23 -br -useGui 0 -algorithm $ALGORITHM -path ../data/LFW/img/ -crossValidate 10 -pairwiseCompare ../data/LFW/sigset/test_image_restricted_target.xml ../data/LFW/sigset/test_image_restricted_query.xml ${ALGORITHM}_LFW.mtx -convert Output ${ALGORITHM}_lfw.mtx Algorithm_Dataset/${ALGORITHM}_LFW%1.eval 23 +br -algorithm $ALGORITHM -path ../data/LFW/img/ -crossValidate 10 -pairwiseCompare ../data/LFW/sigset/test_image_restricted_target.xml ../data/LFW/sigset/test_image_restricted_query.xml ${ALGORITHM}_LFW.mtx -convert Output ${ALGORITHM}_lfw.mtx Algorithm_Dataset/${ALGORITHM}_LFW%1.eval
24 24
25 # Plot results 25 # Plot results
26 -br -useGui 0 -plot Algorithm_Dataset/* 'lfw_results.pdf[smooth=Dataset,rocOptions[yLimits=(0,1)]]' 26 +br -plot Algorithm_Dataset/* 'lfw_results.pdf[smooth=Dataset,rocOptions[yLimits=(0,1)]]'
scripts/evalFaceRecognition-MEDS.sh
@@ -20,11 +20,11 @@ if [ ! -e Algorithm_Dataset ]; then @@ -20,11 +20,11 @@ if [ ! -e Algorithm_Dataset ]; then
20 fi 20 fi
21 21
22 if [ ! -e MEDS.mask ]; then 22 if [ ! -e MEDS.mask ]; then
23 - br -useGui 0 -makeMask ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml MEDS.mask 23 + br -makeMask ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml MEDS.mask
24 fi 24 fi
25 25
26 # Run Algorithm on MEDS 26 # Run Algorithm on MEDS
27 -br -useGui 0 -algorithm ${ALGORITHM} -path ../data/MEDS/img -compare ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml ${ALGORITHM}_MEDS.mtx -eval ${ALGORITHM}_MEDS.mtx MEDS.mask Algorithm_Dataset/${ALGORITHM}_MEDS.csv 27 +br -algorithm ${ALGORITHM} -path ../data/MEDS/img -compare ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml ${ALGORITHM}_MEDS.mtx -eval ${ALGORITHM}_MEDS.mtx MEDS.mask Algorithm_Dataset/${ALGORITHM}_MEDS.csv
28 28
29 # Plot results 29 # Plot results
30 -br -useGui 0 -plot Algorithm_Dataset/*_MEDS.csv MEDS 30 +br -plot Algorithm_Dataset/*_MEDS.csv MEDS
scripts/evalGenderClassification-PCSO.sh
@@ -9,7 +9,7 @@ export ALGORITHM=GenderClassification @@ -9,7 +9,7 @@ export ALGORITHM=GenderClassification
9 export PCSO_DIR=../data/PCSO/img 9 export PCSO_DIR=../data/PCSO/img
10 10
11 # Create a file list by querying the database 11 # Create a file list by querying the database
12 -$BR -useGui 0 -quiet -algorithm Identity -enroll "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=1:8000]" terminal.txt > Input.txt 12 +$BR -quiet -algorithm Identity -enroll "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=1:8000]" terminal.txt > Input.txt
13 13
14 # Enroll the file list and evaluate performance 14 # Enroll the file list and evaluate performance
15 -$BR -useGui 0 -algorithm $ALGORITHM -path $PCSO_DIR -enroll Input.txt Output.txt -evalClassification Output.txt Input.txt Gender  
16 \ No newline at end of file 15 \ No newline at end of file
  16 +$BR -algorithm $ALGORITHM -path $PCSO_DIR -enroll Input.txt Output.txt -evalClassification Output.txt Input.txt Gender
17 \ No newline at end of file 17 \ No newline at end of file
scripts/pedestrianBaselineLBP.sh
@@ -27,8 +27,7 @@ else @@ -27,8 +27,7 @@ else
27 TEST=testSmall.xml 27 TEST=testSmall.xml
28 fi 28 fi
29 29
30 -br -useGui 0 \  
31 - -algorithm "${ALG}" \ 30 +br -algorithm "${ALG}" \
32 -path $INRIA_PATH/img \ 31 -path $INRIA_PATH/img \
33 -train $INRIA_PATH/sigset/train.xml pedModel \ 32 -train $INRIA_PATH/sigset/train.xml pedModel \
34 -enroll $INRIA_PATH/sigset/$TEST pedResults.xml 33 -enroll $INRIA_PATH/sigset/$TEST pedResults.xml
scripts/trainAgeRegression-PCSO.sh
@@ -13,4 +13,4 @@ export ageAlg=AgeRegression @@ -13,4 +13,4 @@ export ageAlg=AgeRegression
13 13
14 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ 14 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/
15 15
16 -$BR -useGui 0 -algorithm $ageAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Age,PersonID FROM PCSO WHERE Age >= 17 AND AGE <= 68', subset=0:200]" ../share/openbr/models/algorithms/AgeRegression 16 +$BR -algorithm $ageAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Age,PersonID FROM PCSO WHERE Age >= 17 AND AGE <= 68', subset=0:200]" ../share/openbr/models/algorithms/AgeRegression
scripts/trainFaceRecognition-PCSO.sh
@@ -14,7 +14,5 @@ export BR=../build/app/br/br @@ -14,7 +14,5 @@ export BR=../build/app/br/br
14 14
15 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ 15 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/
16 16
17 -  
18 -  
19 -$BR -useGui 0 -algorithm FaceRecognition -path "$PCSO_DIR/Images/" -train "$PCSO_DIR/PCSO.db[query='SELECT File,PersonID as Label,PersonID FROM PCSO', subset=0:5:6000]" ../share/openbr/models/algorithms/FaceRecognition 17 +$BR -algorithm FaceRecognition -path "$PCSO_DIR/Images/" -train "$PCSO_DIR/PCSO.db[query='SELECT File,PersonID as Label,PersonID FROM PCSO', subset=0:5:6000]" ../share/openbr/models/algorithms/FaceRecognition
20 18
scripts/trainGenderClassification-PCSO.sh
@@ -13,4 +13,4 @@ export genderAlg=GenderClassification @@ -13,4 +13,4 @@ export genderAlg=GenderClassification
13 13
14 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ 14 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/
15 15
16 -$BR -useGui 0 -algorithm $genderAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=0:8000]" ../share/openbr/models/algorithms/GenderClassification 16 +$BR -algorithm $genderAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=0:8000]" ../share/openbr/models/algorithms/GenderClassification
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 0 โ†’ 100644
  1 +set(CVMATIO_DIR "${BR_THIRDPARTY_DIR}/cvmatio")
  2 +if(NOT EXISTS ${CVMATIO_DIR})
  3 + # download source from github
  4 + execute_process(COMMAND "git" "clone" "https://github.com/hbristow/cvmatio.git" WORKING_DIRECTORY ${BR_THIRDPARTY_DIR})
  5 +else()
  6 + # update the source
  7 + execute_process(COMMAND "git" "pull" WORKING_DIRECTORY ${CVMATIO_DIR})
  8 +endif()
  9 +set(CVMATIO_LIB_DIR ${CMAKE_BINARY_DIR}/3rdparty/cvmatio/src)
share/openbr/cmake/OpenBRConfig.cmake
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 # target_link_libraries(MY_TARGET_NAME ${OPENBR_LIBS}) 8 # target_link_libraries(MY_TARGET_NAME ${OPENBR_LIBS})
9 # ================================================================ 9 # ================================================================
10 10
  11 +find_path(OPENBR_DIR include/openbr/openbr.h)
11 include_directories(${OPENBR_DIR}/include) 12 include_directories(${OPENBR_DIR}/include)
12 link_directories(${OPENBR_DIR}/lib) 13 link_directories(${OPENBR_DIR}/lib)
13 set(OPENBR_LIBS "openbr") 14 set(OPENBR_LIBS "openbr")