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,6 +2,7 @@
2 3rdparty/LatentSDK* 2 3rdparty/LatentSDK*
3 3rdparty/pittpatt* 3 3rdparty/pittpatt*
4 data/*/img 4 data/*/img
  5 +data/*/vid
5 data/PCSO/* 6 data/PCSO/*
6 build* 7 build*
7 scripts/results 8 scripts/results
app/br/br.cpp
@@ -135,11 +135,14 @@ public: @@ -135,11 +135,14 @@ public:
135 check(parc == 2, "Incorrect parameter count for 'evalClustering'."); 135 check(parc == 2, "Incorrect parameter count for 'evalClustering'.");
136 br_eval_clustering(parv[0], parv[1]); 136 br_eval_clustering(parv[0], parv[1]);
137 } else if (!strcmp(fun, "evalDetection")) { 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 } else if (!strcmp(fun, "evalRegression")) { 140 } else if (!strcmp(fun, "evalRegression")) {
141 check(parc == 2, "Incorrect parameter count for 'evalRegression'."); 141 check(parc == 2, "Incorrect parameter count for 'evalRegression'.");
142 br_eval_regression(parv[0], parv[1]); 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 } else if (!strcmp(fun, "plotMetadata")) { 146 } else if (!strcmp(fun, "plotMetadata")) {
144 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); 147 check(parc >= 2, "Incorrect parameter count for 'plotMetadata'.");
145 br_plot_metadata(parc-1, parv, parv[parc-1], true); 148 br_plot_metadata(parc-1, parv, parv[parc-1], true);
@@ -214,8 +217,9 @@ private: @@ -214,8 +217,9 @@ private:
214 "-convert (Format|Gallery|Output) <input_file> {output_file}\n" 217 "-convert (Format|Gallery|Output) <input_file> {output_file}\n"
215 "-evalClassification <predicted_gallery> <truth_gallery>\n" 218 "-evalClassification <predicted_gallery> <truth_gallery>\n"
216 "-evalClustering <clusters> <gallery>\n" 219 "-evalClustering <clusters> <gallery>\n"
217 - "-evalDetection <predicted_gallery> <truth_gallery>\n" 220 + "-evalDetection <predicted_gallery> <truth_gallery> [{csv}]\n"
218 "-evalRegression <predicted_gallery> <truth_gallery>\n" 221 "-evalRegression <predicted_gallery> <truth_gallery>\n"
  222 + "-plotDetection <file> ... <file> {destination}\n"
219 "-plotMetadata <file> ... <file> <columns>\n" 223 "-plotMetadata <file> ... <file> <columns>\n"
220 "-getHeader <matrix>\n" 224 "-getHeader <matrix>\n"
221 "-setHeader {<matrix>} <target_gallery> <query_gallery>\n" 225 "-setHeader {<matrix>} <target_gallery> <query_gallery>\n"
openbr/core/eval.cpp
@@ -23,6 +23,8 @@ using namespace cv; @@ -23,6 +23,8 @@ using namespace cv;
23 namespace br 23 namespace br
24 { 24 {
25 25
  26 +static const int Max_Points = 500; // Maximum number of points to render on plots
  27 +
26 struct Comparison 28 struct Comparison
27 { 29 {
28 float score; 30 float score;
@@ -100,7 +102,6 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv) @@ -100,7 +102,6 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv)
100 qFatal("Similarity matrix (%ix%i) differs in size from mask matrix (%ix%i).", 102 qFatal("Similarity matrix (%ix%i) differs in size from mask matrix (%ix%i).",
101 simmat.rows, simmat.cols, mask.rows, mask.cols); 103 simmat.rows, simmat.cols, mask.rows, mask.cols);
102 104
103 - const int Max_Points = 500;  
104 float result = -1; 105 float result = -1;
105 106
106 // Make comparisons 107 // Make comparisons
@@ -237,7 +238,7 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv) @@ -237,7 +238,7 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv)
237 if (i == Report_Retrieval) reportRetrievalRate = retrievalRate; 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 qDebug("TAR @ FAR = 0.01: %.3f\nRetrieval Rate @ Rank = %d: %.3f", result, Report_Retrieval, reportRetrievalRate); 242 qDebug("TAR @ FAR = 0.01: %.3f\nRetrieval Rate @ Rank = %d: %.3f", result, Report_Retrieval, reportRetrievalRate);
242 return result; 243 return result;
243 } 244 }
@@ -325,7 +326,7 @@ struct Detection @@ -325,7 +326,7 @@ struct Detection
325 float overlap(const Detection &other) const 326 float overlap(const Detection &other) const
326 { 327 {
327 const Detection intersection(boundingBox.intersected(other.boundingBox)); 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,14 +335,53 @@ struct Detections
334 QList<Detection> predicted, truth; 335 QList<Detection> predicted, truth;
335 }; 336 };
336 337
337 -struct DetectionOperatingPoint 338 +struct ResolvedDetection
338 { 339 {
339 float confidence, overlap; 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 float EvalDetection(const QString &predictedInput, const QString &truthInput, const QString &csv) 385 float EvalDetection(const QString &predictedInput, const QString &truthInput, const QString &csv)
346 { 386 {
347 qDebug("Evaluating detection of %s against %s", qPrintable(predictedInput), qPrintable(truthInput)); 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,18 +398,18 @@ float EvalDetection(const QString &amp;predictedInput, const QString &amp;truthInput, co
358 if (detectKey.isNull()) qFatal("No suitable metadata key found."); 398 if (detectKey.isNull()) qFatal("No suitable metadata key found.");
359 else qDebug("Using metadata key: %s", qPrintable(detectKey)); 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 foreach (const Template &t, predicted) 402 foreach (const Template &t, predicted)
363 allDetections[t.file.baseName()].predicted.append(Detection(t.file.get<QRectF>(detectKey), t.file.get<float>("Confidence", -1))); 403 allDetections[t.file.baseName()].predicted.append(Detection(t.file.get<QRectF>(detectKey), t.file.get<float>("Confidence", -1)));
364 foreach (const Template &t, truth) 404 foreach (const Template &t, truth)
365 allDetections[t.file.baseName()].truth.append(Detection(t.file.get<QRectF>(detectKey))); 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 foreach (Detections detections, allDetections.values()) { 408 foreach (Detections detections, allDetections.values()) {
369 while (!detections.truth.isEmpty() && !detections.predicted.isEmpty()) { 409 while (!detections.truth.isEmpty() && !detections.predicted.isEmpty()) {
370 - Detection truth = detections.truth.takeFirst(); 410 + const Detection truth = detections.truth.takeFirst();
371 int bestIndex = -1; 411 int bestIndex = -1;
372 - float bestOverlap = -1; 412 + float bestOverlap = -std::numeric_limits<float>::max();
373 for (int i=0; i<detections.predicted.size(); i++) { 413 for (int i=0; i<detections.predicted.size(); i++) {
374 const float overlap = truth.overlap(detections.predicted[i]); 414 const float overlap = truth.overlap(detections.predicted[i]);
375 if (overlap > bestOverlap) { 415 if (overlap > bestOverlap) {
@@ -377,25 +417,40 @@ float EvalDetection(const QString &amp;predictedInput, const QString &amp;truthInput, co @@ -377,25 +417,40 @@ float EvalDetection(const QString &amp;predictedInput, const QString &amp;truthInput, co
377 bestIndex = i; 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 foreach (const Detection &detection, detections.predicted) 424 foreach (const Detection &detection, detections.predicted)
385 - points.append(DetectionOperatingPoint(detection.confidence, 0)); 425 + resolvedDetections.append(ResolvedDetection(detection.confidence, 0));
386 for (int i=0; i<detections.truth.size(); i++) 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 QStringList lines; 432 QStringList lines;
393 lines.append("Plot, X, Y"); 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 void EvalRegression(const QString &predictedInput, const QString &truthInput) 456 void EvalRegression(const QString &predictedInput, const QString &truthInput)
openbr/core/plot.cpp
@@ -79,7 +79,7 @@ struct RPlot @@ -79,7 +79,7 @@ struct RPlot
79 79
80 Pivot major, minor; 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 if (files.isEmpty()) qFatal("Empty file list."); 84 if (files.isEmpty()) qFatal("Empty file list.");
85 qSort(files.begin(), files.end(), sortFiles); 85 qSort(files.begin(), files.end(), sortFiles);
@@ -214,7 +214,7 @@ struct RPlot @@ -214,7 +214,7 @@ struct RPlot
214 }; 214 };
215 215
216 // Does not work if dataset folder starts with a number 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 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination)); 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,6 +272,15 @@ bool Plot(const QStringList &amp;files, const br::File &amp;destination, bool show)
272 return p.finalize(show); 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 bool PlotMetadata(const QStringList &files, const QString &columns, bool show) 284 bool PlotMetadata(const QStringList &files, const QString &columns, bool show)
276 { 285 {
277 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns)); 286 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns));
openbr/core/plot.h
@@ -24,7 +24,8 @@ @@ -24,7 +24,8 @@
24 24
25 namespace br 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 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false); 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,6 +105,7 @@ void QtUtils::writeFile(const QString &amp;file, const QString &amp;data)
105 105
106 void QtUtils::writeFile(const QString &file, const QByteArray &data, int compression) 106 void QtUtils::writeFile(const QString &file, const QByteArray &data, int compression)
107 { 107 {
  108 + if (file.isEmpty()) return;
108 const QString baseName = QFileInfo(file).baseName(); 109 const QString baseName = QFileInfo(file).baseName();
109 const QByteArray contents = (compression == 0) ? data : qCompress(data, compression); 110 const QByteArray contents = (compression == 0) ? data : qCompress(data, compression);
110 if (baseName == "terminal") { 111 if (baseName == "terminal") {
openbr/openbr.cpp
@@ -82,9 +82,9 @@ void br_eval_clustering(const char *csv, const char *gallery) @@ -82,9 +82,9 @@ void br_eval_clustering(const char *csv, const char *gallery)
82 EvalClustering(csv, gallery); 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 void br_eval_regression(const char *predicted_gallery, const char *truth_gallery) 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,6 +172,11 @@ bool br_plot(int num_files, const char *files[], const char *destination, bool s
172 return Plot(QtUtils::toStringList(num_files, files), destination, show); 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 bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show) 180 bool br_plot_metadata(int num_files, const char *files[], const char *columns, bool show)
176 { 181 {
177 return PlotMetadata(QtUtils::toStringList(num_files, files), columns, show); 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,9 +146,8 @@ BR_EXPORT float br_eval(const char *simmat, const char *mask, const char *csv =
146 146
147 /*! 147 /*!
148 * \brief Evaluates and prints classification accuracy to terminal. 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 BR_EXPORT void br_eval_classification(const char *predicted_gallery, const char *truth_gallery); 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,16 +162,16 @@ BR_EXPORT void br_eval_clustering(const char *csv, const char *gallery);
163 /*! 162 /*!
164 * \brief Evaluates and prints detection accuracy to terminal. 163 * \brief Evaluates and prints detection accuracy to terminal.
165 * \param predicted_gallery The predicted br::Gallery. 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 * \brief Evaluates regression accuracy to disk. 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 BR_EXPORT void br_eval_regression(const char *predicted_gallery, const char *truth_gallery); 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,7 +240,7 @@ BR_EXPORT const char *br_most_recent_message();
241 BR_EXPORT const char *br_objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true); 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 * In order of their output, the figures are: 245 * In order of their output, the figures are:
247 * -# Metadata table 246 * -# Metadata table
@@ -263,11 +262,17 @@ BR_EXPORT const char *br_objects(const char *abstractions = &quot;.*&quot;, const char *im @@ -263,11 +262,17 @@ BR_EXPORT const char *br_objects(const char *abstractions = &quot;.*&quot;, const char *im
263 * \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. 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 * \note This function requires a current <a href="http://www.r-project.org/">R</a> installation with the following packages: 263 * \note This function requires a current <a href="http://www.r-project.org/">R</a> installation with the following packages:
265 * \code install.packages(c("ggplot2", "gplots", "reshape", "scales")) \endcode 264 * \code install.packages(c("ggplot2", "gplots", "reshape", "scales")) \endcode
266 - * \see br_plot_metadata 265 + * \see br_eval
267 */ 266 */
268 BR_EXPORT bool br_plot(int num_files, const char *files[], const char *destination, bool show = false); 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 * \brief Renders metadata figures for a set of <tt>.csv</tt> files with specified columns. 276 * \brief Renders metadata figures for a set of <tt>.csv</tt> files with specified columns.
272 * 277 *
273 * Several files will be created: 278 * Several files will be created:
openbr/openbr_export.cpp
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 /*! 17 /*!
18 * \mainpage 18 * \mainpage
19 * \section overview Overview 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 * 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. 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 * Off-the-shelf algorithms are also available for specific modalities including \ref cpp_face_recognition, \ref cpp_age_estimation, and \ref cpp_gender_estimation. 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,14 +27,24 @@
27 * \image html "abstraction.svg" "The two principal software artifacts are the shared library 'openbr' and command line application 'br'." 27 * \image html "abstraction.svg" "The two principal software artifacts are the shared library 'openbr' and command line application 'br'."
28 * 28 *
29 * \section get_started Get Started 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 * \section learn_more Learn More 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,7 +354,7 @@ struct Template : public QList&lt;cv::Mat&gt;
354 inline const cv::Mat &m() const { static const cv::Mat NullMatrix; 354 inline const cv::Mat &m() const { static const cv::Mat NullMatrix;
355 return isEmpty() ? qFatal("Empty template."), NullMatrix : last(); } /*!< \brief Idiom to treat the template as a matrix. */ 355 return isEmpty() ? qFatal("Empty template."), NullMatrix : last(); } /*!< \brief Idiom to treat the template as a matrix. */
356 inline cv::Mat &m() { return isEmpty() ? append(cv::Mat()), last() : last(); } /*!< \brief Idiom to treat the template as a matrix. */ 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 inline cv::Mat &operator=(const cv::Mat &other) { return m() = other; } /*!< \brief Idiom to treat the template as a matrix. */ 358 inline cv::Mat &operator=(const cv::Mat &other) { return m() = other; } /*!< \brief Idiom to treat the template as a matrix. */
359 inline operator const cv::Mat&() const { return m(); } /*!< \brief Idiom to treat the template as a matrix. */ 359 inline operator const cv::Mat&() const { return m(); } /*!< \brief Idiom to treat the template as a matrix. */
360 inline operator cv::Mat&() { return m(); } /*!< \brief Idiom to treat the template as a matrix. */ 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,67 +269,6 @@ class matrixGallery : public Gallery
269 BR_REGISTER(Gallery, matrixGallery) 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 * \ingroup initializers 272 * \ingroup initializers
334 * \brief Initialization support for memGallery. 273 * \brief Initialization support for memGallery.
335 * \author Josh Klontz \cite jklontz 274 * \author Josh Klontz \cite jklontz
openbr/plugins/stream.cpp
@@ -284,8 +284,11 @@ public: @@ -284,8 +284,11 @@ public:
284 { 284 {
285 qDebug("Video not open!"); 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 return video.isOpened(); 293 return video.isOpened();
291 } 294 }
scripts/downloadDatasets.sh
@@ -63,4 +63,6 @@ if [ ! -d ../data/KTH/vid ]; then @@ -63,4 +63,6 @@ if [ ! -d ../data/KTH/vid ]; then
63 unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass} 63 unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass}
64 rm ${vidclass}.zip 64 rm ${vidclass}.zip
65 done 65 done
  66 + # this file is corrupted
  67 + rm ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi
