Commit 82cb3e55ed88f58ae3cf17604b24b3134dfb664c

Authored by M Taborsky
2 parents bff4b06d 973ce6bf

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

sdk/core/bee.cpp
@@ -225,64 +225,6 @@ void BEE::writeMask(const Mat &m, const QString &mask, const QString &targetSigs @@ -225,64 +225,6 @@ void BEE::writeMask(const Mat &m, const QString &mask, const QString &targetSigs
225 writeMatrix<Mask_t>(m, mask, targetSigset, querySigset); 225 writeMatrix<Mask_t>(m, mask, targetSigset, querySigset);
226 } 226 }
227 227
228 -template <typename T>  
229 -void matrixToCSV(const QString &matrix, const QString &csv)  
230 -{  
231 - qDebug("Converting %s to %s", qPrintable(matrix), qPrintable(csv));  
232 -  
233 - QFile out(csv);  
234 - out.open(QFile::WriteOnly);  
235 -  
236 - Mat m = readMatrix<T>(matrix);  
237 - for (int i=0; i<m.rows; i++) {  
238 - for (int j=0; j<m.cols; j++) {  
239 - out.write(qPrintable(QString::number(m.at<T>(i,j))));  
240 - out.write(",");  
241 - }  
242 - out.write("\n");  
243 - }  
244 -}  
245 -  
246 -void BEE::simmatToCSV(const QString &simmat, const QString &csv)  
247 -{  
248 - matrixToCSV<Simmat_t>(simmat, csv);  
249 -}  
250 -  
251 -void BEE::maskToCSV(const QString &mask, const QString &csv)  
252 -{  
253 - matrixToCSV<Mask_t>(mask, csv);  
254 -}  
255 -  
256 -template <typename T>  
257 -void CSVToMatrix(const QString &csv, const QString &matrix)  
258 -{  
259 - qDebug("Converting %s to %s", qPrintable(csv), qPrintable(matrix));  
260 -  
261 - QStringList lines = QtUtils::readLines(csv);  
262 - Mat m(lines.size(), lines.first().split(",", QString::SkipEmptyParts).size(), OpenCVType<T,1>::make());  
263 -  
264 - for (int i=0; i<lines.size(); i++) {  
265 - const QStringList &words = lines[i].split(",", QString::SkipEmptyParts);  
266 - for (int j=0; j<words.size(); j++) {  
267 - bool ok;  
268 - m.at<T>(i, j) = words[j].toFloat(&ok);  
269 - if (!ok) qFatal("bee.cpp::CSVToMatrix failed to convert %s to floating point format.", qPrintable(words[j]));  
270 - }  
271 - }  
272 -  
273 - writeMatrix<T>(m, matrix, "Unknown_Target", "Unknown_Query");  
274 -}  
275 -  
276 -void BEE::CSVToSimmat(const QString &csv, const QString &simmat)  
277 -{  
278 - CSVToMatrix<Simmat_t>(csv, simmat);  
279 -}  
280 -  
281 -void BEE::CSVToMask(const QString &csv, const QString &mask)  
282 -{  
283 - CSVToMatrix<Mask_t>(csv, mask);  
284 -}  
285 -  
286 void BEE::makeMask(const QString &targetInput, const QString &queryInput, const QString &mask) 228 void BEE::makeMask(const QString &targetInput, const QString &queryInput, const QString &mask)
287 { 229 {
288 qDebug("Making mask from %s and %s to %s", qPrintable(targetInput), qPrintable(queryInput), qPrintable(mask)); 230 qDebug("Making mask from %s and %s to %s", qPrintable(targetInput), qPrintable(queryInput), qPrintable(mask));
sdk/core/bee.h
@@ -44,12 +44,6 @@ namespace BEE @@ -44,12 +44,6 @@ namespace BEE
44 void writeSimmat(const cv::Mat &m, const QString &simmat, const QString &targetSigset = "Unknown_Target", const QString &querySigset = "Unknown_Query"); 44 void writeSimmat(const cv::Mat &m, const QString &simmat, const QString &targetSigset = "Unknown_Target", const QString &querySigset = "Unknown_Query");
45 void writeMask(const cv::Mat &m, const QString &mask, const QString &targetSigset = "Unknown_Target", const QString &querySigset = "Unknown_Query"); 45 void writeMask(const cv::Mat &m, const QString &mask, const QString &targetSigset = "Unknown_Target", const QString &querySigset = "Unknown_Query");
46 46
47 - // CSV IO  
48 - void simmatToCSV(const QString &simmat, const QString &csv);  
49 - void maskToCSV(const QString &mask, const QString &csv);  
50 - void CSVToSimmat(const QString &csv, const QString &simmat);  
51 - void CSVToMask(const QString &csv, const QString &mask);  
52 -  
53 // Write BEE files 47 // Write BEE files
54 void makeMask(const QString &targetInput, const QString &queryInput, const QString &mask); 48 void makeMask(const QString &targetInput, const QString &queryInput, const QString &mask);
55 void combineMasks(const QStringList &inputMasks, const QString &outputMask, const QString &method); 49 void combineMasks(const QStringList &inputMasks, const QString &outputMask, const QString &method);
sdk/core/core.cpp
@@ -305,6 +305,13 @@ void br::Compare(const File &amp;targetGallery, const File &amp;queryGallery, const File @@ -305,6 +305,13 @@ void br::Compare(const File &amp;targetGallery, const File &amp;queryGallery, const File
305 AlgorithmManager::getAlgorithm(output.getString("algorithm"))->compare(targetGallery, queryGallery, output); 305 AlgorithmManager::getAlgorithm(output.getString("algorithm"))->compare(targetGallery, queryGallery, output);
306 } 306 }
307 307
  308 +void br::Convert(const File &src, const File &dst)
  309 +{
  310 + QScopedPointer<Format> before(Factory<Format>::make(src));
  311 + QScopedPointer<Format> after(Factory<Format>::make(dst));
  312 + after->write(before->read());
  313 +}
  314 +
308 QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm) 315 QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm)
309 { 316 {
310 return AlgorithmManager::getAlgorithm(algorithm)->transform; 317 return AlgorithmManager::getAlgorithm(algorithm)->transform;
sdk/core/plot.cpp
@@ -29,7 +29,6 @@ @@ -29,7 +29,6 @@
29 #include <QtAlgorithms> 29 #include <QtAlgorithms>
30 #include <opencv2/core/core.hpp> 30 #include <opencv2/core/core.hpp>
31 #include <assert.h> 31 #include <assert.h>
32 -#include <openbr_plugin.h>  
33 32
34 #include "plot.h" 33 #include "plot.h"
35 #include "version.h" 34 #include "version.h"
@@ -40,9 +39,11 @@ @@ -40,9 +39,11 @@
40 #undef FAR // Windows preprecessor definition 39 #undef FAR // Windows preprecessor definition
41 40
42 using namespace cv; 41 using namespace cv;
43 -using namespace br;  
44 42
45 -void br::Confusion(const QString &file, float score, int &true_positives, int &false_positives, int &true_negatives, int &false_negatives) 43 +namespace br
  44 +{
  45 +
  46 +void Confusion(const QString &file, float score, int &true_positives, int &false_positives, int &true_negatives, int &false_negatives)
46 { 47 {
47 qDebug("Computing confusion matrix of %s at %f", qPrintable(file), score); 48 qDebug("Computing confusion matrix of %s at %f", qPrintable(file), score);
48 49
@@ -123,7 +124,7 @@ static float kernelDensityEstimation(const QList&lt;double&gt; &amp;vals, double x, double @@ -123,7 +124,7 @@ static float kernelDensityEstimation(const QList&lt;double&gt; &amp;vals, double x, double
123 return y / (vals.size() * h); 124 return y / (vals.size() * h);
124 } 125 }
125 126
126 -float br::Evaluate(const QString &simmat, const QString &mask, const QString &csv) 127 +float Evaluate(const QString &simmat, const QString &mask, const QString &csv)
127 { 128 {
128 qDebug("Evaluating %s with %s", qPrintable(simmat), qPrintable(mask)); 129 qDebug("Evaluating %s with %s", qPrintable(simmat), qPrintable(mask));
129 130
@@ -294,11 +295,21 @@ struct RPlot @@ -294,11 +295,21 @@ struct RPlot
294 QFile file; 295 QFile file;
295 QStringList pivotHeaders; 296 QStringList pivotHeaders;
296 QVector< QSet<QString> > pivotItems; 297 QVector< QSet<QString> > pivotItems;
297 - int majorIndex, minorIndex, majorSize, minorSize;  
298 - QString majorHeader, minorHeader;  
299 bool flip; 298 bool flip;
300 299
301 - RPlot(QStringList files, const QString &destination, bool isEvalFormat = true) 300 + struct Pivot
  301 + {
  302 + int index, size;
  303 + QString header;
  304 + bool smooth;
  305 + Pivot() : index(-1), size(0), smooth(false) {}
  306 + Pivot(int _index, int _size, const QString &_header)
  307 + : index(_index), size(_size), header(_header), smooth(false) {}
  308 + };
  309 +
  310 + Pivot major, minor;
  311 +
  312 + RPlot(QStringList files, const br::File &destination, bool isEvalFormat = true)
302 { 313 {
303 if (files.isEmpty()) qFatal("RPlot::RPlot() empty file list."); 314 if (files.isEmpty()) qFatal("RPlot::RPlot() empty file list.");
304 qSort(files.begin(), files.end(), sortFiles); 315 qSort(files.begin(), files.end(), sortFiles);
@@ -388,23 +399,25 @@ struct RPlot @@ -388,23 +399,25 @@ struct RPlot
388 file.write("\n" 399 file.write("\n"
389 "# Write figures\n"); 400 "# Write figures\n");
390 401
391 - majorIndex = -1, minorIndex = -1, majorSize = 0, minorSize = 0;  
392 for (int i=0; i<pivotItems.size(); i++) { 402 for (int i=0; i<pivotItems.size(); i++) {
393 const int size = pivotItems[i].size(); 403 const int size = pivotItems[i].size();
394 - if (size > majorSize) {  
395 - minorIndex = majorIndex;  
396 - minorSize = majorSize;  
397 - majorIndex = i;  
398 - majorSize = size;  
399 - } else if (size > minorSize) {  
400 - minorIndex = i;  
401 - minorSize = size; 404 + if (size > major.size) {
  405 + minor = major;
  406 + major = Pivot(i, size, pivotHeaders[i]);
  407 + } else if (size > minor.size) {
  408 + minor = Pivot(i, size, pivotHeaders[i]);
402 } 409 }
403 } 410 }
404 411
405 - if (majorIndex != -1) majorHeader = pivotHeaders[majorIndex];  
406 - if (minorIndex != -1) minorHeader = pivotHeaders[minorIndex];  
407 - flip = minorHeader == "Algorithm"; 412 + const QString &smooth = destination.getString("smooth", "");
  413 + major.smooth = !smooth.isEmpty() && (major.header == smooth);
  414 + minor.smooth = !smooth.isEmpty() && (minor.header == smooth);
  415 + if (major.smooth) major.size = 1;
  416 + if (minor.smooth) minor.size = 1;
  417 + if (major.size < minor.size)
  418 + std::swap(major, minor);
  419 +
  420 + flip = minor.header == "Algorithm";
408 } 421 }
409 422
410 bool finalize(bool show = false) 423 bool finalize(bool show = false)
@@ -424,74 +437,76 @@ struct RPlot @@ -424,74 +437,76 @@ struct RPlot
424 } 437 }
425 }; 438 };
426 439
427 -bool br::Plot(const QStringList &files, const QString &destination, bool show) 440 +bool Plot(const QStringList &files, const br::File &destination, bool show)
428 { 441 {
429 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination)); 442 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination));
430 443
431 RPlot p(files, destination); 444 RPlot p(files, destination);
432 445
433 - p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"line\"") +  
434 - (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) +  
435 - (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + 446 + p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"%1\"").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  447 + (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
  448 + (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
436 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") + 449 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") +
437 - (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) +  
438 - (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + 450 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
  451 + (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
439 QString(" + scale_x_log10() + scale_y_continuous(labels=percent)") + 452 QString(" + scale_x_log10() + scale_y_continuous(labels=percent)") +
440 QString("\nggsave(\"%1\")\n").arg(p.subfile("ROC")))); 453 QString("\nggsave(\"%1\")\n").arg(p.subfile("ROC"))));
441 454
442 - p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"line\"") +  
443 - (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) +  
444 - (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + 455 + p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"%1\"").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  456 + (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
  457 + (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
445 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") + 458 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") +
446 - (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) +  
447 - (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + 459 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
  460 + (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
448 QString(" + scale_x_log10() + scale_y_log10()") + 461 QString(" + scale_x_log10() + scale_y_log10()") +
449 QString("\nggsave(\"%1\")\n").arg(p.subfile("DET")))); 462 QString("\nggsave(\"%1\")\n").arg(p.subfile("DET"))));
450 463
451 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") + 464 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") +
452 - QString(", xlab=\"Score%1\"").arg((p.flip ? p.majorSize : p.minorSize) > 1 ? " / " + (p.flip ? p.majorHeader : p.minorHeader) : QString()) +  
453 - QString(", ylab=\"Frequency%1\"").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) + 465 + QString(", xlab=\"Score%1\"").arg((p.flip ? p.major.size : p.minor.size) > 1 ? " / " + (p.flip ? p.major.header : p.minor.header) : QString()) +
  466 + QString(", ylab=\"Frequency%1\"").arg((p.flip ? p.minor.size : p.major.size) > 1 ? " / " + (p.flip ? p.minor.header : p.major.header) : QString()) +
