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 1 ### Repository Specific ###
2 2 3rdparty/LatentSDK*
3 3 3rdparty/pittpatt*
  4 +3rdparty/cvmatio
4 5 data/*/img
5 6 data/*/vid
6 7 data/PCSO/*
... ... @@ -39,4 +40,10 @@ scripts/results
39 40 ### autogenerated sigsets ###
40 41 data/INRIAPerson/sigset
41 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 4 # Global settings
5 5 set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr")
6 6 set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts")
  7 +set(BR_THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty")
7 8 set(CMAKE_AUTOMOC ON)
8 9 set(CPACK_PACKAGE_NAME "OpenBR")
9 10 set(CPACK_PACKAGE_VENDOR "OpenBiometrics")
... ... @@ -90,6 +91,18 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS})
90 91 # Find Alphanum
91 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 106 # Compiler flags
94 107 if(UNIX)
95 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 14  
15 15  
16 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 5 add_subdirectory(examples)
6 6  
7 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 158 } else if (!strcmp(fun, "plotMetadata")) {
159 159 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'.");
160 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 166 // Miscellaneous
164 167 else if (!strcmp(fun, "help")) {
165 168 check(parc == 0, "No parameters expected for 'help'.");
166 169 help();
  170 + } else if (!strcmp(fun, "gui")) {
  171 + // Do nothing because we checked for this flag prior to initialization
167 172 } else if (!strcmp(fun, "objects")) {
168 173 check(parc <= 2, "Incorrect parameter count for 'objects'.");
169 174 printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*"));
... ... @@ -177,11 +182,10 @@ public:
177 182 check(parc == 1, "Incorrect parameter count for 'daemon'.");
178 183 daemon = true;
179 184 daemon_pipe = parv[0];
180   - } else if (!strcmp(fun,"slave")) {
  185 + } else if (!strcmp(fun, "slave")) {
181 186 check(parc == 1, "Incorrect parameter count for 'slave'");
182 187 br_slave_process(parv[0]);
183   - }
184   - else if (!strcmp(fun, "exit")) {
  188 + } else if (!strcmp(fun, "exit")) {
185 189 check(parc == 0, "No parameters expected for 'exit'.");
186 190 daemon = false;
187 191 } else if (!strcmp(fun, "getHeader")) {
... ... @@ -245,6 +249,7 @@ private:
245 249 "\n"
246 250 "==== Miscellaneous ====\n"
247 251 "-help\n"
  252 + "-gui\n"
248 253 "-objects [abstraction [implementation]]\n"
249 254 "-about\n"
250 255 "-version\n"
... ... @@ -255,7 +260,7 @@ private:
255 260  
256 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 265 FakeMain *fakeMain = new FakeMain(argc, argv);
261 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 34 set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation")
35 35 mark_as_advanced(JANUS_BUILD_PP5_WRAPPER)
36 36 mark_as_advanced(JANUS_BUILD_DOCS)
37   -set(JANUS_TEST_IMPLEMENTATION openbr)
  37 +set(JANUS_IMPLEMENTATION openbr)
38 38 add_subdirectory(janus)
39 39  
40 40 # Install
... ...
openbr/core/bee.cpp
... ... @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &amp;matrix, QString *targetSigset, QString *querySi
172 172 qint64 read = file.read((char*)m.data, bytesExpected);
173 173 if (read != bytesExpected)
174 174 qFatal("Invalid matrix size.");
  175 + if (!file.atEnd())
  176 + qFatal("Expected matrix end of file.");
175 177 file.close();
176 178  
177 179 Mat result;
... ...
openbr/core/cluster.cpp
... ... @@ -21,6 +21,7 @@
21 21 #include <QSet>
22 22 #include <limits>
23 23 #include <openbr/openbr_plugin.h>
  24 +#include <assert.h>
24 25  
25 26 #include "openbr/core/bee.h"
26 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 63 }
64 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 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 261 * \brief See Matlab function unique() for documentation.
257 262 */
258 263 template <typename T>
... ...
openbr/core/core.cpp
... ... @@ -254,6 +254,56 @@ struct AlgorithmCore
254 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 307 void compare(File targetGallery, File queryGallery, File output)
258 308 {
259 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 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 560 QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess)
503 561 {
504 562 if (!preprocess)
... ...
openbr/core/eigenutils.cpp
... ... @@ -54,3 +54,16 @@ void printEigen(Eigen::MatrixXd X) {
54 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 26 void writeEigen(Eigen::VectorXd X, QString filename);
27 27 void writeEigen(Eigen::VectorXf X, QString filename);
28 28 void printEigen(Eigen::MatrixXd X);
  29 +void printEigen(Eigen::MatrixXf X);
  30 +void printSize(Eigen::MatrixXf X);
29 31  
30 32 template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
31 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 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17 17 #include <opencv2/highgui/highgui.hpp>
  18 +#include <opencv2/highgui/highgui_c.h>
18 19 #include <opencv2/imgproc/imgproc.hpp>
  20 +#include <opencv2/imgproc/imgproc_c.h>
19 21 #include <openbr/openbr_plugin.h>
20 22  
21 23 #include "opencvutils.h"
... ...
openbr/core/opencvutils.h
... ... @@ -22,6 +22,7 @@
22 22 #include <QString>
23 23 #include <QStringList>
24 24 #include <opencv2/core/core.hpp>
  25 +#include <assert.h>
25 26  
26 27 namespace OpenCVUtils
27 28 {
... ...
openbr/gui/tail.cpp
1 1 #include <QtConcurrentRun>
2 2  
3 3 #include "tail.h"
  4 +#include <assert.h>
4 5  
5 6 using namespace br;
6 7  
... ...
openbr/gui/utility.cpp
1 1 #include <limits>
2 2 #include <vector>
  3 +#include <assert.h>
3 4 #include <opencv2/imgproc/imgproc.hpp>
  5 +#include <opencv2/imgproc/imgproc_c.h>
4 6 #include "utility.h"
5 7  
6 8 using namespace cv;
... ...
1   -Subproject commit 0eaa00f19256fee2f24033ff68b526ea6320624d
  1 +Subproject commit f8d9c869c821cc032d092ab1274da8f3cabf5eb7
... ...
openbr/janus.cpp
... ... @@ -3,140 +3,138 @@
3 3 #endif
4 4  
5 5 #include "janus.h"
  6 +#include "janus_io.h"
6 7 #include "openbr_plugin.h"
7 8  
8   -// Use the provided default implementation of some functions
9   -#include "janus/src/janus.cpp"
10   -
11 9 using namespace br;
12 10  
13 11 static QSharedPointer<Transform> transform;
14 12 static QSharedPointer<Distance> distance;
15 13  
  14 +size_t janus_max_template_size()
  15 +{
  16 + return 33554432; // 32 MB
  17 +}
  18 +
16 19 janus_error janus_initialize(const char *sdk_path, const char *model_file)
17 20 {
18 21 int argc = 1;
19 22 const char *argv[1] = { "janus" };
20 23 Context::initialize(argc, (char**)argv, sdk_path);
21 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 35 return JANUS_SUCCESS;
26 36 }
27 37  
28 38 janus_error janus_finalize()
29 39 {
  40 + transform.reset();
  41 + distance.reset();
30 42 Context::finalize();
31 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 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 57 Template t;
48 58 t.append(cv::Mat(image.height,
49 59 image.width,
50   - image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC1,
  60 + image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC3,
51 61 image.data));
52 62 for (size_t i=0; i<attributes.size; i++)
53 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 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 73 Template u;
64 74 transform->project(t, u);
65   - incomplete_template->data.append(u);
  75 + template_->append(u);
66 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 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 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 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 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 139 return JANUS_SUCCESS;
142 140 }
... ...
openbr/openbr.cpp
... ... @@ -24,6 +24,7 @@
24 24 #include "core/qtutils.h"
25 25 #include "plugins/openbr_internal.h"
26 26 #include <opencv2/highgui/highgui.hpp>
  27 +#include <opencv2/highgui/highgui_c.h>
27 28  
28 29 using namespace br;
29 30  
... ... @@ -121,9 +122,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[],
121 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 130 void br_initialize_default()
... ... @@ -381,8 +382,9 @@ bool br_img_is_empty(br_template tmpl)
381 382  
382 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 390 void br_set_filename(br_template tmpl, const char *filename)
... ... @@ -470,3 +472,8 @@ void br_close_gallery(br_gallery gallery)
470 472 Gallery *gal = reinterpret_cast<Gallery*>(gallery);
471 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 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 81 * \brief Clusters one or more similarity matrices into a list of subjects.
71 82 *
72 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 224 * \brief Wraps br::Context::initialize()
214 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 229 * \brief Wraps br::Context::initialize() with default arguments.
219 230 * \see br_finalize
... ...
openbr/openbr_plugin.cpp
... ... @@ -44,12 +44,6 @@ using namespace cv;
44 44  
45 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 47 /* File - public methods */
54 48 // Note that the convention for displaying metadata is as follows:
55 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 842  
849 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 848 void br::Context::printStatus()
... ... @@ -907,42 +895,30 @@ bool br::Context::checkSDKPath(const QString &amp;sdkPath)
907 895 // We create our own when the user hasn't
908 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 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 910 // We take in argc as a reference due to:
925 911 // https://bugreports.qt-project.org/browse/QTBUG-5637
926 912 // QApplication should be initialized before anything else.
927 913 // Since we can't ensure that it gets deleted last, we never delete it.
928 914 if (QCoreApplication::instance() == NULL) {
929 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 920 application = new QCoreApplication(argc, argv);
945   -#endif
  921 +#endif // BR_EMBEDDED
946 922 }
947 923  
948 924 QCoreApplication::setOrganizationName(COMPANY_NAME);
... ... @@ -965,14 +941,14 @@ void br::Context::initialize(int &amp;argc, char *argv[], QString sdkPath, bool use_
965 941  
966 942 Globals = new Context();
967 943 Globals->init(File());
968   - Globals->useGui = use_gui;
969   -
  944 + Globals->useGui = useGui;
970 945  
971 946 Common::seedRNG();
972 947  
973 948 // Search for SDK
974 949 if (sdkPath.isEmpty()) {
975 950 QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath();
  951 + checkPaths << QString(getenv("PATH")).split(sep, QString::SkipEmptyParts);
976 952  
977 953 bool foundSDK = false;
978 954 foreach (const QString &path, checkPaths) {
... ... @@ -1035,26 +1011,6 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte
1035 1011 static QMutex generalLock;
1036 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 1014 QString txt;
1059 1015 if (type == QtDebugMsg) {
1060 1016 if (Globals->quiet) return;
... ... @@ -1076,8 +1032,13 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &amp;conte
1076 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 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 1044 Context *br::Globals = NULL;
... ...
openbr/openbr_plugin.h
... ... @@ -41,6 +41,7 @@
41 41 #include <QVector>
42 42 #include <opencv2/core/core.hpp>
43 43 #include <openbr/openbr.h>
  44 +#include <assert.h>
44 45  
45 46 /*!
46 47 * \defgroup cpp_plugin_sdk C++ Plugin SDK
... ... @@ -794,12 +795,12 @@ public:
794 795 * By default <tt>share/openbr/openbr.bib</tt> will be searched for relative to:
795 796 * -# The working directory
796 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 799 * \note Tiggers \em abort() on failure to locate <tt>share/openbr/openbr.bib</tt>.
799 800 * \note <a href="http://qt-project.org/">Qt</a> users should instead call this <i>after</i> initializing QApplication.
800 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 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 1372 */
1372 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 1385 } // namespace br
... ...
openbr/plugins/algorithms.cpp
... ... @@ -50,6 +50,9 @@ class AlgorithmsInitializer : public Initializer
50 50 Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)");
51 51 Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)");
52 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 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 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 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 81 // Transforms
79   - Globals->abbreviations.insert("FaceDetection", "(Open+Cvt(Gray)+Cascade(FrontalFace))");
  82 + Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)");
80 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 84 Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)");
82 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 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17 17 #include <opencv2/objdetect/objdetect.hpp>
  18 +//#include <opencv2/objdetect/objdetect_c.h>
18 19 #include "openbr_internal.h"
19 20 #include "openbr/core/opencvutils.h"
20 21 #include "openbr/core/resource.h"
... ... @@ -86,11 +87,11 @@ class CascadeTransform : public UntrainableMetaTransform
86 87  
87 88 for (int i=0; i<t.size(); i++) {
88 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 96 if (!enrollAll && rects.empty())
96 97 rects.push_back(Rect(0, 0, m.cols, m.rows));
... ...
openbr/plugins/cvt.cpp
... ... @@ -14,6 +14,7 @@
14 14 * limitations under the License. *
15 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
  17 +#include <opencv2/imgproc/imgproc_c.h>
17 18 #include <opencv2/imgproc/imgproc.hpp>
18 19 #include "openbr_internal.h"
19 20 #include "openbr/core/opencvutils.h"
... ... @@ -44,7 +45,8 @@ public:
44 45 Luv = CV_BGR2Luv,
45 46 RGB = CV_BGR2RGB,
46 47 XYZ = CV_BGR2XYZ,
47   - YCrCb = CV_BGR2YCrCb };
  48 + YCrCb = CV_BGR2YCrCb,
  49 + Color = CV_GRAY2BGR };
48 50  
49 51 private:
50 52 BR_PROPERTY(ColorSpace, colorSpace, Gray)
... ... @@ -52,8 +54,8 @@ private:
52 54  
53 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 60 if (channel != -1) {
59 61 std::vector<Mat> mv;
... ...
openbr/plugins/distance.cpp
... ... @@ -18,6 +18,7 @@
18 18 #include <QtConcurrentRun>
19 19 #include <numeric>
20 20 #include <opencv2/imgproc/imgproc.hpp>
  21 +#include <opencv2/imgproc/imgproc_c.h>
21 22 #include "openbr_internal.h"
22 23  
23 24 #include "openbr/core/distance_sse.h"
... ... @@ -61,6 +62,7 @@ private:
61 62 (a.m().type() != b.m().type()))
62 63 return -std::numeric_limits<float>::max();
63 64  
  65 +// TODO: this max value is never returned based on the switch / default
64 66 float result = std::numeric_limits<float>::max();
65 67 switch (metric) {
66 68 case Correlation:
... ... @@ -386,5 +388,67 @@ class OnlineDistance : public Distance
386 388  
387 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 453 } // namespace br
390 454 #include "distance.moc"
... ...
openbr/plugins/draw.cpp
... ... @@ -15,6 +15,7 @@
15 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17 17 #include <opencv2/highgui/highgui.hpp>
  18 +#include <opencv2/highgui/highgui_c.h>
18 19 #include <opencv2/imgproc/imgproc.hpp>
19 20 #include <vector>
20 21 #include "openbr_internal.h"
... ... @@ -40,10 +41,12 @@ class DrawTransform : public UntrainableTransform
40 41 Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false)
41 42 Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false)
42 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 45 BR_PROPERTY(bool, verbose, false)
44 46 BR_PROPERTY(bool, points, true)
45 47 BR_PROPERTY(bool, rects, true)
46 48 BR_PROPERTY(bool, inPlace, false)
  49 + BR_PROPERTY(int, lineThickness, 1)
