Commit ff98581b768c19b9e5add6e8d0ea6d073d5d414d

Authored by Josh Klontz
1 parent a1015388

implemented BhattacharyyaTransform

Showing 1 changed file with 86 additions and 0 deletions
openbr/plugins/quality.cpp
  1 +#include <QFutureSynchronizer>
  2 +#include <QtConcurrent>
1 3 #include <openbr/openbr_plugin.h>
2 4  
3 5 #include "openbr/core/common.h"
  6 +#include "openbr/core/opencvutils.h"
4 7  
5 8 namespace br
6 9 {
... ... @@ -198,6 +201,89 @@ class MatchProbabilityDistance : public Distance
198 201 BR_REGISTER(Distance, MatchProbabilityDistance)
199 202  
200 203 /*!
  204 + * \ingroup transforms
  205 + * \brief Normalize by Bhattacharyya coefficient.
  206 + * \author Josh Klontz \cite jklontz
  207 + */
  208 +class BhattacharyyaTransform : public Transform
  209 +{
  210 + Q_OBJECT
  211 + cv::Mat scale;
  212 +
  213 + static float bhattacharyyaCoefficient(const cv::Mat &data, const QList<int> &labels)
  214 + {
  215 + const QList<float> vals = OpenCVUtils::matrixToVector<float>(data);
  216 + if (vals.size() != labels.size())
  217 + qFatal("Logic error.");
  218 +
  219 + QList<float> genuineScores; genuineScores.reserve(vals.size());
  220 + QList<float> impostorScores; impostorScores.reserve(vals.size()*vals.size()/2);
  221 + for (int i=0; i<vals.size(); i++)
  222 + for (int j=i+1; j<vals.size(); j++)
  223 + if (labels[i] == labels[j]) genuineScores.append(fabs(vals[i]-vals[j]));
  224 + else impostorScores.append(fabs(vals[i]-vals[j]));
  225 +
  226 + genuineScores = Common::Downsample(genuineScores, 256);
  227 + impostorScores = Common::Downsample(impostorScores, 256);
  228 + double hGenuine = Common::KernelDensityBandwidth(genuineScores);
  229 + double hImpostor = Common::KernelDensityBandwidth(impostorScores);
  230 +
  231 + float genuineMin, genuineMax, impostorMin, impostorMax, min, max;
  232 + Common::MinMax(genuineScores, &genuineMin, &genuineMax);
  233 + Common::MinMax(impostorScores, &impostorMin, &impostorMax);
  234 + min = std::min(genuineMin, impostorMin);
  235 + max = std::max(genuineMax, impostorMax);
  236 +
  237 + const int steps = 512;
  238 + double bc = 0;
  239 + for (int i=0; i<steps; i++) {
  240 + float score = min + i*(max-min)/(steps-1);
  241 + bc += sqrt(Common::KernelDensityEstimation(genuineScores, score, hGenuine) *
  242 + Common::KernelDensityEstimation(impostorScores, score, hImpostor))/steps;
  243 + }
  244 + if ((bc <= 0) || (bc > 1)) qFatal("Logic error.");
  245 + return -log(bc);
  246 + }
  247 +
  248 + void train(const TemplateList &src)
  249 + {
  250 + const cv::Mat data = OpenCVUtils::toMat(src.data());
  251 + const QList<int> labels = src.labels<int>();
  252 +
  253 + QFutureSynchronizer<float> futures;
  254 + QList<float> coefficients; coefficients.reserve(data.cols);
  255 + for (int i=0; i<data.cols; i++)
  256 + if (Globals->parallelism) futures.addFuture(QtConcurrent::run(&BhattacharyyaTransform::bhattacharyyaCoefficient, data.col(i), labels));
  257 + else coefficients.append( bhattacharyyaCoefficient( data.col(i), labels));
  258 + futures.waitForFinished();
  259 + foreach (const QFuture<float> &future, futures.futures())
  260 + coefficients.append(future.result());
  261 +
  262 + scale = cv::Mat(1, coefficients.size(), CV_32FC1);
  263 + for (int i=0; i<coefficients.size(); i++)
  264 + scale.at<float>(0,i) = coefficients[i];
  265 +
  266 + }
  267 +
  268 + void project(const Template &src, Template &dst) const
  269 + {
  270 + cv::multiply(src.m().reshape(1,1), scale, dst);
  271 + }
  272 +
  273 + void store(QDataStream &stream) const
  274 + {
  275 + stream << scale;
  276 + }
  277 +
  278 + void load(QDataStream &stream)
  279 + {
  280 + stream >> scale;
  281 + }
  282 +};
  283 +
  284 +BR_REGISTER(Transform, BhattacharyyaTransform)
  285 +
  286 +/*!
201 287 * \ingroup distances
202 288 * \brief Linear normalizes of a distance so the mean impostor score is 0 and the mean genuine score is 1.
203 289 * \author Josh Klontz \cite jklontz
... ...