454 QString(") + scale_fill_manual(\"Ground Truth\", values=c(\"blue\", \"red\")) + theme_minimal() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + theme(axis.text.y=element_blank(), axis.ticks=element_blank(), axis.text.x=element_text(angle=-90, hjust=0))") + 467 QString(") + scale_fill_manual(\"Ground Truth\", values=c(\"blue\", \"red\")) + theme_minimal() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + theme(axis.text.y=element_blank(), axis.ticks=element_blank(), axis.text.x=element_text(angle=-90, hjust=0))") +
455 - (p.majorSize > 1 ? (p.minorSize > 1 ? QString(" + facet_grid(%2 ~ %1, scales=\"free\")").arg((p.flip ? p.majorHeader : p.minorHeader), (p.flip ? p.minorHeader : p.majorHeader)) : QString(" + facet_wrap(~ %1, scales = \"free\")").arg(p.majorHeader)) : QString()) + 468 + (p.major.size > 1 ? (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ %1, scales=\"free\")").arg((p.flip ? p.major.header : p.minor.header), (p.flip ? p.minor.header : p.major.header)) : QString(" + facet_wrap(~ %1, scales = \"free\")").arg(p.major.header)) : QString()) +
456 QString(" + theme(aspect.ratio=1)") + 469 QString(" + theme(aspect.ratio=1)") +
457 QString("\nggsave(\"%1\")\n").arg(p.subfile("SD")))); 470 QString("\nggsave(\"%1\")\n").arg(p.subfile("SD"))));
458 471
459 - p.file.write(qPrintable(QString("qplot(X, Y, data=CMC, geom=\"line\", xlab=\"Rank\", ylab=\"Retrieval Rate\"") +  
460 - (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) +  
461 - (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) + 472 + p.file.write(qPrintable(QString("qplot(X, Y, data=CMC, geom=\"%1\", xlab=\"Rank\", ylab=\"Retrieval Rate\"").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  473 + (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
  474 + (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
462 QString(") + theme_minimal() + scale_x_continuous(limits = c(1,25), breaks = c(1,5,10,25))") + 475 QString(") + theme_minimal() + scale_x_continuous(limits = c(1,25), breaks = c(1,5,10,25))") +
463 - (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) +  
464 - (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) + 476 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
  477 + (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
465 QString(" + scale_y_continuous(labels=percent)") + 478 QString(" + scale_y_continuous(labels=percent)") +
466 QString("\nggsave(\"%1\")\n").arg(p.subfile("CMC")))); 479 QString("\nggsave(\"%1\")\n").arg(p.subfile("CMC"))));
467 480
468 - p.file.write(qPrintable(QString("qplot(factor(%1), data=BC, geom=\"bar\", position=\"dodge\", weight=Y").arg(p.majorHeader) +  
469 - (p.majorSize > 1 ? QString(", fill=factor(%1)").arg(p.majorHeader) : QString()) +  
470 - QString(", xlab=\"%1False Accept Rate\"").arg(p.majorSize > 1 ? p.majorHeader + " / " : QString()) +  
471 - QString(", ylab=\"True Accept Rate%1\") + theme_minimal()").arg(p.minorSize > 1 ? " / " + p.minorHeader : QString()) +  
472 - (p.majorSize > 1 ? getScale("fill", p.majorHeader, p.majorSize) : QString()) +  
473 - (p.minorSize > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minorHeader) : QString(" + facet_wrap(~ X)")) +  
474 - QString(" + scale_y_continuous(labels=percent) + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0)) + geom_text(data=BC, aes(label=Y, y=0.05))") + 481 + p.file.write(qPrintable(QString("qplot(factor(%1)%2, data=BC, %3").arg(p.major.header, (p.major.smooth || p.minor.smooth) ? ", Y" : "", (p.major.smooth || p.minor.smooth) ? "geom=\"boxplot\"" : "geom=\"bar\", position=\"dodge\", weight=Y") +
  482 + (p.major.size > 1 ? QString(", fill=factor(%1)").arg(p.major.header) : QString()) +
  483 + QString(", xlab=\"%1False Accept Rate\"").arg(p.major.size > 1 ? p.major.header + " / " : QString()) +
  484 + QString(", ylab=\"True Accept Rate%1\") + theme_minimal()").arg(p.minor.size > 1 ? " / " + p.minor.header : QString()) +
  485 + (p.major.size > 1 ? getScale("fill", p.major.header, p.major.size) : QString()) +
  486 + (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minor.header) : QString(" + facet_wrap(~ X)")) +
  487 + QString(" + scale_y_continuous(labels=percent) + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0))%1").arg((p.major.smooth || p.minor.smooth) ? "" : " + geom_text(data=BC, aes(label=Y, y=0.05))") +
475 QString("\nggsave(\"%1\")\n").arg(p.subfile("BC")))); 488 QString("\nggsave(\"%1\")\n").arg(p.subfile("BC"))));
476 489
477 - p.file.write(qPrintable(QString("qplot(X, Y, data=ERR, geom=\"line\", linetype=Error") +  
478 - ((p.flip ? p.majorSize : p.minorSize) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.majorHeader : p.minorHeader) : QString()) +  
479 - QString(", xlab=\"Score%1\", ylab=\"Error Rate\") + theme_minimal()").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) +  
480 - ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) + 490 + p.file.write(qPrintable(QString("qplot(X, Y, data=ERR, geom=\"%1\", linetype=Error").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  491 + ((p.flip ? p.major.size : p.minor.size) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.major.header : p.minor.header) : QString()) +
  492 + QString(", xlab=\"Score%1\", ylab=\"Error Rate\") + theme_minimal()").arg((p.flip ? p.minor.size : p.major.size) > 1 ? " / " + (p.flip ? p.minor.header : p.major.header) : QString()) +
  493 + ((p.flip ? p.major.size : p.minor.size) > 1 ? getScale("colour", p.flip ? p.major.header : p.minor.header, p.flip ? p.major.size : p.minor.size) : QString()) +
481 QString(" + scale_y_log10()") + 494 QString(" + scale_y_log10()") +
482 - ((p.flip ? p.minorSize : p.majorSize) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minorHeader : p.majorHeader) : QString()) + 495 + ((p.flip ? p.minor.size : p.major.size) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minor.header : p.major.header) : QString()) +
483 QString(" + theme(aspect.ratio=1)") + 496 QString(" + theme(aspect.ratio=1)") +
484 QString("\nggsave(\"%1\")\n").arg(p.subfile("ERR")))); 497 QString("\nggsave(\"%1\")\n").arg(p.subfile("ERR"))));
485 498
486 return p.finalize(show); 499 return p.finalize(show);
487 } 500 }
488 501
489 -bool br::PlotMetadata(const QStringList &files, const QString &columns, bool show) 502 +bool PlotMetadata(const QStringList &files, const QString &columns, bool show)
490 { 503 {
491 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns)); 504 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns));
492 505
493 RPlot p(files, "PlotMetadata", false); 506 RPlot p(files, "PlotMetadata", false);
494 foreach (const QString &column, columns.split(";")) 507 foreach (const QString &column, columns.split(";"))
495 - p.file.write(qPrintable(QString("qplot(%1, %2, data=data, geom=\"violin\", fill=%1) + coord_flip() + theme_minimal()\nggsave(\"%2.pdf\")\n").arg(p.majorHeader, column))); 508 + p.file.write(qPrintable(QString("qplot(%1, %2, data=data, geom=\"violin\", fill=%1) + coord_flip() + theme_minimal()\nggsave(\"%2.pdf\")\n").arg(p.major.header, column)));
496 return p.finalize(show); 509 return p.finalize(show);
497 } 510 }
  511 +
  512 +} // namespace br