47 50  
48 51 void project(const Template &src, Template &dst) const
49 52 {
... ... @@ -61,7 +64,7 @@ class DrawTransform : public UntrainableTransform
61 64 }
62 65 if (rects) {
63 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 346  
344 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 418 // TODO: re-implement EditTransform using Qt
347 419 #if 0
348 420 /*!
... ...
openbr/plugins/eigen3.cpp
... ... @@ -302,8 +302,8 @@ class LDATransform : public Transform
302 302 Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false)
303 303 Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false)
304 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 307 BR_PROPERTY(float, pcaKeep, 0.98)
308 308 BR_PROPERTY(bool, pcaWhiten, false)
309 309 BR_PROPERTY(int, directLDA, 0)
... ... @@ -316,12 +316,6 @@ class LDATransform : public Transform
316 316 Eigen::VectorXf mean;
317 317 Eigen::MatrixXf projection;
318 318 float stdDev;
319   - bool trained;
320   -
321   - void init()
322   - {
323   - trained = false;
324   - }
325 319  
326 320 void train(const TemplateList &_trainingSet)
327 321 {
... ... @@ -461,9 +455,9 @@ class LDATransform : public Transform
461 455 projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose();
462 456 dimsOut = dim2;
463 457  
  458 + stdDev = 1; // default initialize
464 459 if (isBinary) {
465 460 assert(dimsOut == 1);
466   - TemplateList projected;
467 461 float posVal = 0;
468 462 float negVal = 0;
469 463 Eigen::MatrixXf results(trainingSet.size(),1);
... ... @@ -493,8 +487,6 @@ class LDATransform : public Transform
493 487 if (normalize)
494 488 stdDev = sqrt(results.array().square().sum() / trainingSet.size());
495 489 }
496   -
497   - trained = true;
498 490 }
499 491  
500 492 void project(const Template &src, Template &dst) const
... ... @@ -508,18 +500,22 @@ class LDATransform : public Transform
508 500 // Do projection
509 501 outMap = projection.transpose() * (inMap - mean);
510 502  
511   - if (normalize && isBinary && trained)
  503 + if (normalize && isBinary)
512 504 dst.m().at<float>(0,0) = dst.m().at<float>(0,0) / stdDev;
513 505 }
514 506  
515 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 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 34 */
35 35  
36 36 #include <opencv2/imgproc/imgproc.hpp>
  37 +#include <opencv2/imgproc/imgproc_c.h>
37 38 #include "openbr_internal.h"
38 39 #include "openbr/core/opencvutils.h"
39 40  
... ...
openbr/plugins/format.cpp
... ... @@ -16,10 +16,12 @@
16 16  
17 17 #include <QDate>
18 18 #include <QSize>
  19 +#include <QChar>
19 20 #ifndef BR_EMBEDDED
20 21 #include <QtXml>
21 22 #endif // BR_EMBEDDED
22 23 #include <opencv2/highgui/highgui.hpp>
  24 +#include <opencv2/highgui/highgui_c.h>
23 25 #include "openbr_internal.h"
24 26  
25 27 #include "openbr/core/bee.h"
... ... @@ -719,7 +721,7 @@ BR_REGISTER(Format, xmlFormat)
719 721 /*!
720 722 * \ingroup formats
721 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 726 * Example of the format:
725 727 * \code
... ... @@ -768,6 +770,90 @@ class scoresFormat : public Format
768 770  
769 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 857 } // namespace br
772 858  
773 859 #include "format.moc"
... ...
openbr/plugins/gallery.cpp
... ... @@ -32,6 +32,11 @@
32 32 #include "openbr/core/opencvutils.h"
33 33 #include "openbr/core/qtutils.h"
34 34  
  35 +#ifdef CVMATIO
  36 +#include "MatlabIO.hpp"
  37 +#include "MatlabIOContainer.hpp"
  38 +#endif
  39 +
35 40 namespace br
36 41 {
37 42  
... ... @@ -969,6 +974,74 @@ class landmarksGallery : public Gallery
969 974  
970 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 1045 } // namespace br
973 1046  
974 1047 #include "gallery.moc"
... ...
openbr/plugins/gui.cpp
... ... @@ -12,6 +12,7 @@
12 12 #include <QLineEdit>
13 13  
14 14 #include <opencv2/imgproc/imgproc.hpp>
  15 +#include <opencv2/imgproc/imgproc_c.h>
15 16 #include "openbr_internal.h"
16 17 #include "openbr/gui/utility.h"
17 18  
... ...
openbr/plugins/hist.cpp
... ... @@ -94,7 +94,7 @@ class BinTransform : public UntrainableTransform
94 94 } else if (channels == 2) {
95 95 // If there are two channels, the first is channel is assumed to be a weight vector
96 96 // and the second channel contains the vectors we would like to bin.
97   - vector<Mat> mv;
  97 + std::vector<Mat> mv;
98 98 cv::split(src, mv);
99 99 weights = mv[0];
100 100 weights.convertTo(weights, CV_32F);
... ...
openbr/plugins/integral.cpp
1 1 #include <opencv2/imgproc/imgproc.hpp>
  2 +#include <opencv2/imgproc/imgproc_c.h>
2 3 #include <Eigen/Core>
3 4 #include "openbr_internal.h"
4 5  
... ... @@ -293,7 +294,7 @@ private:
293 294 Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR);
294 295 Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR);
295 296 cartToPolar(dx, dy, magnitude, angle, true);
296   - vector<Mat> mv;
  297 + std::vector<Mat> mv;
297 298 if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) {
298 299 const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f));
299 300 mv.push_back(magnitude / theoreticalMaxMagnitude);
... ...
openbr/plugins/landmarks.cpp
... ... @@ -290,16 +290,18 @@ class DrawDelaunayTransform : public UntrainableTransform
290 290  
291 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 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17 17 #include <opencv2/imgproc/imgproc.hpp>
  18 +#include <opencv2/imgproc/imgproc_c.h>
18 19 #include <opencv2/highgui/highgui.hpp>
  20 +#include <opencv2/highgui/highgui_c.h>
19 21 #include <limits>
20 22 #include "openbr_internal.h"
21 23  
... ...
openbr/plugins/ltp.cpp
... ... @@ -15,6 +15,7 @@
15 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17 17 #include <opencv2/imgproc/imgproc.hpp>
  18 +#include <opencv2/imgproc/imgproc_c.h>
18 19 #include <limits>
19 20 #include "openbr_internal.h"
20 21  
... ...
openbr/plugins/mask.cpp
... ... @@ -15,6 +15,7 @@
15 15 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16 16  
17 17 #include <opencv2/imgproc/imgproc.hpp>
  18 +#include <opencv2/imgproc/imgproc_c.h>
18 19 #include "openbr_internal.h"
19 20  
20 21 using namespace cv;
... ... @@ -164,7 +165,7 @@ class LargestConvexAreaTransform : public UntrainableTransform
164 165 void project(const Template &src, Template &dst) const
165 166 {
166 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 169 double maxArea = 0;
169 170 foreach (const std::vector<Point> &contour, contours) {
170 171 std::vector<Point> hull;
... ...
openbr/plugins/misc.cpp
... ... @@ -537,7 +537,7 @@ class ProgressCounterTransform : public TimeVaryingTransform
537 537 {
538 538 (void) data;
539 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 543 void init()
... ...
openbr/plugins/motion.cpp
... ... @@ -23,6 +23,7 @@ class OpticalFlowTransform : public UntrainableMetaTransform
23 23 Q_PROPERTY(int poly_n READ get_poly_n WRITE set_poly_n RESET reset_poly_n STORED false)
24 24 Q_PROPERTY(double poly_sigma READ get_poly_sigma WRITE set_poly_sigma RESET reset_poly_sigma STORED false)
25 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 27 // these defaults are optimized for KTH
27 28 BR_PROPERTY(double, pyr_scale, 0.1)
28 29 BR_PROPERTY(int, levels, 1)
... ... @@ -31,22 +32,27 @@ class OpticalFlowTransform : public UntrainableMetaTransform
31 32 BR_PROPERTY(int, poly_n, 7)
32 33 BR_PROPERTY(double, poly_sigma, 1.1)
33 34 BR_PROPERTY(int, flags, 0)
  35 + BR_PROPERTY(bool, useMagnitude, true)
34 36  
35 37 void project(const Template &src, Template &dst) const
36 38 {
37 39 // get the two images put there by AggregateFrames
38 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 42 if (src[0].channels() != 1) OpenCVUtils::cvtGray(src[0], prevImg);
41 43 if (src[1].channels() != 1) OpenCVUtils::cvtGray(src[1], nextImg);
42 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 56 dst.file = src.file;
51 57 }
52 58 };
... ... @@ -62,7 +68,8 @@ class SubtractBackgroundTransform : public TimeVaryingTransform
62 68 {
63 69 Q_OBJECT
64 70  
65   - BackgroundSubtractorMOG2 mog;
  71 + // TODO: This is broken.
  72 + // BackgroundSubtractorMOG2 mog;
66 73  
67 74 public:
68 75 SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {}
... ... @@ -72,7 +79,8 @@ private:
72 79 {
73 80 dst = src;
74 81 Mat mask;
75   - mog(src, mask);
  82 + // TODO: broken
  83 + // mog(src, mask);
76 84 erode(mask, mask, Mat());
77 85 dilate(mask, mask, Mat());
78 86 dst.file.set("Mask", QVariant::fromValue(mask));
... ... @@ -86,7 +94,8 @@ private:
86 94 void finalize(TemplateList &output)
87 95 {
88 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 60  
61 61 Q_PROPERTY(bool ByRow READ get_ByRow WRITE set_ByRow RESET reset_ByRow STORED false)
62 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 68 public:
65 69 /*!< */
66 70 enum NormType { Inf = NORM_INF,
67 71 L1 = NORM_L1,
68   - L2 = NORM_L2 };
  72 + L2 = NORM_L2,
  73 + Range = NORM_MINMAX };
