diff --git a/sdk/openbr_plugin.cpp b/sdk/openbr_plugin.cpp index ec78665..4c8d311 100644 --- a/sdk/openbr_plugin.cpp +++ b/sdk/openbr_plugin.cpp @@ -1270,44 +1270,6 @@ void Transform::backProject(const TemplateList &dst, TemplateList &src) const } /* Distance - public methods */ -void Distance::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); -} - void Distance::compare(const TemplateList &target, const TemplateList &query, Output *output) const { const bool stepTarget = target.size() > query.size(); @@ -1336,7 +1298,7 @@ float Distance::compare(const Template &target, const Template &query) const return -std::numeric_limits::max(); } - return a * (_compare(target, query) - b); + return _compare(target, query); } QList Distance::compare(const TemplateList &targets, const Template &query) const diff --git a/sdk/openbr_plugin.h b/sdk/openbr_plugin.h index a045a63..f4964eb 100644 --- a/sdk/openbr_plugin.h +++ b/sdk/openbr_plugin.h @@ -1065,15 +1065,9 @@ class BR_EXPORT Distance : public Object { Q_OBJECT - // Score normalization - 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(float, a, 1) - BR_PROPERTY(float, b, 0) - public: static QSharedPointer fromAlgorithm(const QString &algorithm); /*!< \brief Retrieve an algorithm's distance. */ - virtual void train(const TemplateList &src); /*!< \brief Train the distance. */ + virtual void train(const TemplateList &src) { (void) src; } /*!< \brief Train the distance. */ virtual void compare(const TemplateList &target, const TemplateList &query, Output *output) const; /*!< \brief Compare two template lists. */ float compare(const Template &target, const Template &query) const; /*!< \brief Compute the normalized distance between two templates. */ QList compare(const TemplateList &targets, const Template &query) const; /*!< \brief Compute the normalized distance between a template and a template list. */ diff --git a/sdk/plugins/quality.cpp b/sdk/plugins/quality.cpp index 3c3f332..769ffde 100644 --- a/sdk/plugins/quality.cpp +++ b/sdk/plugins/quality.cpp @@ -74,6 +74,119 @@ class IUMTransform : public Transform BR_REGISTER(Transform, IUMTransform) +/* Kernel Density Estimator */ +struct KDE +{ + float min, max; + QList bins; + + KDE() : min(0), max(1) {} + KDE(const QList &scores) + { + Common::MinMax(scores, &min, &max); + double h = Common::KernelDensityBandwidth(scores); + const int size = 255; + bins.reserve(size); + for (int i=0; i= max) return bins.last(); + const float x = (score-min)/(max-min)*bins.size(); + const float y1 = bins[floor(x)]; + const float y2 = bins[ceil(x)]; + return y1 + (y2-y1)*(x-floor(x)); + } +}; + +QDataStream &operator<<(QDataStream &stream, const KDE &kde) +{ + return stream << kde.min << kde.max << kde.bins; +} + +QDataStream &operator>>(QDataStream &stream, KDE &kde) +{ + return stream >> kde.min >> kde.max >> kde.bins; +} + +/* Non-match Probability */ +struct NMP +{ + KDE genuine, impostor; + NMP() {} + NMP(const QList &genuineScores, const QList &impostorScores) + : genuine(genuineScores), impostor(impostorScores) {} + float operator()(float score) const { float g = genuine(score); return g / (impostor(score) + g); } +}; + +QDataStream &operator<<(QDataStream &stream, const NMP &nmp) +{ + return stream << nmp.genuine << nmp.impostor; +} + +QDataStream &operator>>(QDataStream &stream, NMP &nmp) +{ + return stream >> nmp.genuine >> nmp.impostor; +} + +/*! + * \ingroup distances + * \brief Impostor Uniqueness Distance \cite klare12 + * \author Josh Klontz \cite jklontz + */ +class IUMDistance : public Distance +{ + Q_OBJECT + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) + BR_PROPERTY(br::Distance*, distance, Factory::make(".Dist(L2)")) + + QList nmps; + + void train(const TemplateList &src) + { + distance->train(src); + + const QList labels = src.labels(); + QScopedPointer memoryOutput(dynamic_cast(Output::make(".Matrix", FileList(src.size()), FileList(src.size())))); + distance->compare(src, src, memoryOutput.data()); + + const int IUM_Bins = 3; + QVector< QList > genuineScores(IUM_Bins), impostorScores(IUM_Bins); + for (int i=0; idata.at(i, j); + const int bin = src[i].file.getInt("IUM_Bin"); + if (labels[i] == labels[j]) genuineScores[bin].append(score); + else impostorScores[bin].append(score); + } + + for (int i=0; icompare(target, query)); + } + + void store(QDataStream &stream) const + { + distance->store(stream); + stream << nmps; + } + + void load(QDataStream &stream) + { + distance->load(stream); + stream >> nmps; + } +}; + +BR_REGISTER(Distance, IUMDistance) + } // namespace br #include "quality.moc"