sdk/core/plot.h
@@ -20,13 +20,14 @@ @@ -20,13 +20,14 @@
20 #include <QPair> 20 #include <QPair>
21 #include <QString> 21 #include <QString>
22 #include <QVector> 22 #include <QVector>
  23 +#include <openbr_plugin.h>
23 24
24 namespace br 25 namespace br
25 { 26 {
26 27
27 void Confusion(const QString &file, float score, int &true_positives, int &false_positives, int &true_negatives, int &false_negatives); 28 void Confusion(const QString &file, float score, int &true_positives, int &false_positives, int &true_negatives, int &false_negatives);
28 float Evaluate(const QString &simmat, const QString &mask, const QString &csv = ""); // Returns TAR @ FAR = 0.01 29 float Evaluate(const QString &simmat, const QString &mask, const QString &csv = ""); // Returns TAR @ FAR = 0.01
29 -bool Plot(const QStringList &files, const QString &destination, bool show = false); 30 +bool Plot(const QStringList &files, const br::File &destination, bool show = false);
30 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false); 31 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false);
31 32
32 } 33 }
sdk/openbr.cpp
@@ -51,17 +51,9 @@ void br_confusion(const char *file, float score, int *true_positives, int *false @@ -51,17 +51,9 @@ void br_confusion(const char *file, float score, int *true_positives, int *false
51 return Confusion(file, score, *true_positives, *false_positives, *true_negatives, *false_negatives); 51 return Confusion(file, score, *true_positives, *false_positives, *true_negatives, *false_negatives);
52 } 52 }
53 53
54 -void br_convert(const char *input_matrix, const char *output_matrix)  
55 -{  
56 - QString inputSuffix = QFileInfo(input_matrix).suffix();  
57 - QString outputSuffix = QFileInfo(output_matrix).suffix();  
58 - if (inputSuffix == "csv") {  
59 - if (outputSuffix == "mtx") BEE::CSVToSimmat(input_matrix, output_matrix);  
60 - else BEE::CSVToMask(input_matrix, output_matrix);  
61 - } else {  
62 - if (inputSuffix == "mtx") BEE::simmatToCSV(input_matrix, output_matrix);  
63 - else BEE::maskToCSV(input_matrix, output_matrix);  
64 - } 54 +void br_convert(const char *input, const char *output)
  55 +{
  56 + Convert(File(input), File(output));
65 } 57 }
66 58
67 void br_enroll(const char *input, const char *gallery) 59 void br_enroll(const char *input, const char *gallery)
sdk/openbr.h
@@ -123,11 +123,9 @@ BR_EXPORT void br_confusion(const char *file, float score, @@ -123,11 +123,9 @@ BR_EXPORT void br_confusion(const char *file, float score,
123 int *true_positives, int *false_positives, int *true_negatives, int *false_negatives); 123 int *true_positives, int *false_positives, int *true_negatives, int *false_negatives);
124 124
125 /*! 125 /*!
126 - * \brief Converts a <i>.csv</i> file to/from a \ref simmat or \ref mask.  
127 - * \param input_matrix The input matrix.  
128 - * \param output_matrix The output matrix. 126 + * \brief Wraps br::Convert()
129 */ 127 */
130 -BR_EXPORT void br_convert(const char *input_matrix, const char *output_matrix); 128 +BR_EXPORT void br_convert(const char *input, const char *output);
131 129
132 /*! 130 /*!
133 * \brief Constructs template(s) from an input. 131 * \brief Constructs template(s) from an input.
sdk/openbr_plugin.h
@@ -845,6 +845,7 @@ class BR_EXPORT Format : public Object @@ -845,6 +845,7 @@ class BR_EXPORT Format : public Object
845 public: 845 public:
846 virtual ~Format() {} 846 virtual ~Format() {}
847 virtual Template read() const = 0; /*!< \brief Returns a br::Template created by reading #br::Object::file. */ 847 virtual Template read() const = 0; /*!< \brief Returns a br::Template created by reading #br::Object::file. */
  848 + virtual void write(const Template &t) const = 0; /*!< \brief Writes the br::Template to #br::Object::file. */
