Commit d1dee8c220ab52498e4e78ec749139caccc112e2

Authored by Scott Klum
2 parents 2f4fffed 4c9bff3e

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

CMakeLists.txt
... ... @@ -19,9 +19,11 @@ set(PACKAGE_YEAR 2013)
19 19  
20 20 if(${CMAKE_VERSION} VERSION_EQUAL 2.8.11)
21 21 cmake_policy(SET CMP0020 OLD)
  22 + cmake_policy(SET CMP0022 OLD)
22 23 endif()
23 24 if(${CMAKE_VERSION} VERSION_GREATER 2.8.11)
24 25 cmake_policy(SET CMP0020 OLD)
  26 + cmake_policy(SET CMP0022 OLD)
25 27 endif()
26 28  
27 29 if(${CMAKE_SIZEOF_VOID_P} MATCHES 8)
... ...
openbr/core/eval.cpp
... ... @@ -394,6 +394,7 @@ static QStringList computeDetectionResults(const QList<ResolvedDetection> &detec
394 394 for (int i=0; i<detections.size(); i++) {
395 395 const ResolvedDetection &detection = detections[i];
396 396 if (discrete) {
  397 + // A 50% overlap is considered a true positive
397 398 if (detection.overlap >= 0.5) TP++;
398 399 else FP++;
399 400 } else {
... ... @@ -507,11 +508,13 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery
507 508 QMap<QString, Detections> allDetections = getDetections(predicted, truth);
508 509  
509 510 QList<ResolvedDetection> resolvedDetections, falseNegativeDetections;
510   - foreach (Detections detections, allDetections.values()) {
  511 + foreach (Detections detections, allDetections.values()) { // For every file
  512 + // Try to associate ground truth detections with predicted detections
511 513 while (!detections.truth.isEmpty() && !detections.predicted.isEmpty()) {
512   - const Detection truth = detections.truth.takeFirst();
  514 + const Detection truth = detections.truth.takeFirst(); // Take removes the detection
513 515 int bestIndex = -1;
514 516 float bestOverlap = -std::numeric_limits<float>::max();
  517 + // Find the nearest predicted detection to this ground truth detection
515 518 for (int i=0; i<detections.predicted.size(); i++) {
516 519 const float overlap = truth.overlap(detections.predicted[i]);
517 520 if (overlap > bestOverlap) {
... ... @@ -519,6 +522,9 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery
519 522 bestIndex = i;
520 523 }
521 524 }
  525 + // Removing the detection prevents us from considering it twice.
  526 + // We don't want to associate two ground truth detections with the
  527 + // same prediction, over vice versa.
522 528 const Detection predicted = detections.predicted.takeAt(bestIndex);
523 529 resolvedDetections.append(ResolvedDetection(predicted.confidence, bestOverlap));
524 530 }
... ...
openbr/plugins/meta.cpp
... ... @@ -717,6 +717,42 @@ public:
717 717 };
718 718 BR_REGISTER(Transform, DistributeTemplateTransform)
719 719  
  720 +/*!
  721 + * \ingroup transforms
  722 + * \brief Filters a gallery based on the value of a metadata field.
  723 + * \author Brendan Klare \cite bklare
  724 + */
  725 +class FilterOnMetadataTransform : public UntrainableMetaTransform
  726 +{
  727 + Q_OBJECT
  728 + Q_PROPERTY(QString attributeName READ get_attributeName WRITE set_attributeName RESET reset_attributeName STORED false)
  729 + Q_PROPERTY(float threshold READ get_threshold WRITE set_threshold RESET reset_threshold STORED false)
  730 + Q_PROPERTY(bool isGreaterThan READ get_isGreaterThan WRITE set_isGreaterThan RESET reset_isGreaterThan STORED false)
  731 + BR_PROPERTY(QString, attributeName, "Confidence")
  732 + BR_PROPERTY(float, threshold, 0)
  733 + BR_PROPERTY(bool, isGreaterThan, true)
  734 +
  735 + void project(const TemplateList &src, TemplateList &dst) const
  736 + {
  737 + QList<Template> filtered;
  738 + foreach (Template t, src) {
  739 + if (!t.file.contains(attributeName))
  740 + continue;
  741 + bool pass = t.file.get<float>(attributeName) > threshold;
  742 + if (isGreaterThan ? pass : !pass)
  743 + filtered.append(t);
  744 + }
  745 + dst = TemplateList(filtered);
  746 + }
  747 +
  748 + void project(const Template &src, Template &dst) const
  749 + {
  750 + (void) src; (void) dst; qFatal("shouldn't be here");
  751 + }
  752 +};
  753 +
  754 +BR_REGISTER(Transform, FilterOnMetadataTransform)
  755 +
720 756 } // namespace br
721 757  
722 758 #include "meta.moc"
... ...
openbr/plugins/pp5.cpp
... ... @@ -45,7 +45,7 @@ class PP5Initializer : public Initializer
45 45 void initialize() const
46 46 {
47 47 TRY(ppr_initialize_sdk(qPrintable(Globals->sdkPath + "/share/openbr/models/pp5/"), my_license_id, my_license_key))
48   - Globals->abbreviations.insert("PP5","Open!PP5Enroll:PP5Compare");
  48 + Globals->abbreviations.insert("PP5","Open+Expand+PP5Enroll:PP5Compare");
49 49 Globals->abbreviations.insert("PP5Register", "Open+PP5Enroll(true)+RenameFirst([eyeL,PP5_Landmark0_Right_Eye],Affine_0)+RenameFirst([eyeR,PP5_Landmark1_Left_Eye],Affine_1)");
50 50 Globals->abbreviations.insert("PP5CropFace", "Open+PP5Enroll(true)+RenameFirst([eyeL,PP5_Landmark0_Right_Eye],Affine_0)+RenameFirst([eyeR,PP5_Landmark1_Left_Eye],Affine_1)+Affine(128,128,0.25,0.35)+Cvt(Gray)");
51 51 }
... ...
openbr/plugins/slidingwindow.cpp
... ... @@ -164,6 +164,7 @@ static TemplateList cropTrainingSamples(const TemplateList &amp;data, const float as
164 164 continue;
165 165  
166 166 result += Template(tmpl.file, Mat(tmpl, posRect));
  167 + result.last().file.set("Label", QString("pos"));
167 168  
168 169 // Add random negative samples
169 170 Mat m = tmpl.m();
... ...
openbr/plugins/stream.cpp
... ... @@ -477,13 +477,17 @@ public:
477 477 if (frameNumber == final_frame) {
478 478 // We just received the last frame, better pulse
479 479 allReturned = true;
480   - lastReturned.wakeAll();
481 480 rval = true;
482 481 }
483 482  
484 483 return rval;
485 484 }
486 485  
  486 + void wake()
  487 + {
  488 + lastReturned.wakeAll();
  489 + }
  490 +
487 491 bool waitLast()
488 492 {
489 493 QMutexLocker lock(&last_frame_update);
... ... @@ -627,9 +631,9 @@ public:
627 631 }
628 632 virtual ~ProcessingStage() {}
629 633  
630   - virtual FrameData* run(FrameData * input, bool & should_continue)=0;
  634 + virtual FrameData* run(FrameData * input, bool & should_continue, bool & final)=0;
631 635  
632   - virtual bool tryAcquireNextStage(FrameData *& input)=0;
  636 + virtual bool tryAcquireNextStage(FrameData *& input, bool & final)=0;
633 637  
634 638 int stage_id;
635 639  
... ... @@ -648,23 +652,6 @@ protected:
648 652  
649 653 };
650 654  
651   -void BasicLoop::run()
652   -{
653   - int current_idx = start_idx;
654   - FrameData * target_item = startItem;
655   - bool should_continue = true;
656   - forever
657   - {
658   - target_item = stages->at(current_idx)->run(target_item, should_continue);
659   - if (!should_continue) {
660   - break;
661   - }
662   - current_idx++;
663   - current_idx = current_idx % stages->size();
664   - }
665   - this->reportFinished();
666   -}
667   -
668 655 class MultiThreadStage : public ProcessingStage
669 656 {
670 657 public:
... ... @@ -672,7 +659,7 @@ public:
672 659  
673 660 // Not much to worry about here, we will project the input
674 661 // and try to continue to the next stage.
675   - FrameData * run(FrameData * input, bool & should_continue)
  662 + FrameData * run(FrameData * input, bool & should_continue, bool & final)
676 663 {
677 664 if (input == NULL) {
678 665 qFatal("null input to multi-thread stage");
... ... @@ -680,16 +667,17 @@ public:
680 667  
681 668 input->data >> *transform;
682 669  
683   - should_continue = nextStage->tryAcquireNextStage(input);
  670 + should_continue = nextStage->tryAcquireNextStage(input, final);
684 671  
685 672 return input;
686 673 }
687 674  
688 675 // Called from a different thread than run. Nothing to worry about
689 676 // we offer no restrictions on when loops may enter this stage.
690   - virtual bool tryAcquireNextStage(FrameData *& input)
  677 + virtual bool tryAcquireNextStage(FrameData *& input, bool & final)
691 678 {
692 679 (void) input;
  680 + final = false;
693 681 return true;
694 682 }
695 683  
... ... @@ -744,7 +732,7 @@ public:
744 732 QReadWriteLock statusLock;
745 733 Status currentStatus;
746 734  
747   - FrameData * run(FrameData * input, bool & should_continue)
  735 + FrameData * run(FrameData * input, bool & should_continue, bool & final)
748 736 {
749 737 if (input == NULL)
750 738 qFatal("NULL input to stage %d", this->stage_id);
... ... @@ -758,7 +746,10 @@ public:
758 746 // Project the input we got
759 747 transform->projectUpdate(input->data);
760 748  
761   - should_continue = nextStage->tryAcquireNextStage(input);
  749 + should_continue = nextStage->tryAcquireNextStage(input,final);
  750 +
  751 + if (final)
  752 + return input;
762 753  
763 754 // Is there anything on our input buffer? If so we should start a thread with that.
764 755 QWriteLocker lock(&statusLock);
... ... @@ -792,8 +783,9 @@ public:
792 783  
793 784  
794 785 // Calledfrom a different thread than run.
795   - bool tryAcquireNextStage(FrameData *& input)
  786 + bool tryAcquireNextStage(FrameData *& input, bool & final)
796 787 {
  788 + final = false;
797 789 inputBuffer->addItem(input);
798 790  
799 791 QReadLocker lock(&statusLock);
... ... @@ -865,13 +857,13 @@ public:
865 857 SingleThreadStage::reset();
866 858 }
867 859  
868   - FrameData * run(FrameData * input, bool & should_continue)
  860 + FrameData * run(FrameData * input, bool & should_continue, bool & final)
869 861 {
870 862 if (input == NULL)
871 863 qFatal("NULL frame in input stage");
872 864  
873 865 // Can we enter the next stage?
874   - should_continue = nextStage->tryAcquireNextStage(input);
  866 + should_continue = nextStage->tryAcquireNextStage(input, final);
875 867  
876 868 // Try to get a frame from the datasource, we keep working on
877 869 // the frame we have, but we will queue another job for the next
... ... @@ -893,14 +885,14 @@ public:
893 885 }
894 886  
895 887 // The last stage, trying to access the first stage
896   - bool tryAcquireNextStage(FrameData *& input)
  888 + bool tryAcquireNextStage(FrameData *& input, bool & final)
897 889 {
898 890 // Return the frame, was it the last one?
899   - bool was_last = dataSource.returnFrame(input);
  891 + final = dataSource.returnFrame(input);
900 892 input = NULL;
901 893  
902 894 // OK we won't continue.
903   - if (was_last) {
  895 + if (final) {
904 896 return false;
905 897 }
906 898  
... ... @@ -943,6 +935,29 @@ public:
943 935 }
944 936 };
945 937  
  938 +void BasicLoop::run()
  939 +{
  940 + int current_idx = start_idx;
  941 + FrameData * target_item = startItem;
  942 + bool should_continue = true;
  943 + bool the_end = false;
  944 + forever
  945 + {
  946 + target_item = stages->at(current_idx)->run(target_item, should_continue, the_end);
  947 + if (!should_continue) {
  948 + break;
  949 + }
  950 + current_idx++;
  951 + current_idx = current_idx % stages->size();
  952 + }
  953 + if (the_end) {
  954 + dynamic_cast<ReadStage *> (stages->at(0))->dataSource.wake();
  955 + }
  956 +
  957 + this->reportFinished();
  958 +
  959 +}
  960 +
946 961 class DirectStreamTransform : public CompositeTransform
947 962 {
948 963 Q_OBJECT
... ...