Commit ef44eed775ac606bc8d28aa5b883c091c06324d7

Authored by Scott Klum
2 parents a83b5e97 bdf861b4

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

.gitignore
... ... @@ -2,6 +2,7 @@
2 2 3rdparty/LatentSDK*
3 3 3rdparty/pittpatt*
4 4 data/*/img
  5 +data/*/vid
5 6 data/PCSO/*
6 7 build*
7 8 scripts/results
... ...
app/br/br.cpp
... ... @@ -135,11 +135,14 @@ public:
135 135 check(parc == 2, "Incorrect parameter count for 'evalClustering'.");
136 136 br_eval_clustering(parv[0], parv[1]);
137 137 } else if (!strcmp(fun, "evalDetection")) {
138   - check(parc == 2, "Incorrect parameter count for 'evalDetection'.");
139   - br_eval_detection(parv[0], parv[1]);
  138 + check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'evalDetection'.");
  139 + br_eval_detection(parv[0], parv[1], parc == 3 ? parv[2] : "");
140 140 } else if (!strcmp(fun, "evalRegression")) {
141 141 check(parc == 2, "Incorrect parameter count for 'evalRegression'.");
142 142 br_eval_regression(parv[0], parv[1]);
  143 + } else if (!strcmp(fun, "plotDetection")) {
  144 + check(parc >= 2, "Incorrect parameter count for 'plotDetection'.");
  145 + br_plot_detection(parc-1, parv, parv[parc-1], true);
143 146 } else if (!strcmp(fun, "plotMetadata")) {
144 147 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'.");
145 148 br_plot_metadata(parc-1, parv, parv[parc-1], true);
... ... @@ -214,8 +217,9 @@ private:
214 217 "-convert (Format|Gallery|Output) <input_file> {output_file}\n"
215 218 "-evalClassification <predicted_gallery> <truth_gallery>\n"
216 219 "-evalClustering <clusters> <gallery>\n"
217   - "-evalDetection <predicted_gallery> <truth_gallery>\n"
  220 + "-evalDetection <predicted_gallery> <truth_gallery> [{csv}]\n"
218 221 "-evalRegression <predicted_gallery> <truth_gallery>\n"
  222 + "-plotDetection <file> ... <file> {destination}\n"
219 223 "-plotMetadata <file> ... <file> <columns>\n"
220 224 "-getHeader <matrix>\n"
221 225 "-setHeader {<matrix>} <target_gallery> <query_gallery>\n"
... ...
openbr/core/eval.cpp
... ... @@ -23,6 +23,8 @@ using namespace cv;
23 23 namespace br
24 24 {
25 25  
  26 +static const int Max_Points = 500; // Maximum number of points to render on plots
  27 +
26 28 struct Comparison
27 29 {
28 30 float score;
... ... @@ -100,7 +102,6 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv)
100 102 qFatal("Similarity matrix (%ix%i) differs in size from mask matrix (%ix%i).",
101 103 simmat.rows, simmat.cols, mask.rows, mask.cols);
102 104  
103   - const int Max_Points = 500;
104 105 float result = -1;
105 106  
106 107 // Make comparisons
... ... @@ -237,7 +238,7 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv)
237 238 if (i == Report_Retrieval) reportRetrievalRate = retrievalRate;
238 239 }
239 240  
240   - if (!csv.isEmpty()) QtUtils::writeFile(csv, lines);
  241 + QtUtils::writeFile(csv, lines);
241 242 qDebug("TAR @ FAR = 0.01: %.3f\nRetrieval Rate @ Rank = %d: %.3f", result, Report_Retrieval, reportRetrievalRate);
242 243 return result;
243 244 }
... ... @@ -325,7 +326,7 @@ struct Detection
325 326 float overlap(const Detection &other) const
326 327 {
327 328 const Detection intersection(boundingBox.intersected(other.boundingBox));
328   - return intersection.area() / (area() + other.area() - 2*intersection.area());
  329 + return intersection.area() / (area() + other.area() - intersection.area());
329 330 }
330 331 };
331 332  
... ... @@ -334,14 +335,53 @@ struct Detections
334 335 QList<Detection> predicted, truth;
335 336 };
336 337  
337   -struct DetectionOperatingPoint
  338 +struct ResolvedDetection
338 339 {
339 340 float confidence, overlap;
340   - DetectionOperatingPoint() : confidence(-1), overlap(-1) {}
341   - DetectionOperatingPoint(float confidence_, float overlap_) : confidence(confidence_), overlap(overlap_) {}
342   - inline bool operator<(const DetectionOperatingPoint &other) const { return confidence > other.confidence; }
  341 + ResolvedDetection() : confidence(-1), overlap(-1) {}
  342 + ResolvedDetection(float confidence_, float overlap_) : confidence(confidence_), overlap(overlap_) {}
  343 + inline bool operator<(const ResolvedDetection &other) const { return confidence > other.confidence; }
  344 +};
  345 +
  346 +struct DetectionOperatingPoint
  347 +{
  348 + float Recall, FalsePositives, Precision;
  349 + DetectionOperatingPoint() : Recall(-1), FalsePositives(-1), Precision(-1) {}
  350 + DetectionOperatingPoint(float TP, float FP, float totalPositives)
  351 + : Recall(TP/totalPositives), FalsePositives(FP), Precision(TP/(TP+FP)) {}
343 352 };
344 353  
  354 +static QStringList computeDetectionResults(const QList<ResolvedDetection> &detections, int totalPositives, bool discrete)
  355 +{
  356 + QList<DetectionOperatingPoint> points;
  357 + float TP = 0, FP = 0, prevFP = 0;
  358 + for (int i=0; i<detections.size(); i++) {
  359 + const ResolvedDetection &detection = detections[i];
  360 + if (discrete) {
  361 + if (detection.overlap >= 0.5) TP++;
  362 + else FP++;
  363 + } else {
  364 + TP += detection.overlap;
  365 + FP += 1 - detection.overlap;
  366 + }
  367 + if ((i == detections.size()-1) || (detection.confidence > detections[i+1].confidence)) {
  368 + if (FP > prevFP) {
  369 + points.append(DetectionOperatingPoint(TP, FP, totalPositives));
  370 + prevFP = FP;
  371 + }
  372 + }
  373 + }
  374 +
  375 + const int keep = qMin(points.size(), Max_Points);
  376 + QStringList lines; lines.reserve(keep);
  377 + for (int i=0; i<keep; i++) {
  378 + const DetectionOperatingPoint &point = points[double(i) / double(keep-1) * double(points.size()-1)];
  379 + lines.append(QString("%1ROC, %2, %3").arg(discrete ? "Discrete" : "Continuous", QString::number(point.FalsePositives), QString::number(point.Recall)));
  380 + lines.append(QString("%1PR, %2, %3").arg(discrete ? "Discrete" : "Continuous", QString::number(point.Precision), QString::number(point.Recall)));
  381 + }
  382 + return lines;
  383 +}
  384 +
345 385 float EvalDetection(const QString &predictedInput, const QString &truthInput, const QString &csv)
346 386 {
347 387 qDebug("Evaluating detection of %s against %s", qPrintable(predictedInput), qPrintable(truthInput));
... ... @@ -358,18 +398,18 @@ float EvalDetection(const QString &amp;predictedInput, const QString &amp;truthInput, co
358 398 if (detectKey.isNull()) qFatal("No suitable metadata key found.");
359 399 else qDebug("Using metadata key: %s", qPrintable(detectKey));
360 400  
361   - QHash<QString, Detections> allDetections; // Organized by file
  401 + QMap<QString, Detections> allDetections; // Organized by file, QMap used to preserve order
362 402 foreach (const Template &t, predicted)
363 403 allDetections[t.file.baseName()].predicted.append(Detection(t.file.get<QRectF>(detectKey), t.file.get<float>("Confidence", -1)));
364 404 foreach (const Template &t, truth)
365 405 allDetections[t.file.baseName()].truth.append(Detection(t.file.get<QRectF>(detectKey)));
366 406  
367   - QList<DetectionOperatingPoint> points;
  407 + QList<ResolvedDetection> resolvedDetections, falseNegativeDetections;
368 408 foreach (Detections detections, allDetections.values()) {
369 409 while (!detections.truth.isEmpty() && !detections.predicted.isEmpty()) {
370   - Detection truth = detections.truth.takeFirst();
  410 + const Detection truth = detections.truth.takeFirst();
371 411 int bestIndex = -1;
372   - float bestOverlap = -1;
  412 + float bestOverlap = -std::numeric_limits<float>::max();
373 413 for (int i=0; i<detections.predicted.size(); i++) {
374 414 const float overlap = truth.overlap(detections.predicted[i]);
375 415 if (overlap > bestOverlap) {
... ... @@ -377,25 +417,40 @@ float EvalDetection(const QString &amp;predictedInput, const QString &amp;truthInput, co
377 417 bestIndex = i;
378 418 }
379 419 }
380   - Detection predicted = detections.predicted.takeAt(bestIndex);
381   - points.append(DetectionOperatingPoint(predicted.confidence, bestOverlap));
  420 + const Detection predicted = detections.predicted.takeAt(bestIndex);
  421 + resolvedDetections.append(ResolvedDetection(predicted.confidence, bestOverlap));
382 422 }
383 423  
384 424 foreach (const Detection &detection, detections.predicted)
385   - points.append(DetectionOperatingPoint(detection.confidence, 0));
  425 + resolvedDetections.append(ResolvedDetection(detection.confidence, 0));
386 426 for (int i=0; i<detections.truth.size(); i++)
387   - points.append(DetectionOperatingPoint(-std::numeric_limits<float>::max(), 0));
  427 + falseNegativeDetections.append(ResolvedDetection(-std::numeric_limits<float>::max(), 0));
388 428 }
389 429  
390   - std::sort(points.begin(), points.end());
  430 + std::sort(resolvedDetections.begin(), resolvedDetections.end());
391 431  
392 432 QStringList lines;
393 433 lines.append("Plot, X, Y");
  434 + lines.append(computeDetectionResults(resolvedDetections, truth.size(), true));
  435 + lines.append(computeDetectionResults(resolvedDetections, truth.size(), false));
  436 +
  437 + float averageOverlap;
  438 + { // Overlap Density
  439 + QList<ResolvedDetection> allDetections; allDetections << resolvedDetections << falseNegativeDetections;
  440 + const int keep = qMin(allDetections.size(), Max_Points);
  441 + lines.reserve(lines.size() + keep);
  442 + float totalOverlap = 0;
  443 + for (int i=0; i<keep; i++) {
  444 + const float overlap = allDetections[double(i) / double(keep-1) * double(allDetections.size()-1)].overlap;
  445 + totalOverlap += overlap;
  446 + lines.append(QString("Overlap,%1,1").arg(QString::number(allDetections[double(i) / double(keep-1) * double(allDetections.size()-1)].overlap)));
  447 + }
  448 + averageOverlap = totalOverlap / keep;
  449 + }
394 450  
395   - // TODO: finish implementing
396   -
397   - (void) csv;
398   - return 0;
  451 + QtUtils::writeFile(csv, lines);
  452 + qDebug("Average Overlap = %.3f", averageOverlap);
  453 + return averageOverlap;
399 454 }
400 455  
401 456 void EvalRegression(const QString &predictedInput, const QString &truthInput)
... ...
openbr/core/plot.cpp
... ... @@ -79,7 +79,7 @@ struct RPlot
79 79  
80 80 Pivot major, minor;
81 81  
82   - RPlot(QStringList files, const br::File &destination, bool isEvalFormat = true)
  82 + RPlot(QStringList files, const File &destination, bool isEvalFormat = true)
83 83 {
84 84 if (files.isEmpty()) qFatal("Empty file list.");
85 85 qSort(files.begin(), files.end(), sortFiles);
... ... @@ -214,7 +214,7 @@ struct RPlot
214 214 };
215 215  
216 216 // Does not work if dataset folder starts with a number
217   -bool Plot(const QStringList &files, const br::File &destination, bool show)
  217 +bool Plot(const QStringList &files, const File &destination, bool show)
218 218 {
219 219 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination));
220 220  
... ... @@ -272,6 +272,15 @@ bool Plot(const QStringList &amp;files, const br::File &amp;destination, bool show)
272 272 return p.finalize(show);
273 273 }
274 274  
  275 +bool PlotDetection(const QStringList &files, const File &destination, bool show)
  276 +{
  277 + qDebug("Plotting %d detection file(s) to %s", files.size(), qPrintable(destination));
  278 +
  279 + RPlot p(files, destination, false);
  280 +
  281 + return p.finalize(show);
  282 +}
  283 +
275 284 bool PlotMetadata(const QStringList &files, const QString &columns, bool show)
276 285 {
277 286 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns));
... ...
openbr/core/plot.h
... ... @@ -24,7 +24,8 @@
24 24  
25 25 namespace br
26 26 {
27   - bool Plot(const QStringList &files, const br::File &destination, bool show = false);
  27 + bool Plot(const QStringList &files, const File &destination, bool show = false);
  28 + bool PlotDetection(const QStringList &files, const File &destination, bool show = false);
28 29 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false);
29 30 }
30 31  
... ...
openbr/core/qtutils.cpp
... ... @@ -105,6 +105,7 @@ void QtUtils::writeFile(const QString &amp;file, const QString &amp;data)
105 105  
106 106 void QtUtils::writeFile(const QString &file, const QByteArray &data, int compression)
107 107 {
  108 + if (file.isEmpty()) return;
108 109 const QString baseName = QFileInfo(file).baseName();
109 110 const QByteArray contents = (compression == 0) ? data : qCompress(data, compression);
110 111 if (baseName == "terminal") {
... ...
openbr/openbr.cpp
... ... @@ -82,9 +82,9 @@ void br_eval_clustering(const char *csv, const char *gallery)
82 82 EvalClustering(csv, gallery);
83 83 }
84 84  
85   -void br_eval_detection(const char *predicted_gallery, const char *truth_gallery)
  85 +float br_eval_detection(const char *predicted_gallery, const char *truth_gallery, const char *csv)
86 86 {
87   - EvalDetection(predicted_gallery, truth_gallery);
  87 + return EvalDetection(predicted_gallery, truth_gallery, csv);
88 88 }
89 89  
90 90 void br_eval_regression(const char *predicted_gallery, const char *truth_gallery)
... ... @@ -172,6 +172,11 @@ bool br_plot(int num_files, const char *files[], const char *destination, bool s
172 172 return Plot(QtUtils::toStringList(num_files, files), destination, show);
173 173 }
174 174  
  175 +bool br_plot_detection(int num_files, const char *files[], const char *destination, bool show)
  176 +{
  177 + return PlotDetection(QtUtils::toStringList(num_files, files), destination, show);
  178 +}
  179 +
175 180 bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show)
176 181 {
177 182 return PlotMetadata(QtUtils::toStringList(num_files, files), columns, show);
... ...
openbr/openbr.h
... ... @@ -146,9 +146,8 @@ BR_EXPORT float br_eval(const char *simmat, const char *mask, const char *csv =
146 146  
147 147 /*!
148 148 * \brief Evaluates and prints classification accuracy to terminal.
149   - * \param predicted_input The predicted br::Gallery.
150   - * \param truth_input The ground truth br::Gallery.
151   - * \see br_enroll
  149 + * \param predicted_gallery The predicted br::Gallery.
  150 + * \param truth_gallery The ground truth br::Gallery.
152 151 */
153 152 BR_EXPORT void br_eval_classification(const char *predicted_gallery, const char *truth_gallery);
154 153  
... ... @@ -163,16 +162,16 @@ BR_EXPORT void br_eval_clustering(const char *csv, const char *gallery);
163 162 /*!
164 163 * \brief Evaluates and prints detection accuracy to terminal.
165 164 * \param predicted_gallery The predicted br::Gallery.
166   - * \param truth_galery The ground truth br::Gallery.
167   - * \see br_enroll
  165 + * \param truth_gallery The ground truth br::Gallery.
  166 + * \param csv Optional \c .csv file to contain performance metrics.
  167 + * \return Average detection bounding box overlap.
168 168 */
169   -BR_EXPORT void br_eval_detection(const char *predicted_gallery, const char *truth_gallery);
  169 +BR_EXPORT float br_eval_detection(const char *predicted_gallery, const char *truth_gallery, const char *csv = "");