69 74  
70 75 private:
71 76 BR_PROPERTY(NormType, normType, L2)
72 77  
73 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 81 else {
77 82 dst = src;
78 83 for (int i=0; i<dst.m().rows; i++) {
79 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 86 temp.copyTo(dst.m().row(i));
82 87 }
83 88 }
... ... @@ -132,7 +137,7 @@ private:
132 137 const QList<int> labels = data.indexProperty(inputVariable);
133 138 const int dims = m.cols;
134 139  
135   - vector<Mat> mv, av, bv;
  140 + std::vector<Mat> mv, av, bv;
136 141 split(m, mv);
137 142 for (size_t c = 0; c < mv.size(); c++) {
138 143 av.push_back(Mat(1, dims, CV_64FC1));
... ...
openbr/plugins/output.cpp
... ... @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput
268 268  
269 269 for (int i=0; i<queryFiles.size(); i++) {
270 270 QStringList files;
271   - if (simple) files.append(queryFiles[i]);
  271 + if (simple) files.append(queryFiles[i].fileName());
272 272  
273 273 typedef QPair<float,int> Pair;
274 274 foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true, limit)) {
... ... @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput
276 276 if (pair.first < threshold) break;
277 277 File target = targetFiles[pair.second];
278 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 280 else files.append(target.flat());
281 281 }
282 282 }
... ... @@ -528,7 +528,7 @@ class tailOutput : public Output
528 528 } else {
529 529 // General case
530 530 for (int k=0; k<comparisons.size(); k++) {
531   - if (comparisons[k].value < value) {
  531 + if (comparisons[k].value <= value) {
532 532 comparisons.insert(k, Comparison(queryFiles[i], targetFiles[j], value));
533 533 break;
534 534 }
... ... @@ -539,6 +539,7 @@ class tailOutput : public Output
539 539 comparisons.removeLast();
540 540 while ((comparisons.size() > atLeast) && (comparisons.last().value < threshold))
541 541 comparisons.removeLast();
  542 +
542 543 lastValue = comparisons.last().value;
543 544 comparisonsLock.unlock();
544 545 }
... ...
openbr/plugins/process.cpp
... ... @@ -531,8 +531,6 @@ class ProcessWrapperTransform : public TimeVaryingTransform
531 531 baseKey = id.toString();
532 532  
533 533 QStringList argumentList;
534   - argumentList.append("-useGui");
535   - argumentList.append("0");
536 534 argumentList.append("-algorithm");
537 535 argumentList.append(transform);
538 536 if (!Globals->path.isEmpty()) {
... ...
openbr/plugins/quality.cpp
... ... @@ -272,92 +272,75 @@ BR_REGISTER(Distance, ZScoreDistance)
272 272  
273 273 /*!
274 274 * \ingroup distances
275   - * \brief Match Probability modification for heat maps \cite klare12
  275 + * \brief 1v1 heat map comparison
276 276 * \author Scott Klum \cite sklum
277 277 */
278 278 class HeatMapDistance : public Distance
279 279 {
280 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 282 Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false)
285 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 285 BR_PROPERTY(int, step, 1)
290 286 BR_PROPERTY(QString, inputVariable, "Label")
291 287  
292   - QList<MP> mp;
  288 + QList<br::Distance*> distances;
293 289  
294 290 void train(const TemplateList &src)
295 291 {
296   - distance->train(src);
297   -
298   - const QList<int> labels = src.indexProperty(inputVariable);
299   -
300 292 QList<TemplateList> patches;
301 293  
302 294 // Split src into list of TemplateLists of corresponding patches across all Templates
303 295 for (int i=0; i<step; i++) {
304 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 299 patches.append(patchBuffer);
309 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 311 float compare(const Template &target, const Template &query) const
334 312 {
335 313 (void) target;
336 314 (void) query;
337   - qFatal("You did this wrong");
  315 + qFatal("Heatmap Distance not compatible with Template to Template comparison.");
338 316  
339 317 return 0;
340 318 }
341 319  
342 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 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 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 35  
36 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 39 Globals->abbreviations.insert("RectFromStasmBrow","RectFromPoints([16,17,18,19,20,21,22,23,24,25,26,27],0.15,5)");
40 40 Globals->abbreviations.insert("RectFromStasmNose","RectFromPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],0.15,1.15)");
41 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 2 #include <QReadWriteLock>
2 3 #include <QWaitCondition>
3 4 #include <QThreadPool>
4 5 #include <QSemaphore>
5 6 #include <QMap>
6   -#include <opencv/highgui.h>
  7 +#include <QQueue>
7 8 #include <QtConcurrent>
  9 +#include <opencv/highgui.h>
  10 +#include <opencv2/highgui/highgui.hpp>
8 11 #include "openbr_internal.h"
9   -
10 12 #include "openbr/core/common.h"
11 13 #include "openbr/core/opencvutils.h"
12 14 #include "openbr/core/qtutils.h"
13 15  
14 16 using namespace cv;
  17 +using namespace std;
15 18  
16 19 namespace br
17 20 {
... ... @@ -203,6 +206,13 @@ public:
203 206 virtual bool getNextTemplate(Template & output)=0;
204 207 protected:
205 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 218 static QMutex openLock;
... ... @@ -236,12 +246,9 @@ public:
236 246 qDebug("Video not open!");
237 247 }
238 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 249 // On windows, this appears to not be thread-safe
243 250 QMutexLocker lock(&openLock);
244   - video.open(QFileInfo(fileName).absoluteFilePath().toStdString());
  251 + video.open(getAbsolutePath(input.file.name));
245 252 }
246 253  
247 254 return video.isOpened();
... ... @@ -319,6 +326,198 @@ protected:
319 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 522 // Interface for sequentially getting data from some data source.
324 523 // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor
... ... @@ -514,11 +713,16 @@ protected:
514 713 if (frameSource)
515 714 frameSource->close();
516 715  
  716 + Template curr = this->templates[current_template_idx];
517 717 if (mode == br::Idiocy::Auto)
518 718 {
519 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 726 else
523 727 frameSource = new DirectReturn();
524 728 }
... ... @@ -529,11 +733,14 @@ protected:
529 733 }
530 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 744 if (!open_res)
538 745 {
539 746 current_template_idx++;
... ... @@ -1079,8 +1286,7 @@ public:
1079 1286  
1080 1287 // Wait for the stream to process the last frame available from
1081 1288 // the data source.
1082   - bool wait_res = false;
1083   - wait_res = readStage->dataSource.waitLast();
  1289 + readStage->dataSource.waitLast();
1084 1290  
1085 1291 // Now that there are no more incoming frames, call finalize
1086 1292 // on each transform in turn to collect any last templates
... ... @@ -1217,6 +1423,7 @@ public:
1217 1423 {
1218 1424 // Delete all the stages
1219 1425 for (int i = 0; i < processingStages.size(); i++) {
  1426 +// TODO: Are we releasing memory which is already freed?
1220 1427 delete processingStages[i];
1221 1428 }
1222 1429 processingStages.clear();
... ...
scripts/downloadDatasets.sh
... ... @@ -35,6 +35,35 @@ if [ ! -d ../data/BioID/img ]; then
35 35 rm *.eye description.txt BioID-FaceDatabase-V1.2.zip
36 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 67 # INRIA person
39 68 if [ ! -d ../data/INRIAPerson/img ]; then
40 69 echo "Downloading INRIA person dataset..."
... ... @@ -66,7 +95,7 @@ if [ ! -d ../data/KTH/vid ]; then
66 95 fi
67 96 mkdir ../data/KTH/vid/${vidclass}
68 97 unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass}
69   - rm ${vidclass}.zip
  98 + rm ${vidclass}.zip
70 99 done
71 100 # this file is corrupted
72 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 4 exit
5 5 fi
6 6  
7   -export BR="../build/app/br/br -useGui 0"
  7 +export BR=../build/app/br/br
8 8 export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/
9 9 export ageAlg=AgeRegression
10 10  
... ...
scripts/evalFaceRecognition-LFW.sh
... ... @@ -20,7 +20,7 @@ if [ ! -e Algorithm_Dataset ]; then
20 20 fi
21 21  
22 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 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 20 fi
21 21  
22 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 24 fi
25 25  
26 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 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 9 export PCSO_DIR=../data/PCSO/img
10 10  
11 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 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 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 17 \ No newline at end of file
... ...
scripts/pedestrianBaselineLBP.sh
... ... @@ -27,8 +27,7 @@ else
27 27 TEST=testSmall.xml
28 28 fi
29 29  
30   -br -useGui 0 \
31   - -algorithm "${ALG}" \
  30 +br -algorithm "${ALG}" \
32 31 -path $INRIA_PATH/img \
33 32 -train $INRIA_PATH/sigset/train.xml pedModel \
34 33 -enroll $INRIA_PATH/sigset/$TEST pedResults.xml
... ...
scripts/trainAgeRegression-PCSO.sh
... ... @@ -13,4 +13,4 @@ export ageAlg=AgeRegression
13 13  
14 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 14  
15 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 13  
14 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 8 # target_link_libraries(MY_TARGET_NAME ${OPENBR_LIBS})
9 9 # ================================================================
10 10  
  11 +find_path(OPENBR_DIR include/openbr/openbr.h)
11 12 include_directories(${OPENBR_DIR}/include)
12 13 link_directories(${OPENBR_DIR}/lib)
13 14 set(OPENBR_LIBS "openbr")
... ...