66 fi 68 fi
share/openbr/Doxyfile.in
1 -# Doxyfile 1.8.2 1 +# Doxyfile 1.8.4
2 2
3 # This file describes the settings to be used by the documentation system 3 # This file describes the settings to be used by the documentation system
4 # doxygen (www.doxygen.org) for a project. 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 # All text after a hash (#) is considered a comment and will be ignored. 8 # All text after a hash (#) is considered a comment and will be ignored.
7 # The format is: 9 # The format is:
8 # TAG = value [value, ...] 10 # TAG = value [value, ...]
@@ -70,9 +72,9 @@ CREATE_SUBDIRS = NO @@ -70,9 +72,9 @@ CREATE_SUBDIRS = NO
70 # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 72 # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
71 # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 73 # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
72 # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 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 OUTPUT_LANGUAGE = English 79 OUTPUT_LANGUAGE = English
78 80
@@ -252,10 +254,10 @@ EXTENSION_MAPPING = @@ -252,10 +254,10 @@ EXTENSION_MAPPING =
252 254
253 MARKDOWN_SUPPORT = YES 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 AUTOLINK_SUPPORT = YES 262 AUTOLINK_SUPPORT = YES
261 263
@@ -279,7 +281,12 @@ CPP_CLI_SUPPORT = NO @@ -279,7 +281,12 @@ CPP_CLI_SUPPORT = NO
279 281
280 SIP_SUPPORT = NO 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 IDL_PROPERTY_SUPPORT = YES 291 IDL_PROPERTY_SUPPORT = YES
285 292
@@ -306,11 +313,11 @@ SUBGROUPING = YES @@ -306,11 +313,11 @@ SUBGROUPING = YES
306 INLINE_GROUPED_CLASSES = NO 313 INLINE_GROUPED_CLASSES = NO
307 314
308 # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 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 INLINE_SIMPLE_STRUCTS = NO 322 INLINE_SIMPLE_STRUCTS = NO
316 323
@@ -324,30 +331,14 @@ INLINE_SIMPLE_STRUCTS = NO @@ -324,30 +331,14 @@ INLINE_SIMPLE_STRUCTS = NO
324 331
325 TYPEDEF_HIDES_STRUCT = NO 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 LOOKUP_CACHE_SIZE = 0 343 LOOKUP_CACHE_SIZE = 0
353 344
@@ -358,7 +349,7 @@ LOOKUP_CACHE_SIZE = 0 @@ -358,7 +349,7 @@ LOOKUP_CACHE_SIZE = 0
358 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 349 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
359 # documentation are documented, even if no documentation was available. 350 # documentation are documented, even if no documentation was available.
360 # Private class members and static file members will be hidden unless 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 EXTRACT_ALL = YES 354 EXTRACT_ALL = YES
364 355
@@ -539,7 +530,8 @@ GENERATE_BUGLIST = YES @@ -539,7 +530,8 @@ GENERATE_BUGLIST = YES
539 GENERATE_DEPRECATEDLIST= YES 530 GENERATE_DEPRECATEDLIST= YES
540 531
541 # The ENABLED_SECTIONS tag can be used to enable conditional 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 ENABLED_SECTIONS = 536 ENABLED_SECTIONS =
545 537
@@ -597,7 +589,8 @@ LAYOUT_FILE = @@ -597,7 +589,8 @@ LAYOUT_FILE =
597 # requires the bibtex tool to be installed. See also 589 # requires the bibtex tool to be installed. See also
598 # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 590 # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
599 # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 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 CITE_BIB_FILES = ${BR_SHARE_DIR}/openbr.bib 595 CITE_BIB_FILES = ${BR_SHARE_DIR}/openbr.bib
603 596
@@ -680,7 +673,8 @@ INPUT_ENCODING = UTF-8 @@ -680,7 +673,8 @@ INPUT_ENCODING = UTF-8
680 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 673 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
681 # *.f90 *.f *.for *.vhd *.vhdl 674 # *.f90 *.f *.for *.vhd *.vhdl
682 675
683 -FILE_PATTERNS = *.h *.cpp 676 +FILE_PATTERNS = *.h \
  677 + *.cpp
