Commit d61c72e9f96b5ba3d4e2ed30e6f6b8ffff1968d5
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; |