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