848 }; 849 };
849 850
850 /*! 851 /*!
@@ -1079,6 +1080,13 @@ BR_EXPORT FileList Enroll(const File &amp;input, const File &amp;gallery = File()); @@ -1079,6 +1080,13 @@ BR_EXPORT FileList Enroll(const File &amp;input, const File &amp;gallery = File());
1079 */ 1080 */
1080 BR_EXPORT void Compare(const File &targetGallery, const File &queryGallery, const File &output); 1081 BR_EXPORT void Compare(const File &targetGallery, const File &queryGallery, const File &output);
1081 1082
  1083 +/*!
  1084 + * \brief To convert between matrix/template formats.
  1085 + * \param input The input matrix or template.
  1086 + * \param output The output matrix or template.
  1087 + */
  1088 +BR_EXPORT void Convert(const File &input, const File &output);
  1089 +
1082 /*! @}*/ 1090 /*! @}*/
1083 1091
1084 } // namespace br 1092 } // namespace br
sdk/plugins/format.cpp
@@ -23,6 +23,10 @@ @@ -23,6 +23,10 @@
23 #include <opencv2/highgui/highgui.hpp> 23 #include <opencv2/highgui/highgui.hpp>
24 #include <openbr_plugin.h> 24 #include <openbr_plugin.h>
25 25
  26 +#include "core/bee.h"
  27 +#include "core/opencvutils.h"
  28 +#include "core/qtutils.h"
  29 +
