diff --git a/app/br/br.cpp b/app/br/br.cpp index 949b277..89cd232 100644 --- a/app/br/br.cpp +++ b/app/br/br.cpp @@ -171,6 +171,9 @@ public: } else if (!strcmp(fun, "evalKNN")) { check(parc >= 2 && parc <= 3, "Incorrect parameter count for 'evalKNN'."); br_eval_knn(parv[0], parv[1], parc > 2 ? parv[2] : ""); + } else if (!strcmp(fun, "evalEER")) { + check(parc >=1 && parc <=3 , "Incorrect parameter count for 'evalEER'."); + br_eval_eer(parv[0], parc > 1 ? parv[1] : "", parc > 2 ? parv[2] : ""); } else if (!strcmp(fun, "pairwiseCompare")) { check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'pairwiseCompare'."); br_pairwise_compare(parv[0], parv[1], parc == 3 ? parv[2] : ""); diff --git a/openbr/core/eval.cpp b/openbr/core/eval.cpp index 4cfcd5c..c2ffb52 100755 --- a/openbr/core/eval.cpp +++ b/openbr/core/eval.cpp @@ -1168,4 +1168,68 @@ void EvalKNN(const QString &knnGraph, const QString &knnTruth, const QString &cs qDebug("FNIR @ FPIR = 0.01: %.3f", 1-getOperatingPointGivenFAR(operatingPoints, 0.01).TAR); } +void EvalEER(const QString &predictedXML, QString gt_property, QString distribution_property){ + if (gt_property.isEmpty()) + gt_property = "LivenessGT"; + if (distribution_property.isEmpty()) + distribution_property = "LivenessDistribution"; + int classOneTemplateCount = 0; + const TemplateList templateList(TemplateList::fromGallery(predictedXML)); + + QHash gtLabels; + QHash > scores; + for (int i=0; i(gt_property); + if (gtLabel == 1) + classOneTemplateCount++; + QList templateScores = templateList[i].file.getList(distribution_property); + gtLabels[templateKey] = gtLabel; + scores[templateKey] = templateScores; + } + + const int numPoints = 200; + const float stepSize = 100.0/numPoints; + const int numTemplates = scores.size(); + float thres = 0.0; //Between [0,100] + float thresNorm = 0.0; //Between [0,1] + int FA = 0, FR = 0; + float minDiff = 100; + float EER = 100; + float EERThres = 0; + + for(int i = 0; i <= numPoints; i++){ + FA = 0, FR = 0; + thresNorm = thres/100.0; + foreach(const QString &key, scores.keys()){ + int gtLabel = gtLabels[key]; + //> thresNorm = class 0 (spoof) : < thresNorm = class 1 (genuine) + if (scores[key][0] >= thresNorm && gtLabel == 0) + continue; + else if (scores[key][0] < thresNorm && gtLabel == 1) + continue; + else if (scores[key][0] >= thresNorm && gtLabel == 1) + FR +=1; + else if (scores[key][0] < thresNorm && gtLabel == 0) + FA +=1; + } + float FAR = FA / float(numTemplates - classOneTemplateCount); + float FRR = FR / float(classOneTemplateCount); + + float diff = std::abs(FAR-FRR); + if (diff < minDiff){ + minDiff = diff; + EER = (FAR+FRR)/2.0; + EERThres = thresNorm; + } + thres += stepSize; + } + + qDebug() <<"Class 0 Templates:" << classOneTemplateCount << "Class 1 Templates:" + << numTemplates - classOneTemplateCount << "Total Templates:" << numTemplates; + qDebug("EER: %.3f @ Threshold %.3f", EER*100, EERThres); + +} + + } // namespace br diff --git a/openbr/core/eval.h b/openbr/core/eval.h index 0edfd25..9ecf0aa 100644 --- a/openbr/core/eval.h +++ b/openbr/core/eval.h @@ -34,7 +34,7 @@ namespace br float EvalLandmarking(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", int normalizationIndexA = 0, int normalizationIndexB = 1, int sampleIndex = 0, int totalExamples = 5); // Return average error void EvalRegression(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = ""); void EvalKNN(const QString &knnGraph, const QString &knnTruth, const QString &csv = ""); - + void EvalEER(const QString &predictedXML, const QString gt_property = "", const QString distribution_property = ""); struct Candidate { size_t index; diff --git a/openbr/openbr.cpp b/openbr/openbr.cpp index 97155ec..9236c60 100644 --- a/openbr/openbr.cpp +++ b/openbr/openbr.cpp @@ -150,6 +150,11 @@ void br_eval_knn(const char *knnGraph, const char *knnTruth, const char *csv) EvalKNN(knnGraph, knnTruth, csv); } +void br_eval_eer(const char *predicted_xml, const char *gt_property, const char *distribution_property ) +{ + EvalEER(predicted_xml, gt_property, distribution_property); +} + void br_finalize() { Context::finalize(); diff --git a/openbr/openbr.h b/openbr/openbr.h index 12a769a..5b147ad 100644 --- a/openbr/openbr.h +++ b/openbr/openbr.h @@ -66,6 +66,8 @@ BR_EXPORT void br_eval_regression(const char *predicted_gallery, const char *tru BR_EXPORT void br_eval_knn(const char *knnGraph, const char *knnTruth, const char *csv = ""); +BR_EXPORT void br_eval_eer(const char *predicted_xml, const char *gt_property = "", const char *distribution_property = ""); + BR_EXPORT void br_finalize(); BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], diff --git a/openbr/plugins/metadata/randomrects.cpp b/openbr/plugins/metadata/randomrects.cpp index 9f86088..179ba5c 100644 --- a/openbr/plugins/metadata/randomrects.cpp +++ b/openbr/plugins/metadata/randomrects.cpp @@ -4,6 +4,9 @@ #include #include +#include "opencv2/imgproc/imgproc.hpp" + +using namespace cv; namespace br { @@ -18,8 +21,15 @@ class RandomRectsTransform : public UntrainableMetaTransform Q_OBJECT Q_PROPERTY(int numRects READ get_numRects WRITE set_numRects RESET reset_numRects STORED false) Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) + Q_PROPERTY(bool sameSize READ get_sameSize WRITE set_sameSize RESET reset_sameSize STORED false) + Q_PROPERTY(bool filterDarkPatches READ get_filterDarkPatches WRITE set_filterDarkPatches RESET reset_filterDarkPatches STORED false) + Q_PROPERTY(float bgFgThresh READ get_bgFgThresh WRITE set_bgFgThresh RESET reset_bgFgThresh STORED false) + BR_PROPERTY(int, numRects, 135) BR_PROPERTY(int, minSize, 24) + BR_PROPERTY(bool, sameSize, false) + BR_PROPERTY(bool, filterDarkPatches, false) + BR_PROPERTY(float, bgFgThresh, 0.75) void project(const Template &, Template &) const { @@ -28,13 +38,28 @@ class RandomRectsTransform : public UntrainableMetaTransform void project(const TemplateList &src, TemplateList &dst) const { + int size = minSize; foreach (const Template &t, src) { int maxSize = std::min(t.m().rows, t.m().cols); for (int i = 0; i < numRects; i++) { - int size = (rand() % (maxSize - minSize)) + minSize; + + if (!sameSize){ + size = (rand() % (maxSize - minSize)) + minSize; + } + int x = rand() % (t.m().cols - size); int y = rand() % (t.m().rows - size); + if (filterDarkPatches){ + Mat patch; + t.m()(cv::Rect(x,y,size,size)).copyTo(patch); + cv::threshold(patch,patch,5,1,cv::THRESH_BINARY); + Scalar sumForeground = sum(patch); + float bgFgRatio = sumForeground[0] / float(minSize * minSize); + if (bgFgRatio < bgFgThresh) + continue; + } + Template out(t.file, t.m()); out.file.clearRects(); out.file.appendRect(QRect(x,y,size,size));