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