684 678
685 # The RECURSIVE tag can be used to turn specify whether or not subdirectories 679 # The RECURSIVE tag can be used to turn specify whether or not subdirectories
686 # should be searched for input files as well. Possible values are YES and NO. 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,8 +757,10 @@ IMAGE_PATH = ${CMAKE_SOURCE_DIR}/share/openbr
763 # is the value of the INPUT_FILTER tag, and <input-file> is the name of an 757 # is the value of the INPUT_FILTER tag, and <input-file> is the name of an
764 # input file. Doxygen will then use the output that the filter program writes 758 # input file. Doxygen will then use the output that the filter program writes
765 # to standard output. 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 INPUT_FILTER = 765 INPUT_FILTER =
770 766
@@ -793,6 +789,13 @@ FILTER_SOURCE_FILES = NO @@ -793,6 +789,13 @@ FILTER_SOURCE_FILES = NO
793 789
794 FILTER_SOURCE_PATTERNS = 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 # configuration options related to source browsing 800 # configuration options related to source browsing
798 #--------------------------------------------------------------------------- 801 #---------------------------------------------------------------------------
@@ -934,7 +937,7 @@ HTML_EXTRA_STYLESHEET = @@ -934,7 +937,7 @@ HTML_EXTRA_STYLESHEET =
934 # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 937 # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
935 # other source files which should be copied to the HTML output directory. Note 938 # other source files which should be copied to the HTML output directory. Note
936 # that these files will be copied to the base HTML output directory. Use the 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 # files. In the HTML_STYLESHEET file, use the file name only. Also note that 941 # files. In the HTML_STYLESHEET file, use the file name only. Also note that
939 # the files will be copied as-is; there are no commands or markers available. 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,6 +1205,13 @@ FORMULA_TRANSPARENT = YES
1202 1205
1203 USE_MATHJAX = NO 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 # When MathJax is enabled you need to specify the location relative to the 1215 # When MathJax is enabled you need to specify the location relative to the
1206 # HTML output directory using the MATHJAX_RELPATH option. The destination 1216 # HTML output directory using the MATHJAX_RELPATH option. The destination
1207 # directory should contain the MathJax.js script. For instance, if the mathjax 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,6 +1229,11 @@ MATHJAX_RELPATH = http://www.mathjax.org/mathjax
1219 1229
1220 MATHJAX_EXTENSIONS = 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 # When the SEARCHENGINE tag is enabled doxygen will generate a search box 1237 # When the SEARCHENGINE tag is enabled doxygen will generate a search box
1223 # for the HTML output. The underlying search engine uses javascript 1238 # for the HTML output. The underlying search engine uses javascript
1224 # and DHTML and should work on any modern browser. Note that when using 1239 # and DHTML and should work on any modern browser. Note that when using
@@ -1230,15 +1245,55 @@ MATHJAX_EXTENSIONS = @@ -1230,15 +1245,55 @@ MATHJAX_EXTENSIONS =
1230 SEARCHENGINE = YES 1245 SEARCHENGINE = YES
1231 1246
1232 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be 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 SERVER_BASED_SEARCH = NO 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 # configuration options related to the LaTeX output 1298 # configuration options related to the LaTeX output
1244 #--------------------------------------------------------------------------- 1299 #---------------------------------------------------------------------------
@@ -1276,7 +1331,7 @@ COMPACT_LATEX = NO @@ -1276,7 +1331,7 @@ COMPACT_LATEX = NO
1276 1331
1277 # The PAPER_TYPE tag can be used to set the paper type that is used 1332 # The PAPER_TYPE tag can be used to set the paper type that is used
1278 # by the printer. Possible values are: a4, letter, legal and 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 PAPER_TYPE = a4 1336 PAPER_TYPE = a4
1282 1337
@@ -1299,6 +1354,13 @@ LATEX_HEADER = @@ -1299,6 +1354,13 @@ LATEX_HEADER =
1299 1354
1300 LATEX_FOOTER = 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 # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 1364 # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
1303 # is prepared for conversion to pdf (using ps2pdf). The pdf file will 1365 # is prepared for conversion to pdf (using ps2pdf). The pdf file will
1304 # contain links (just like the HTML output) instead of page references 1366 # contain links (just like the HTML output) instead of page references
@@ -1444,6 +1506,21 @@ XML_DTD = @@ -1444,6 +1506,21 @@ XML_DTD =
1444 XML_PROGRAMLISTING = YES 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 # configuration options for the AutoGen Definitions output 1524 # configuration options for the AutoGen Definitions output
1448 #--------------------------------------------------------------------------- 1525 #---------------------------------------------------------------------------
1449 1526
@@ -1539,7 +1616,8 @@ INCLUDE_FILE_PATTERNS = @@ -1539,7 +1616,8 @@ INCLUDE_FILE_PATTERNS =
1539 # undefined via #undef or recursively expanded use the := operator 1616 # undefined via #undef or recursively expanded use the := operator
1540 # instead of the = operator. 1617 # instead of the = operator.
1541 1618
1542 -PREDEFINED = BR_EXPORT= __cplusplus 1619 +PREDEFINED = BR_EXPORT= \
  1620 + __cplusplus