170 170  
171 171 /*!
172 172 * \brief Evaluates regression accuracy to disk.
173   - * \param predicted_input The predicted br::Gallery.
174   - * \param truth_input The ground truth br::Gallery.
175   - * \see br_enroll
  173 + * \param predicted_gallery The predicted br::Gallery.
  174 + * \param truth_gallery The ground truth br::Gallery.
176 175 */
177 176 BR_EXPORT void br_eval_regression(const char *predicted_gallery, const char *truth_gallery);
178 177  
... ... @@ -241,7 +240,7 @@ BR_EXPORT const char *br_most_recent_message();
241 240 BR_EXPORT const char *br_objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true);
242 241  
243 242 /*!
244   - * \brief Renders performance figures for a set of <tt>.csv</tt> files.
  243 + * \brief Renders recognition performance figures for a set of <tt>.csv</tt> files created by \ref br_eval.
245 244 *
246 245 * In order of their output, the figures are:
247 246 * -# Metadata table
... ... @@ -263,11 +262,17 @@ BR_EXPORT const char *br_objects(const char *abstractions = &quot;.*&quot;, const char *im
263 262 * \return Returns \c true on success. Returns false on a failure to compile the figures due to a missing, out of date, or incomplete \c R installation.
264 263 * \note This function requires a current <a href="http://www.r-project.org/">R</a> installation with the following packages:
265 264 * \code install.packages(c("ggplot2", "gplots", "reshape", "scales")) \endcode
266   - * \see br_plot_metadata
  265 + * \see br_eval
267 266 */
268 267 BR_EXPORT bool br_plot(int num_files, const char *files[], const char *destination, bool show = false);
269 268  
270 269 /*!
  270 + * \brief Renders detection performance figures for a set of <tt>.csv</tt> files created by \ref br_eval_detection.
  271 + * \see br_plot
  272 + */
  273 +BR_EXPORT bool br_plot_detection(int num_files, const char *files[], const char *destination, bool show = false);
  274 +
  275 +/*!
271 276 * \brief Renders metadata figures for a set of <tt>.csv</tt> files with specified columns.
272 277 *
273 278 * Several files will be created:
... ...
openbr/openbr_export.cpp
... ... @@ -17,7 +17,7 @@
17 17 /*!
18 18 * \mainpage
19 19 * \section overview Overview
20   - * OpenBR \cite openbr is a framework for investigating new modalities, improving existing algorithms, interfacing with commercial systems, measuring recognition performance, and deploying automated biometric systems.
  20 + * OpenBR \cite klontz2013open is a framework for investigating new modalities, improving existing algorithms, interfacing with commercial systems, measuring recognition performance, and deploying automated biometric systems.
21 21 * The project is designed to facilitate rapid algorithm prototyping, and features a mature core framework, flexible plugin system, and support for open and closed source development.
22 22 * Off-the-shelf algorithms are also available for specific modalities including \ref cpp_face_recognition, \ref cpp_age_estimation, and \ref cpp_gender_estimation.
23 23 *
... ... @@ -27,14 +27,24 @@
27 27 * \image html "abstraction.svg" "The two principal software artifacts are the shared library 'openbr' and command line application 'br'."
28 28 *
29 29 * \section get_started Get Started
30   - * - \ref installation - \copybrief installation
31   - * - \ref qmake_integration - \copybrief qmake_integration
  30 + * - \ref introduction - A high-level technical overview of OpenBR.
  31 + * - \ref installation - A hacker's guide to building, editing, and running OpenBR.
  32 + * - \ref qmake_integration - Add OpenBR to your Qt <tt>.pro</tt> project.
32 33 *
33 34 * \section learn_more Learn More
34   - * - \ref algorithm_grammar - \copybrief algorithm_grammar
35   - * - \ref cli - \copybrief cli
36   - * - \ref c_sdk - \copybrief c_sdk
37   - * - \ref cpp_plugin_sdk - \copybrief cpp_plugin_sdk
  35 + * - \ref algorithm_grammar - How algorithms are constructed from string descriptions.
  36 + * - \ref cli - Command line wrapper of the \ref c_sdk.
  37 + * - \ref c_sdk - High-level API for running algorithms and evaluating results.
  38 + * - \ref cpp_plugin_sdk - Plugin API for extending OpenBR functionality.
  39 + * - \ref bee - A <a href="http://www.nist.gov/index.html">NIST</a> standard for evaluating biometric algorithms.
  40 + */
  41 +
  42 +/*!
  43 + * \page introduction Introduction
  44 + * \brief A high-level technical overview of OpenBR.
  45 + *
  46 + * We strongly encourage users new to OpenBR to read our <a href="www.openbiometrics.org/publications/klontz2013open.pdf"><b>publication</b></a> for an introduction to the core concepts.
  47 + * Researchers incorporating OpenBR into their own work are kindly requested to cite this paper.
38 48 */
39 49  
40 50 /*!
... ...
openbr/openbr_plugin.h
... ... @@ -354,7 +354,7 @@ struct Template : public QList&lt;cv::Mat&gt;
354 354 inline const cv::Mat &m() const { static const cv::Mat NullMatrix;
355 355 return isEmpty() ? qFatal("Empty template."), NullMatrix : last(); } /*!< \brief Idiom to treat the template as a matrix. */
356 356 inline cv::Mat &m() { return isEmpty() ? append(cv::Mat()), last() : last(); } /*!< \brief Idiom to treat the template as a matrix. */
357   - inline const File &operator()() const { return file; }
  357 + inline operator const File &() const { return file; }
