diff --git a/openbr/plugins/quality.cpp b/openbr/plugins/quality.cpp index 4ff8229..5ea1c3e 100644 --- a/openbr/plugins/quality.cpp +++ b/openbr/plugins/quality.cpp @@ -1,6 +1,9 @@ +#include +#include #include #include "openbr/core/common.h" +#include "openbr/core/opencvutils.h" namespace br { @@ -198,6 +201,89 @@ class MatchProbabilityDistance : public Distance BR_REGISTER(Distance, MatchProbabilityDistance) /*! + * \ingroup transforms + * \brief Normalize by Bhattacharyya coefficient. + * \author Josh Klontz \cite jklontz + */ +class BhattacharyyaTransform : public Transform +{ + Q_OBJECT + cv::Mat scale; + + static float bhattacharyyaCoefficient(const cv::Mat &data, const QList &labels) + { + const QList vals = OpenCVUtils::matrixToVector(data); + if (vals.size() != labels.size()) + qFatal("Logic error."); + + QList genuineScores; genuineScores.reserve(vals.size()); + QList impostorScores; impostorScores.reserve(vals.size()*vals.size()/2); + for (int i=0; i 1)) qFatal("Logic error."); + return -log(bc); + } + + void train(const TemplateList &src) + { + const cv::Mat data = OpenCVUtils::toMat(src.data()); + const QList labels = src.labels(); + + QFutureSynchronizer futures; + QList coefficients; coefficients.reserve(data.cols); + for (int i=0; iparallelism) futures.addFuture(QtConcurrent::run(&BhattacharyyaTransform::bhattacharyyaCoefficient, data.col(i), labels)); + else coefficients.append( bhattacharyyaCoefficient( data.col(i), labels)); + futures.waitForFinished(); + foreach (const QFuture &future, futures.futures()) + coefficients.append(future.result()); + + scale = cv::Mat(1, coefficients.size(), CV_32FC1); + for (int i=0; i(0,i) = coefficients[i]; + + } + + void project(const Template &src, Template &dst) const + { + cv::multiply(src.m().reshape(1,1), scale, dst); + } + + void store(QDataStream &stream) const + { + stream << scale; + } + + void load(QDataStream &stream) + { + stream >> scale; + } +}; + +BR_REGISTER(Transform, BhattacharyyaTransform) + +/*! * \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