diff --git a/sdk/plugins/algorithms.cpp b/sdk/plugins/algorithms.cpp index d25208d..c841fdf 100644 --- a/sdk/plugins/algorithms.cpp +++ b/sdk/plugins/algorithms.cpp @@ -70,6 +70,7 @@ class AlgorithmsInitializer : public Initializer Globals->abbreviations.insert("FaceClassificationExtraction", "((Grid(7,7)+SIFTDescriptor(8)+ByRow)/DenseLBP+PCA(0.95,instances=-1)+Cat)"); Globals->abbreviations.insert("AgeRegressor", "Center(Range,instances=-1)+SVM(RBF,EPS_SVR,instances=100)"); Globals->abbreviations.insert("GenderClassifier", "Center(Range,instances=-1)+SVM(RBF,C_SVC,instances=4000)"); + Globals->abbreviations.insert("UCharL1", "Unit(ByteL1)"); } }; diff --git a/sdk/plugins/compare.cpp b/sdk/plugins/compare.cpp index 113e57f..3a6baf2 100644 --- a/sdk/plugins/compare.cpp +++ b/sdk/plugins/compare.cpp @@ -119,7 +119,7 @@ BR_REGISTER(Distance, DistDistance) * \brief Fast 8-bit L1 distance * \author Josh Klontz \cite jklontz */ -class UCharL1Distance : public Distance +class ByteL1Distance : public Distance { Q_OBJECT @@ -129,7 +129,7 @@ class UCharL1Distance : public Distance } }; -BR_REGISTER(Distance, UCharL1Distance) +BR_REGISTER(Distance, ByteL1Distance) /*! @@ -137,7 +137,7 @@ BR_REGISTER(Distance, UCharL1Distance) * \brief Fast 4-bit L1 distance * \author Josh Klontz \cite jklontz */ -class PackedUCharL1Distance : public Distance +class HalfByteL1Distance : public Distance { Q_OBJECT @@ -147,7 +147,7 @@ class PackedUCharL1Distance : public Distance } }; -BR_REGISTER(Distance, PackedUCharL1Distance) +BR_REGISTER(Distance, HalfByteL1Distance) /*! * \ingroup distances diff --git a/sdk/plugins/quality.cpp b/sdk/plugins/quality.cpp index 789cdd4..796bb86 100644 --- a/sdk/plugins/quality.cpp +++ b/sdk/plugins/quality.cpp @@ -201,6 +201,67 @@ class MPDistance : public Distance BR_REGISTER(Distance, MPDistance) +/*! + * \ingroup distances + * \brief Linear normalizes of a distance so the mean impostor score is 0 and the mean genuine score is 1. + * \author Josh Klontz \cite jklontz + */ +class UnitDistance : public Distance +{ + Q_OBJECT + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance) + Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a) + Q_PROPERTY(float b READ get_b WRITE set_b RESET reset_b) + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)")) + BR_PROPERTY(float, a, 1) + BR_PROPERTY(float, b, 0) + + void train(const TemplateList &templates) + { + const TemplateList samples = templates.mid(0, 2000); + const QList sampleLabels = samples.labels(); + QScopedPointer memoryOutput(dynamic_cast(Output::make(".Matrix", FileList(samples.size()), FileList(samples.size())))); + compare(samples, samples, memoryOutput.data()); + + double genuineAccumulator, impostorAccumulator; + int genuineCount, impostorCount; + genuineAccumulator = impostorAccumulator = genuineCount = impostorCount = 0; + + for (int i=0; idata.at(i, j); + if (sampleLabels[i] == sampleLabels[j]) { + genuineAccumulator += val; + genuineCount++; + } else { + impostorAccumulator += val; + impostorCount++; + } + } + } + + if (genuineCount == 0) { qWarning("No genuine matches."); return; } + if (impostorCount == 0) { qWarning("No impostor matches."); return; } + + double genuineMean = genuineAccumulator / genuineCount; + double impostorMean = impostorAccumulator / impostorCount; + + if (genuineMean == impostorMean) { qWarning("Genuines and impostors are indistinguishable."); return; } + + a = 1.0/(genuineMean-impostorMean); + b = impostorMean; + + qDebug("a = %f, b = %f", a, b); + } + + float _compare(const Template &target, const Template &query) const + { + return a * (distance->compare(target, query) - b); + } +}; + +BR_REGISTER(Distance, UnitDistance) + } // namespace br #include "quality.moc"