358 358 inline cv::Mat &operator=(const cv::Mat &other) { return m() = other; } /*!< \brief Idiom to treat the template as a matrix. */
359 359 inline operator const cv::Mat&() const { return m(); } /*!< \brief Idiom to treat the template as a matrix. */
360 360 inline operator cv::Mat&() { return m(); } /*!< \brief Idiom to treat the template as a matrix. */
... ...
openbr/plugins/frames.cpp 0 โ†’ 100644
  1 +#include "openbr_internal.h"
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Passes along n sequential frames to the next transform.
  9 + * \author Josh Klontz \cite jklontz
  10 + *
  11 + * For a video with m frames, AggregateFrames would create a total of m-n+1 sequences ([0,n] ... [m-n+1, m]).
  12 + */
  13 +class AggregateFrames : public TimeVaryingTransform
  14 +{
  15 + Q_OBJECT
  16 + Q_PROPERTY(int n READ get_n WRITE set_n RESET reset_n STORED false)
  17 + BR_PROPERTY(int, n, 1)
  18 +
  19 + TemplateList buffer;
  20 +
  21 + void train(const TemplateList &data)
  22 + {
  23 + (void) data;
  24 + }
  25 +
  26 + void projectUpdate(const Template &src, Template &dst)
  27 + {
  28 + buffer.append(src);
  29 + if (buffer.size() < n) return;
  30 + foreach (const Template &t, buffer) dst.append(t);
  31 + dst.file = buffer.takeFirst().file;
  32 + }
  33 +
  34 + void store(QDataStream &stream) const
  35 + {
  36 + (void) stream;
  37 + }
  38 +
  39 + void load(QDataStream &stream)
  40 + {
  41 + (void) stream;
  42 + }
  43 +};
  44 +
  45 +BR_REGISTER(Transform, AggregateFrames)
  46 +
  47 +} // namespace br
  48 +
  49 +#include "frames.moc"
