Commit ef44eed775ac606bc8d28aa5b883c091c06324d7
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
16 changed files
with
340 additions
and
169 deletions
.gitignore
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 &simmat, const Mat &mask, const QString &csv) | @@ -100,7 +102,6 @@ float Evaluate(const Mat &simmat, const Mat &mask, const QString &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 &simmat, const Mat &mask, const QString &csv) | @@ -237,7 +238,7 @@ float Evaluate(const Mat &simmat, const Mat &mask, const QString &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 &predictedInput, const QString &truthInput, co | @@ -358,18 +398,18 @@ float EvalDetection(const QString &predictedInput, const QString &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 &predictedInput, const QString &truthInput, co | @@ -377,25 +417,40 @@ float EvalDetection(const QString &predictedInput, const QString &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 &files, const br::File &destination, bool show) | @@ -272,6 +272,15 @@ bool Plot(const QStringList &files, const br::File &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 &file, const QString &data) | @@ -105,6 +105,7 @@ void QtUtils::writeFile(const QString &file, const QString &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 = ".*", const char *im | @@ -263,11 +262,17 @@ BR_EXPORT const char *br_objects(const char *abstractions = ".*", 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<cv::Mat> | @@ -354,7 +354,7 @@ struct Template : public QList<cv::Mat> | ||
| 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}, |