Commit d1dee8c220ab52498e4e78ec749139caccc112e2
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
6 changed files
with
94 additions
and
34 deletions
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 &predictedGallery, const QString &truthGallery | @@ -507,11 +508,13 @@ float EvalDetection(const QString &predictedGallery, const QString &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 &predictedGallery, const QString &truthGallery | @@ -519,6 +522,9 @@ float EvalDetection(const QString &predictedGallery, const QString &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 &data, const float as | @@ -164,6 +164,7 @@ static TemplateList cropTrainingSamples(const TemplateList &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 |