... ...
openbr/plugins/gallery.cpp
... ... @@ -269,67 +269,6 @@ class matrixGallery : public Gallery
269 269 BR_REGISTER(Gallery, matrixGallery)
270 270  
271 271 /*!
272   - * \ingroup galleries
273   - * \brief Treat a video as a gallery, making a single template from each frame
274   - * \author Charles Otto \cite caotto
275   - */
276   -class aviGallery : public Gallery
277   -{
278   - Q_OBJECT
279   -
280   - TemplateList output_set;
281   - QScopedPointer<cv::VideoWriter> videoOut;
282   -
283   - ~aviGallery()
284   - {
285   - if (videoOut && videoOut->isOpened()) videoOut->release();
286   - }
287   -
288   - TemplateList readBlock(bool * done)
289   - {
290   - std::string fname = file.name.toStdString();
291   - *done = true;
292   -
293   - TemplateList output;
294   - if (!file.exists())
295   - return output;
296   -
297   - cv::VideoCapture videoReader(file.name.toStdString());
298   -
299   - bool open = videoReader.isOpened();
300   -
301   - while (open) {
302   - cv::Mat frame;
303   -
304   - open = videoReader.read(frame);
305   - if (!open) break;
306   - output.append(Template());
307   - output.back() = frame.clone();
308   - }
309   -
310   - return TemplateList();
311   - }
312   -
313   - void write(const Template & t)
314   - {
315   - if (videoOut.isNull() || !videoOut->isOpened()) {
316   - int fourcc = OpenCVUtils::getFourcc();
317   - videoOut.reset(new cv::VideoWriter(qPrintable(file.name), fourcc, 30, t.m().size()));
318   - }
319   -
320   - if (!videoOut->isOpened()) {
321   - qWarning("Failed to open %s for writing\n", qPrintable(file.name));
322   - return;
323   - }
324   -
325   - foreach(const cv::Mat & m, t) {
326   - videoOut->write(m);
327   - }
328   - }
329   -};
330   -BR_REGISTER(Gallery, aviGallery)
331   -
332   -/*!
333 272 * \ingroup initializers
334 273 * \brief Initialization support for memGallery.
335 274 * \author Josh Klontz \cite jklontz
... ...
openbr/plugins/stream.cpp
... ... @@ -284,8 +284,11 @@ public:
284 284 {
285 285 qDebug("Video not open!");
286 286 }
  287 + } else {
  288 + // Yes, we should specify absolute path:
  289 + // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python
  290 + video.open(QFileInfo(input.file.name).absoluteFilePath().toStdString());
287 291 }
288   - else video.open(input.file.name.toStdString());
289 292  
290 293 return video.isOpened();
291 294 }
... ...
scripts/downloadDatasets.sh
... ... @@ -63,4 +63,6 @@ if [ ! -d ../data/KTH/vid ]; then
63 63 unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass}
64 64 rm ${vidclass}.zip
65 65 done
  66 + # this file is corrupted
  67 + rm ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi
66 68 fi
... ...
share/openbr/Doxyfile.in
1   -# Doxyfile 1.8.2
  1 +# Doxyfile 1.8.4
2 2  
3 3 # This file describes the settings to be used by the documentation system
4 4 # doxygen (www.doxygen.org) for a project.
5 5 #
  6 +# All text after a double hash (##) is considered a comment and is placed
  7 +# in front of the TAG it is preceding .
6 8 # All text after a hash (#) is considered a comment and will be ignored.
7 9 # The format is:
8 10 # TAG = value [value, ...]
... ... @@ -70,9 +72,9 @@ CREATE_SUBDIRS = NO
70 72 # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
71 73 # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
72 74 # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
73   -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
74   -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
75   -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
  75 +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian,
  76 +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic,
  77 +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
76 78  
77 79 OUTPUT_LANGUAGE = English
78 80  
... ... @@ -252,10 +254,10 @@ EXTENSION_MAPPING =
252 254  
253 255 MARKDOWN_SUPPORT = YES
254 256  
255   -# When enabled doxygen tries to link words that correspond to documented classes,
256   -# or namespaces to their corresponding documentation. Such a link can be
257   -# prevented in individual cases by by putting a % sign in front of the word or
258   -# globally by setting AUTOLINK_SUPPORT to NO.
  257 +# When enabled doxygen tries to link words that correspond to documented
  258 +# classes, or namespaces to their corresponding documentation. Such a link can
  259 +# be prevented in individual cases by by putting a % sign in front of the word
  260 +# or globally by setting AUTOLINK_SUPPORT to NO.
259 261  
260 262 AUTOLINK_SUPPORT = YES
261 263  
... ... @@ -279,7 +281,12 @@ CPP_CLI_SUPPORT = NO
279 281  
280 282 SIP_SUPPORT = NO
281 283  
282   -# For Microsoft's IDL there are propget and propput attributes to indicate getter and setter methods for a property. Setting this option to YES (the default) will make doxygen replace the get and set methods by a property in the documentation. This will only work if the methods are indeed getting or setting a simple type. If this is not the case, or you want to show the methods anyway, you should set this option to NO.
  284 +# For Microsoft's IDL there are propget and propput attributes to indicate
  285 +# getter and setter methods for a property. Setting this option to YES (the
  286 +# default) will make doxygen replace the get and set methods by a property in
  287 +# the documentation. This will only work if the methods are indeed getting or
  288 +# setting a simple type. If this is not the case, or you want to show the
  289 +# methods anyway, you should set this option to NO.
283 290  
284 291 IDL_PROPERTY_SUPPORT = YES
285 292  
... ... @@ -306,11 +313,11 @@ SUBGROUPING = YES
306 313 INLINE_GROUPED_CLASSES = NO
307 314  
308 315 # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
309   -# unions with only public data fields will be shown inline in the documentation
310   -# of the scope in which they are defined (i.e. file, namespace, or group
311   -# documentation), provided this scope is documented. If set to NO (the default),
312   -# structs, classes, and unions are shown on a separate page (for HTML and Man
313   -# pages) or section (for LaTeX and RTF).
  316 +# unions with only public data fields or simple typedef fields will be shown
  317 +# inline in the documentation of the scope in which they are defined (i.e. file,
  318 +# namespace, or group documentation), provided this scope is documented. If set
  319 +# to NO (the default), structs, classes, and unions are shown on a separate
  320 +# page (for HTML and Man pages) or section (for LaTeX and RTF).
314 321  
315 322 INLINE_SIMPLE_STRUCTS = NO
316 323  
... ... @@ -324,30 +331,14 @@ INLINE_SIMPLE_STRUCTS = NO
324 331  
325 332 TYPEDEF_HIDES_STRUCT = NO
326 333  
327   -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
328   -# determine which symbols to keep in memory and which to flush to disk.
329   -# When the cache is full, less often used symbols will be written to disk.
330   -# For small to medium size projects (<1000 input files) the default value is
331   -# probably good enough. For larger projects a too small cache size can cause
332   -# doxygen to be busy swapping symbols to and from disk most of the time
333   -# causing a significant performance penalty.
334   -# If the system has enough physical memory increasing the cache will improve the
335   -# performance by keeping more symbols in memory. Note that the value works on
336   -# a logarithmic scale so increasing the size by one will roughly double the
337   -# memory usage. The cache size is given by this formula:
338   -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
339   -# corresponding to a cache size of 2^16 = 65536 symbols.
340   -
341   -SYMBOL_CACHE_SIZE = 0
342   -
343   -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
344   -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
345   -# their name and scope. Since this can be an expensive process and often the
346   -# same symbol appear multiple times in the code, doxygen keeps a cache of
347   -# pre-resolved symbols. If the cache is too small doxygen will become slower.
348   -# If the cache is too large, memory is wasted. The cache size is given by this
349   -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
350   -# corresponding to a cache size of 2^16 = 65536 symbols.
  334 +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
  335 +# cache is used to resolve symbols given their name and scope. Since this can
  336 +# be an expensive process and often the same symbol appear multiple times in
  337 +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too
  338 +# small doxygen will become slower. If the cache is too large, memory is wasted.
  339 +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid
  340 +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536
  341 +# symbols.
351 342  
352 343 LOOKUP_CACHE_SIZE = 0
353 344  
... ... @@ -358,7 +349,7 @@ LOOKUP_CACHE_SIZE = 0
358 349 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
359 350 # documentation are documented, even if no documentation was available.
360 351 # Private class members and static file members will be hidden unless
361   -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
  352 +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
362 353  
363 354 EXTRACT_ALL = YES
364 355  
... ... @@ -539,7 +530,8 @@ GENERATE_BUGLIST = YES
539 530 GENERATE_DEPRECATEDLIST= YES
540 531  
541 532 # The ENABLED_SECTIONS tag can be used to enable conditional
542   -# documentation sections, marked by \if sectionname ... \endif.
  533 +# documentation sections, marked by \if section-label ... \endif
  534 +# and \cond section-label ... \endcond blocks.
543 535  
544 536 ENABLED_SECTIONS =
545 537  
... ... @@ -597,7 +589,8 @@ LAYOUT_FILE =
597 589 # requires the bibtex tool to be installed. See also
598 590 # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
599 591 # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
600   -# feature you need bibtex and perl available in the search path.
  592 +# feature you need bibtex and perl available in the search path. Do not use
  593 +# file names with spaces, bibtex cannot handle them.
601 594  
602 595 CITE_BIB_FILES = ${BR_SHARE_DIR}/openbr.bib
603 596  
... ... @@ -680,7 +673,8 @@ INPUT_ENCODING = UTF-8
680 673 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
681 674 # *.f90 *.f *.for *.vhd *.vhdl
682 675  
683   -FILE_PATTERNS = *.h *.cpp
  676 +FILE_PATTERNS = *.h \
  677 + *.cpp
684 678  
685 679 # The RECURSIVE tag can be used to turn specify whether or not subdirectories
686 680 # should be searched for input files as well. Possible values are YES and NO.
... ... @@ -763,8 +757,10 @@ IMAGE_PATH = ${CMAKE_SOURCE_DIR}/share/openbr
763 757 # is the value of the INPUT_FILTER tag, and <input-file> is the name of an
764 758 # input file. Doxygen will then use the output that the filter program writes
765 759 # to standard output.
766   -# If FILTER_PATTERNS is specified, this tag will be
767   -# ignored.
  760 +# If FILTER_PATTERNS is specified, this tag will be ignored.
  761 +# Note that the filter must not add or remove lines; it is applied before the
  762 +# code is scanned, but not when the output code is generated. If lines are added
  763 +# or removed, the anchors will not be placed correctly.
768 764  
769 765 INPUT_FILTER =
770 766  
... ... @@ -793,6 +789,13 @@ FILTER_SOURCE_FILES = NO
793 789  
794 790 FILTER_SOURCE_PATTERNS =
795 791  
  792 +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
  793 +# is part of the input, its contents will be placed on the main page
  794 +# (index.html). This can be useful if you have a project on for instance GitHub
  795 +# and want reuse the introduction page also for the doxygen output.
  796 +
  797 +USE_MDFILE_AS_MAINPAGE =
  798 +
796 799 #---------------------------------------------------------------------------
797 800 # configuration options related to source browsing
798 801 #---------------------------------------------------------------------------
... ... @@ -934,7 +937,7 @@ HTML_EXTRA_STYLESHEET =
934 937 # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
935 938 # other source files which should be copied to the HTML output directory. Note
936 939 # that these files will be copied to the base HTML output directory. Use the
937   -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
  940 +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
938 941 # files. In the HTML_STYLESHEET file, use the file name only. Also note that
939 942 # the files will be copied as-is; there are no commands or markers available.
940 943  
... ... @@ -1202,6 +1205,13 @@ FORMULA_TRANSPARENT = YES
1202 1205  
1203 1206 USE_MATHJAX = NO
1204 1207  
  1208 +# When MathJax is enabled you can set the default output format to be used for
  1209 +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
  1210 +# SVG. The default value is HTML-CSS, which is slower, but has the best
  1211 +# compatibility.
  1212 +
  1213 +MATHJAX_FORMAT = HTML-CSS
  1214 +
1205 1215 # When MathJax is enabled you need to specify the location relative to the
1206 1216 # HTML output directory using the MATHJAX_RELPATH option. The destination
1207 1217 # directory should contain the MathJax.js script. For instance, if the mathjax
... ... @@ -1219,6 +1229,11 @@ MATHJAX_RELPATH = http://www.mathjax.org/mathjax
1219 1229  
1220 1230 MATHJAX_EXTENSIONS =
1221 1231  
  1232 +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
  1233 +# pieces of code that will be used on startup of the MathJax code.
  1234 +
  1235 +MATHJAX_CODEFILE =
  1236 +
1222 1237 # When the SEARCHENGINE tag is enabled doxygen will generate a search box
1223 1238 # for the HTML output. The underlying search engine uses javascript
1224 1239 # and DHTML and should work on any modern browser. Note that when using
... ... @@ -1230,15 +1245,55 @@ MATHJAX_EXTENSIONS =
1230 1245 SEARCHENGINE = YES
1231 1246  
1232 1247 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
1233   -# implemented using a PHP enabled web server instead of at the web client
1234   -# using Javascript. Doxygen will generate the search PHP script and index
1235   -# file to put on the web server. The advantage of the server
1236   -# based approach is that it scales better to large projects and allows
1237   -# full text search. The disadvantages are that it is more difficult to setup
1238   -# and does not have live searching capabilities.
  1248 +# implemented using a web server instead of a web client using Javascript.
  1249 +# There are two flavours of web server based search depending on the
  1250 +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
  1251 +# searching and an index file used by the script. When EXTERNAL_SEARCH is
  1252 +# enabled the indexing and searching needs to be provided by external tools.
  1253 +# See the manual for details.
1239 1254  
1240 1255 SERVER_BASED_SEARCH = NO
1241 1256  
  1257 +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
  1258 +# script for searching. Instead the search results are written to an XML file
  1259 +# which needs to be processed by an external indexer. Doxygen will invoke an
  1260 +# external search engine pointed to by the SEARCHENGINE_URL option to obtain
  1261 +# the search results. Doxygen ships with an example indexer (doxyindexer) and
  1262 +# search engine (doxysearch.cgi) which are based on the open source search
  1263 +# engine library Xapian. See the manual for configuration details.
  1264 +
  1265 +EXTERNAL_SEARCH = NO
  1266 +
  1267 +# The SEARCHENGINE_URL should point to a search engine hosted by a web server
  1268 +# which will returned the search results when EXTERNAL_SEARCH is enabled.
  1269 +# Doxygen ships with an example search engine (doxysearch) which is based on
  1270 +# the open source search engine library Xapian. See the manual for configuration
  1271 +# details.
  1272 +
  1273 +SEARCHENGINE_URL =
  1274 +
  1275 +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
  1276 +# search data is written to a file for indexing by an external tool. With the
  1277 +# SEARCHDATA_FILE tag the name of this file can be specified.
  1278 +
  1279 +SEARCHDATA_FILE = searchdata.xml
  1280 +
  1281 +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
  1282 +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
  1283 +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
  1284 +# projects and redirect the results back to the right project.
  1285 +
  1286 +EXTERNAL_SEARCH_ID =
  1287 +
  1288 +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
  1289 +# projects other than the one defined by this configuration file, but that are
  1290 +# all added to the same external search index. Each project needs to have a
  1291 +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
  1292 +# of to a relative location where the documentation can be found.
  1293 +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
  1294 +
  1295 +EXTRA_SEARCH_MAPPINGS =
  1296 +
1242 1297 #---------------------------------------------------------------------------
1243 1298 # configuration options related to the LaTeX output
1244 1299 #---------------------------------------------------------------------------
... ... @@ -1276,7 +1331,7 @@ COMPACT_LATEX = NO
1276 1331  
1277 1332 # The PAPER_TYPE tag can be used to set the paper type that is used
1278 1333 # by the printer. Possible values are: a4, letter, legal and
1279   -# executive. If left blank a4wide will be used.
  1334 +# executive. If left blank a4 will be used.
1280 1335  
1281 1336 PAPER_TYPE = a4
1282 1337  
... ... @@ -1299,6 +1354,13 @@ LATEX_HEADER =
1299 1354  
1300 1355 LATEX_FOOTER =
1301 1356  
  1357 +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images
  1358 +# or other source files which should be copied to the LaTeX output directory.
  1359 +# Note that the files will be copied as-is; there are no commands or markers
  1360 +# available.
  1361 +
  1362 +LATEX_EXTRA_FILES =
  1363 +
1302 1364 # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
1303 1365 # is prepared for conversion to pdf (using ps2pdf). The pdf file will
1304 1366 # contain links (just like the HTML output) instead of page references
... ... @@ -1444,6 +1506,21 @@ XML_DTD =
1444 1506 XML_PROGRAMLISTING = YES
1445 1507  
1446 1508 #---------------------------------------------------------------------------
  1509 +# configuration options related to the DOCBOOK output
  1510 +#---------------------------------------------------------------------------
  1511 +
  1512 +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files
  1513 +# that can be used to generate PDF.
  1514 +
  1515 +GENERATE_DOCBOOK = NO
  1516 +
  1517 +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put.
  1518 +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
  1519 +# front of it. If left blank docbook will be used as the default path.
  1520 +
  1521 +DOCBOOK_OUTPUT = docbook
  1522 +
  1523 +#---------------------------------------------------------------------------
1447 1524 # configuration options for the AutoGen Definitions output
1448 1525 #---------------------------------------------------------------------------
1449 1526  
... ... @@ -1539,7 +1616,8 @@ INCLUDE_FILE_PATTERNS =
1539 1616 # undefined via #undef or recursively expanded use the := operator
1540 1617 # instead of the = operator.
1541 1618  
1542   -PREDEFINED = BR_EXPORT= __cplusplus
  1619 +PREDEFINED = BR_EXPORT= \
  1620 + __cplusplus
1543 1621  
1544 1622 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
1545 1623 # this tag can be used to specify a list of macro names that should be expanded.
... ... @@ -1592,6 +1670,12 @@ ALLEXTERNALS = NO
1592 1670  
1593 1671 EXTERNAL_GROUPS = YES
1594 1672  
  1673 +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed
  1674 +# in the related pages index. If set to NO, only the current project's
  1675 +# pages will be listed.
  1676 +
  1677 +EXTERNAL_PAGES = YES
  1678 +
1595 1679 # The PERL_PATH should be the absolute path and name of the perl script
1596 1680 # interpreter (i.e. the result of `which perl').
1597 1681  
... ... @@ -1688,7 +1772,7 @@ UML_LOOK = NO
1688 1772 # the class node. If there are many fields or methods and many nodes the
1689 1773 # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
1690 1774 # threshold limits the number of items for each type to make the size more
1691   -# managable. Set this to 0 for no limit. Note that the threshold may be
  1775 +# manageable. Set this to 0 for no limit. Note that the threshold may be
1692 1776 # exceeded by 50% before the limit is enforced.
1693 1777  
1694 1778 UML_LIMIT_NUM_FIELDS = 10
... ...
share/openbr/openbr.bib
... ... @@ -30,16 +30,11 @@
30 30 Title = {ottochar at gmail.com}}
31 31  
32 32 @misc{lbestrowden,
33   - Author = {Lacey S. Best-Rowden},
  33 + Author = {{Lacey S. Best-Rowden}},
34 34 Howpublished = {https://github.com/lbestrowden},
35 35 Title = {bestrow1 at msu.edu}}
36 36  
37 37 % Software
38   -@misc{OpenBR,
39   - Author = {Joshua C. Klontz and Dr. Mark J. Burge},
40   - Title = {{OpenBR} - {Open} {Biometric} {Recognition}},
41   - Year = {2012}}
42   -
43 38 @misc{libface,
44 39 Howpublished = {http://libface.sourceforge.net/file/Home.html},
45 40 Title = {libface},
... ... @@ -227,6 +222,14 @@
227 222 pages={1--8},
228 223 }
229 224  
  225 +@inproceedings{klontz2013open,
  226 + title={{Open Source Biometric Recognition}},
  227 + author={Klontz et al.},
  228 + booktitle={Biometrics: Theory, Applications and Systems (BTAS), 2013 IEEE Sixth International Conference on},
  229 + year={2013},
  230 + organization={IEEE}
  231 +}
  232 +
230 233 @inproceedings{li2009hfb,
231 234 title={The {HFB} face database for heterogeneous face biometrics research},
232 235 author={Li, Stan Z and Lei, Zhen and Ao, Meng},
... ...