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,9 +19,11 @@ set(PACKAGE_YEAR 2013)
19 19
20 if(${CMAKE_VERSION} VERSION_EQUAL 2.8.11) 20 if(${CMAKE_VERSION} VERSION_EQUAL 2.8.11)
21 cmake_policy(SET CMP0020 OLD) 21 cmake_policy(SET CMP0020 OLD)
  22 + cmake_policy(SET CMP0022 OLD)
22 endif() 23 endif()
23 if(${CMAKE_VERSION} VERSION_GREATER 2.8.11) 24 if(${CMAKE_VERSION} VERSION_GREATER 2.8.11)
24 cmake_policy(SET CMP0020 OLD) 25 cmake_policy(SET CMP0020 OLD)
  26 + cmake_policy(SET CMP0022 OLD)
25 endif() 27 endif()
26 28
27 if(${CMAKE_SIZEOF_VOID_P} MATCHES 8) 29 if(${CMAKE_SIZEOF_VOID_P} MATCHES 8)
openbr/core/eval.cpp
@@ -394,6 +394,7 @@ static QStringList computeDetectionResults(const QList<ResolvedDetection> &detec @@ -394,6 +394,7 @@ static QStringList computeDetectionResults(const QList<ResolvedDetection> &detec
394 for (int i=0; i<detections.size(); i++) { 394 for (int i=0; i<detections.size(); i++) {
395 const ResolvedDetection &detection = detections[i]; 395 const ResolvedDetection &detection = detections[i];
396 if (discrete) { 396 if (discrete) {
  397 + // A 50% overlap is considered a true positive
397 if (detection.overlap >= 0.5) TP++; 398 if (detection.overlap >= 0.5) TP++;
398 else FP++; 399 else FP++;
399 } else { 400 } else {
@@ -507,11 +508,13 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery @@ -507,11 +508,13 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery
507 QMap<QString, Detections> allDetections = getDetections(predicted, truth); 508 QMap<QString, Detections> allDetections = getDetections(predicted, truth);
508 509
509 QList<ResolvedDetection> resolvedDetections, falseNegativeDetections; 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 while (!detections.truth.isEmpty() && !detections.predicted.isEmpty()) { 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 int bestIndex = -1; 515 int bestIndex = -1;
514 float bestOverlap = -std::numeric_limits<float>::max(); 516 float bestOverlap = -std::numeric_limits<float>::max();
  517 + // Find the nearest predicted detection to this ground truth detection
515 for (int i=0; i<detections.predicted.size(); i++) { 518 for (int i=0; i<detections.predicted.size(); i++) {
516 const float overlap = truth.overlap(detections.predicted[i]); 519 const float overlap = truth.overlap(detections.predicted[i]);
517 if (overlap > bestOverlap) { 520 if (overlap > bestOverlap) {
@@ -519,6 +522,9 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery @@ -519,6 +522,9 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery
519 bestIndex = i; 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 const Detection predicted = detections.predicted.takeAt(bestIndex); 528 const Detection predicted = detections.predicted.takeAt(bestIndex);
523 resolvedDetections.append(ResolvedDetection(predicted.confidence, bestOverlap)); 529 resolvedDetections.append(ResolvedDetection(predicted.confidence, bestOverlap));
524 } 530 }
openbr/plugins/meta.cpp
@@ -717,6 +717,42 @@ public: @@ -717,6 +717,42 @@ public:
717 }; 717 };
718 BR_REGISTER(Transform, DistributeTemplateTransform) 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 } // namespace br 756 } // namespace br
721 757
722 #include "meta.moc" 758 #include "meta.moc"
openbr/plugins/pp5.cpp
@@ -45,7 +45,7 @@ class PP5Initializer : public Initializer @@ -45,7 +45,7 @@ class PP5Initializer : public Initializer
45 void initialize() const 45 void initialize() const
46 { 46 {
47 TRY(ppr_initialize_sdk(qPrintable(Globals->sdkPath + "/share/openbr/models/pp5/"), my_license_id, my_license_key)) 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 Globals->abbreviations.insert("PP5Register", "Open+PP5Enroll(true)+RenameFirst([eyeL,PP5_Landmark0_Right_Eye],Affine_0)+RenameFirst([eyeR,PP5_Landmark1_Left_Eye],Affine_1)"); 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 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)"); 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,6 +164,7 @@ static TemplateList cropTrainingSamples(const TemplateList &amp;data, const float as
164 continue; 164 continue;
165 165
166 result += Template(tmpl.file, Mat(tmpl, posRect)); 166 result += Template(tmpl.file, Mat(tmpl, posRect));
  167 + result.last().file.set("Label", QString("pos"));
167 168
168 // Add random negative samples 169 // Add random negative samples
169 Mat m = tmpl.m(); 170 Mat m = tmpl.m();
openbr/plugins/stream.cpp
@@ -477,13 +477,17 @@ public: @@ -477,13 +477,17 @@ public:
477 if (frameNumber == final_frame) { 477 if (frameNumber == final_frame) {
478 // We just received the last frame, better pulse 478 // We just received the last frame, better pulse
479 allReturned = true; 479 allReturned = true;
480 - lastReturned.wakeAll();  
481 rval = true; 480 rval = true;
482 } 481 }
483 482
484 return rval; 483 return rval;
485 } 484 }
486 485
  486 + void wake()
  487 + {
  488 + lastReturned.wakeAll();
  489 + }
  490 +
487 bool waitLast() 491 bool waitLast()
488 { 492 {
489 QMutexLocker lock(&last_frame_update); 493 QMutexLocker lock(&last_frame_update);
@@ -627,9 +631,9 @@ public: @@ -627,9 +631,9 @@ public:
627 } 631 }
628 virtual ~ProcessingStage() {} 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 int stage_id; 638 int stage_id;
635 639
@@ -648,23 +652,6 @@ protected: @@ -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 class MultiThreadStage : public ProcessingStage 655 class MultiThreadStage : public ProcessingStage
669 { 656 {
670 public: 657 public:
@@ -672,7 +659,7 @@ public: @@ -672,7 +659,7 @@ public:
672 659
673 // Not much to worry about here, we will project the input 660 // Not much to worry about here, we will project the input
674 // and try to continue to the next stage. 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 if (input == NULL) { 664 if (input == NULL) {
678 qFatal("null input to multi-thread stage"); 665 qFatal("null input to multi-thread stage");
@@ -680,16 +667,17 @@ public: @@ -680,16 +667,17 @@ public:
680 667
681 input->data >> *transform; 668 input->data >> *transform;
682 669
683 - should_continue = nextStage->tryAcquireNextStage(input); 670 + should_continue = nextStage->tryAcquireNextStage(input, final);
684 671
685 return input; 672 return input;
686 } 673 }
687 674
688 // Called from a different thread than run. Nothing to worry about 675 // Called from a different thread than run. Nothing to worry about
689 // we offer no restrictions on when loops may enter this stage. 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 (void) input; 679 (void) input;
  680 + final = false;
693 return true; 681 return true;
694 } 682 }
695 683
@@ -744,7 +732,7 @@ public: @@ -744,7 +732,7 @@ public:
744 QReadWriteLock statusLock; 732 QReadWriteLock statusLock;
745 Status currentStatus; 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 if (input == NULL) 737 if (input == NULL)
750 qFatal("NULL input to stage %d", this->stage_id); 738 qFatal("NULL input to stage %d", this->stage_id);
@@ -758,7 +746,10 @@ public: @@ -758,7 +746,10 @@ public:
758 // Project the input we got 746 // Project the input we got
759 transform->projectUpdate(input->data); 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 // Is there anything on our input buffer? If so we should start a thread with that. 754 // Is there anything on our input buffer? If so we should start a thread with that.
764 QWriteLocker lock(&statusLock); 755 QWriteLocker lock(&statusLock);
@@ -792,8 +783,9 @@ public: @@ -792,8 +783,9 @@ public:
792 783
793 784
794 // Calledfrom a different thread than run. 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 inputBuffer->addItem(input); 789 inputBuffer->addItem(input);
798 790
799 QReadLocker lock(&statusLock); 791 QReadLocker lock(&statusLock);
@@ -865,13 +857,13 @@ public: @@ -865,13 +857,13 @@ public:
865 SingleThreadStage::reset(); 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 if (input == NULL) 862 if (input == NULL)
871 qFatal("NULL frame in input stage"); 863 qFatal("NULL frame in input stage");
872 864
873 // Can we enter the next stage? 865 // Can we enter the next stage?
874 - should_continue = nextStage->tryAcquireNextStage(input); 866 + should_continue = nextStage->tryAcquireNextStage(input, final);
875 867
876 // Try to get a frame from the datasource, we keep working on 868 // Try to get a frame from the datasource, we keep working on
877 // the frame we have, but we will queue another job for the next 869 // the frame we have, but we will queue another job for the next
@@ -893,14 +885,14 @@ public: @@ -893,14 +885,14 @@ public:
893 } 885 }
894 886
895 // The last stage, trying to access the first stage 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 // Return the frame, was it the last one? 890 // Return the frame, was it the last one?
899 - bool was_last = dataSource.returnFrame(input); 891 + final = dataSource.returnFrame(input);
900 input = NULL; 892 input = NULL;
901 893
902 // OK we won't continue. 894 // OK we won't continue.
903 - if (was_last) { 895 + if (final) {
904 return false; 896 return false;
905 } 897 }
906 898
@@ -943,6 +935,29 @@ public: @@ -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 class DirectStreamTransform : public CompositeTransform 961 class DirectStreamTransform : public CompositeTransform
947 { 962 {
948 Q_OBJECT 963 Q_OBJECT