26 using namespace br; 30 using namespace br;
27 using namespace cv; 31 using namespace cv;
28 32
@@ -42,12 +46,15 @@ class csvFormat : public Format @@ -42,12 +46,15 @@ class csvFormat : public Format
42 QStringList lines(QString(f.readAll()).split('\n')); 46 QStringList lines(QString(f.readAll()).split('\n'));
43 f.close(); 47 f.close();
44 48
  49 + bool isUChar = true;
45 QList< QList<float> > valsList; 50 QList< QList<float> > valsList;
46 foreach (const QString &line, lines) { 51 foreach (const QString &line, lines) {
47 QList<float> vals; 52 QList<float> vals;
48 foreach (const QString &word, line.split(QRegExp(" *, *"))) { 53 foreach (const QString &word, line.split(QRegExp(" *, *"))) {
49 bool ok; 54 bool ok;
50 - vals.append(word.toFloat(&ok)); assert(ok); 55 + const float val = word.toFloat(&ok);
  56 + vals.append(val);
  57 + isUChar = isUChar && (val == float(uchar(val)));
51 } 58 }
52 valsList.append(vals); 59 valsList.append(vals);
53 } 60 }
@@ -61,8 +68,26 @@ class csvFormat : public Format @@ -61,8 +68,26 @@ class csvFormat : public Format
61 } 68 }
62 } 69 }
63 70
  71 + if (isUChar) m.convertTo(m, CV_8U);
