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 | 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 &predictedGallery, const QString &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 &predictedGallery, const QString &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 &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 | ... | ... |