1543 1621
1544 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 1622 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
1545 # this tag can be used to specify a list of macro names that should be expanded. 1623 # this tag can be used to specify a list of macro names that should be expanded.
@@ -1592,6 +1670,12 @@ ALLEXTERNALS = NO @@ -1592,6 +1670,12 @@ ALLEXTERNALS = NO
1592 1670
1593 EXTERNAL_GROUPS = YES 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 # The PERL_PATH should be the absolute path and name of the perl script 1679 # The PERL_PATH should be the absolute path and name of the perl script
1596 # interpreter (i.e. the result of `which perl'). 1680 # interpreter (i.e. the result of `which perl').
1597 1681
@@ -1688,7 +1772,7 @@ UML_LOOK = NO @@ -1688,7 +1772,7 @@ UML_LOOK = NO
1688 # the class node. If there are many fields or methods and many nodes the 1772 # the class node. If there are many fields or methods and many nodes the
1689 # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 1773 # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
1690 # threshold limits the number of items for each type to make the size more 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 # exceeded by 50% before the limit is enforced. 1776 # exceeded by 50% before the limit is enforced.
1693 1777
1694 UML_LIMIT_NUM_FIELDS = 10 1778 UML_LIMIT_NUM_FIELDS = 10
share/openbr/openbr.bib
@@ -30,16 +30,11 @@ @@ -30,16 +30,11 @@
30 Title = {ottochar at gmail.com}} 30 Title = {ottochar at gmail.com}}
31 31
32 @misc{lbestrowden, 32 @misc{lbestrowden,
33 - Author = {Lacey S. Best-Rowden}, 33 + Author = {{Lacey S. Best-Rowden}},
34 Howpublished = {https://github.com/lbestrowden}, 34 Howpublished = {https://github.com/lbestrowden},
35 Title = {bestrow1 at msu.edu}} 35 Title = {bestrow1 at msu.edu}}
36 36
37 % Software 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 @misc{libface, 38 @misc{libface,
44 Howpublished = {http://libface.sourceforge.net/file/Home.html}, 39 Howpublished = {http://libface.sourceforge.net/file/Home.html},
45 Title = {libface}, 40 Title = {libface},
@@ -227,6 +222,14 @@ @@ -227,6 +222,14 @@
227 pages={1--8}, 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 @inproceedings{li2009hfb, 233 @inproceedings{li2009hfb,
231 title={The {HFB} face database for heterogeneous face biometrics research}, 234 title={The {HFB} face database for heterogeneous face biometrics research},
232 author={Li, Stan Z and Lei, Zhen and Ao, Meng}, 235 author={Li, Stan Z and Lei, Zhen and Ao, Meng},