Commit ff98581b768c19b9e5add6e8d0ea6d073d5d414d
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 | ... | ... |