64 return Template(m); 72 return Template(m);
65 } 73 }
  74 +
  75 + void write(const Template &t) const
  76 + {
  77 + const Mat &m = t.m();
  78 + if (t.size() != 1) qFatal("csvFormat::write only supports single matrix templates.");
  79 + if (m.channels() != 1) qFatal("csvFormat::write only supports single channel matrices.");
  80 +
  81 + QStringList lines; lines.reserve(m.rows);
  82 + for (int r=0; r<m.rows; r++) {
  83 + QStringList elements; elements.reserve(m.cols);
  84 + for (int c=0; c<m.cols; c++)
  85 + elements.append(OpenCVUtils::elemToString(m, r, c));
  86 + lines.append(elements.join(","));
  87 + }
  88 +
  89 + QtUtils::writeFile(file, lines);
  90 + }
66 }; 91 };
67 92
68 BR_REGISTER(Format, csvFormat) 93 BR_REGISTER(Format, csvFormat)
@@ -105,12 +130,61 @@ class DefaultFormat : public Format @@ -105,12 +130,61 @@ class DefaultFormat : public Format
105 130
106 return t; 131 return t;
107 } 132 }
  133 +
  134 + void write(const Template &t) const
  135 + {
  136 + imwrite(file.name.toStdString(), t);
  137 + }
