Commit d61c72e9f96b5ba3d4e2ed30e6f6b8ffff1968d5

Authored by Josh Klontz
2 parents 83943217 89b9823b

Merge pull request #182 from biometrics/evalDetection

generalized -evalDetection
Showing 1 changed file with 64 additions and 42 deletions
openbr/core/eval.cpp
@@ -433,84 +433,106 @@ static QStringList computeDetectionResults(const QList<ResolvedDetection> &detec @@ -433,84 +433,106 @@ static QStringList computeDetectionResults(const QList<ResolvedDetection> &detec
433 return lines; 433 return lines;
434 } 434 }
435 435
436 -QString getDetectKey(const TemplateList &templates) 436 +struct DetectionKey : public QString
437 { 437 {
438 - const File &f = templates.first().file;  
439 - foreach (const QString &key, f.localKeys()) {  
440 - // first check for single detections 438 + enum Type {
  439 + Invalid,
  440 + Rect,
  441 + RectList,
  442 + XYWidthHeight
  443 + } type;
  444 +
  445 + DetectionKey(const QString &key = "", Type type = Invalid)
  446 + : QString(key), type(type) {}
  447 +};
  448 +
  449 +static DetectionKey getDetectKey(const FileList &files)
  450 +{
  451 + if (files.empty())
  452 + return DetectionKey();
  453 +
  454 + const File &f = files.first();
  455 + const QStringList localKeys = f.localKeys();
  456 +
  457 + // first check for single detections
  458 + foreach (const QString &key, localKeys)
441 if (!f.get<QRectF>(key, QRectF()).isNull()) 459 if (!f.get<QRectF>(key, QRectF()).isNull())
442 - return key;  
443 - } 460 + return DetectionKey(key, DetectionKey::Rect);
  461 +
444 // and then multiple 462 // and then multiple
445 if (!f.rects().empty()) 463 if (!f.rects().empty())
446 - return "Rects";  
447 - return "";  
448 -} 464 + return DetectionKey("Rects", DetectionKey::RectList);
449 465
450 -bool detectKeyIsList(QString key, const TemplateList &templates)  
451 -{  
452 - return templates.first().file.get<QRectF>(key, QRectF()).isNull(); 466 + // check for <Key>_X, <Key>_Y, <Key>_Width, <Key>_Height
  467 + foreach (const QString &localKey, localKeys) {
  468 + if (!localKey.endsWith("_X"))
  469 + continue;
  470 + const QString key = localKey.mid(0, localKey.size()-2);
  471 + if (localKeys.contains(key+"_Y") &&
  472 + localKeys.contains(key+"_Width") &&
  473 + localKeys.contains(key+"_Height"))
  474 + return DetectionKey(key, DetectionKey::XYWidthHeight);
  475 + }
  476 +
  477 + return DetectionKey();
453 } 478 }
454 479
455 -// return a list of detections whether the template holds  
456 -// multiple detections or a single detection  
457 -QList<Detection> getDetections(QString key, const Template &t, bool isList, bool isTruth) 480 +// return a list of detections independent of the detection key format
  481 +static QList<Detection> getDetections(const DetectionKey &key, const File &f, bool isTruth)