108 }; 138 };
109 139
110 BR_REGISTER(Format, DefaultFormat) 140 BR_REGISTER(Format, DefaultFormat)
111 141
112 /*! 142 /*!
113 * \ingroup formats 143 * \ingroup formats
  144 + * \brief Reads a NIST BEE similarity matrix.
  145 + * \author Josh Klontz \cite jklontz
  146 + */
  147 +class mtxFormat : public Format
  148 +{
  149 + Q_OBJECT
  150 +
  151 + Template read() const
  152 + {
  153 + return BEE::readSimmat(file);
  154 + }
  155 +
  156 + void write(const Template &t) const
  157 + {
  158 + BEE::writeSimmat(t, file);
  159 + }
  160 +};
  161 +
  162 +BR_REGISTER(Format, mtxFormat)
  163 +
  164 +/*!
  165 + * \ingroup formats
  166 + * \brief Reads a NIST BEE mask matrix.
  167 + * \author Josh Klontz \cite jklontz
  168 + */
  169 +class maskFormat : public Format
  170 +{
  171 + Q_OBJECT
  172 +
  173 + Template read() const
  174 + {
  175 + return BEE::readMask(file);
  176 + }
  177 +
  178 + void write(const Template &t) const
  179 + {
  180 + BEE::writeMask(t, file);
  181 + }
  182 +};
  183 +
  184 +BR_REGISTER(Format, maskFormat)
  185 +
  186 +/*!
  187 + * \ingroup formats
114 * \brief Retrieves an image from a webcam. 188 * \brief Retrieves an image from a webcam.
115 * \author Josh Klontz \cite jklontz 189 * \author Josh Klontz \cite jklontz
116 */ 190 */
@@ -129,6 +203,12 @@ class webcamFormat : public Format @@ -129,6 +203,12 @@ class webcamFormat : public Format
129 videoCapture->read(m); 203 videoCapture->read(m);
130 return Template(m); 204 return Template(m);
131 } 205 }
  206 +
  207 + void write(const Template &t) const
  208 + {
  209 + (void) t;
  210 + qFatal("webcamFormat::write not supported.");
  211 + }
132 }; 212 };
133 213
134 BR_REGISTER(Format, webcamFormat) 214 BR_REGISTER(Format, webcamFormat)
@@ -191,6 +271,12 @@ class xmlFormat : public Format @@ -191,6 +271,12 @@ class xmlFormat : public Format
191 271
192 return t; 272 return t;
193 } 273 }
  274 +
  275 + void write(const Template &t) const
  276 + {
  277 + (void) t;
  278 + qFatal("xmlFormat::write not supported.");
  279 + }
194 }; 280 };
195 281
196 BR_REGISTER(Format, xmlFormat) 282 BR_REGISTER(Format, xmlFormat)