458 { 482 {
459 - File f = t.file;  
460 QList<Detection> dets; 483 QList<Detection> dets;
461 - if (isList) { 484 + if (key.type == DetectionKey::RectList) {
462 QList<QRectF> rects = f.rects(); 485 QList<QRectF> rects = f.rects();
463 QList<float> confidences = f.getList<float>("Confidences", QList<float>()); 486 QList<float> confidences = f.getList<float>("Confidences", QList<float>());
464 if (!isTruth && rects.size() != confidences.size()) 487 if (!isTruth && rects.size() != confidences.size())
465 qFatal("You don't have enough confidence. I mean, your detections don't all have confidence measures."); 488 qFatal("You don't have enough confidence. I mean, your detections don't all have confidence measures.");
466 for (int i=0; i<rects.size(); i++) { 489 for (int i=0; i<rects.size(); i++) {
467 if (isTruth) 490 if (isTruth)
468 - dets.append(Detection(rects.at(i))); 491 + dets.append(Detection(rects[i]));
469 else 492 else
470 - dets.append(Detection(rects.at(i), confidences.at(i))); 493 + dets.append(Detection(rects[i], confidences[i]));
471 } 494 }
472 - } else {  
473 - if (isTruth)  
474 - dets.append(Detection(f.get<QRectF>(key)));  
475 - else  
476 - dets.append(Detection(f.get<QRectF>(key), f.get<float>("Confidence", -1))); 495 + } else if (key.type == DetectionKey::Rect) {
  496 + dets.append(Detection(f.get<QRectF>(key), isTruth ? -1 : f.get<float>("Confidence", -1)));
  497 + } else if (key.type == DetectionKey::XYWidthHeight) {
  498 + const QRectF rect(f.get<float>(key+"_X"), f.get<float>(key+"_Y"), f.get<float>(key+"_Width"), f.get<float>(key+"_Height"));
  499 + dets.append(Detection(rect, isTruth ? -1 : f.get<float>("Confidence", -1)));
477 } 500 }
478 return dets; 501 return dets;
479 } 502 }
480 503
481 -QMap<QString, Detections> getDetections(const TemplateList &predicted, const TemplateList &truth) 504 +static QMap<QString, Detections> getDetections(const File &predictedGallery, const File &truthGallery)
482 { 505 {
  506 + const FileList predicted = TemplateList::fromGallery(predictedGallery).files();
  507 + const FileList truth = TemplateList::fromGallery(truthGallery).files();
  508 +
483 // Figure out which metadata field contains a bounding box 509 // Figure out which metadata field contains a bounding box
484 - QString truthDetectKey = getDetectKey(truth);  
485 - if (truthDetectKey.isEmpty()) qFatal("No suitable ground truth metadata key found.");  
486 - QString predictedDetectKey = getDetectKey(predicted);  
487 - if (predictedDetectKey.isEmpty()) qFatal("No suitable predicted metadata key found."); 510 + DetectionKey truthDetectKey = getDetectKey(truth);
  511 + if (truthDetectKey.isEmpty())
  512 + qFatal("No suitable ground truth metadata key found.");
  513 +
  514 + DetectionKey predictedDetectKey = getDetectKey(predicted);
  515 + if (predictedDetectKey.isEmpty())
  516 + qFatal("No suitable predicted metadata key found.");
  517 +
488 qDebug("Using metadata key: %s%s", 518 qDebug("Using metadata key: %s%s",
489 qPrintable(predictedDetectKey), 519 qPrintable(predictedDetectKey),
490 qPrintable(predictedDetectKey == truthDetectKey ? QString() : "/"+truthDetectKey)); 520 qPrintable(predictedDetectKey == truthDetectKey ? QString() : "/"+truthDetectKey));
491 521
492 QMap<QString, Detections> allDetections; 522 QMap<QString, Detections> allDetections;
493 - bool predKeyIsList = detectKeyIsList(predictedDetectKey, predicted);  
494 - bool truthKeyIsList = detectKeyIsList(truthDetectKey, truth);  
495 - foreach (const Template &t, predicted) {  
496 - QList<Detection> dets = getDetections(predictedDetectKey, t, predKeyIsList, false);  
497 - allDetections[t.file.baseName()].predicted.append(dets);  
498 - }  
499 - foreach (const Template &t, truth) {  
500 - QList<Detection> dets = getDetections(truthDetectKey, t, truthKeyIsList, true);  
501 - allDetections[t.file.baseName()].truth.append(dets);  
502 - } 523 + foreach (const File &f, predicted)
  524 + allDetections[f.baseName()].predicted.append(getDetections(predictedDetectKey, f, false));
  525 + foreach (const File &f, truth)
  526 + allDetections[f.baseName()].truth.append(getDetections(truthDetectKey, f, true));
503 return allDetections; 527 return allDetections;
504 } 528 }
505 529
506 float EvalDetection(const QString &predictedGallery, const QString &truthGallery, const QString &csv) 530 float EvalDetection(const QString &predictedGallery, const QString &truthGallery, const QString &csv)
507 { 531 {
508 qDebug("Evaluating detection of %s against %s", qPrintable(predictedGallery), qPrintable(truthGallery)); 532 qDebug("Evaluating detection of %s against %s", qPrintable(predictedGallery), qPrintable(truthGallery));
509 - const TemplateList predicted(TemplateList::fromGallery(predictedGallery));  
510 - const TemplateList truth(TemplateList::fromGallery(truthGallery));  
511 533
512 // Organized by file, QMap used to preserve order 534 // Organized by file, QMap used to preserve order
513 - QMap<QString, Detections> allDetections = getDetections(predicted, truth); 535 + QMap<QString, Detections> allDetections = getDetections(predictedGallery, truthGallery);
514 536
515 QList<ResolvedDetection> resolvedDetections, falseNegativeDetections; 537 QList<ResolvedDetection> resolvedDetections, falseNegativeDetections;
516 int totalTrueDetections = 0; 538 int totalTrueDetections = 0;