Commit 0fb1cef2dfc9eea657ee80b6730aba9a54e07994

Authored by Josh Klontz
1 parent 4b34805a

finished IUM draft

sdk/openbr_plugin.cpp
... ... @@ -1270,44 +1270,6 @@ void Transform::backProject(const TemplateList &dst, TemplateList &src) const
1270 1270 }
1271 1271  
1272 1272 /* Distance - public methods */
1273   -void Distance::train(const TemplateList &templates)
1274   -{
1275   - const TemplateList samples = templates.mid(0, 2000);
1276   - const QList<float> sampleLabels = samples.labels<float>();
1277   - QScopedPointer<MatrixOutput> memoryOutput(dynamic_cast<MatrixOutput*>(Output::make(".Matrix", FileList(samples.size()), FileList(samples.size()))));
1278   - compare(samples, samples, memoryOutput.data());
1279   -
1280   - double genuineAccumulator, impostorAccumulator;
1281   - int genuineCount, impostorCount;
1282   - genuineAccumulator = impostorAccumulator = genuineCount = impostorCount = 0;
1283   -
1284   - for (int i=0; i<samples.size(); i++) {
1285   - for (int j=0; j<i; j++) {
1286   - const float val = memoryOutput.data()->data.at<float>(i, j);
1287   - if (sampleLabels[i] == sampleLabels[j]) {
1288   - genuineAccumulator += val;
1289   - genuineCount++;
1290   - } else {
1291   - impostorAccumulator += val;
1292   - impostorCount++;
1293   - }
1294   - }
1295   - }
1296   -
1297   - if (genuineCount == 0) { qWarning("No genuine matches."); return; }
1298   - if (impostorCount == 0) { qWarning("No impostor matches."); return; }
1299   -
1300   - double genuineMean = genuineAccumulator / genuineCount;
1301   - double impostorMean = impostorAccumulator / impostorCount;
1302   -
1303   - if (genuineMean == impostorMean) { qWarning("Genuines and impostors are indistinguishable."); return; }
1304   -
1305   - a = 1.0/(genuineMean-impostorMean);
1306   - b = impostorMean;
1307   -
1308   - qDebug("a = %f, b = %f", a, b);
1309   -}
1310   -
1311 1273 void Distance::compare(const TemplateList &target, const TemplateList &query, Output *output) const
1312 1274 {
1313 1275 const bool stepTarget = target.size() > query.size();
... ... @@ -1336,7 +1298,7 @@ float Distance::compare(const Template &amp;target, const Template &amp;query) const
1336 1298 return -std::numeric_limits<float>::max();
1337 1299 }
1338 1300  
1339   - return a * (_compare(target, query) - b);
  1301 + return _compare(target, query);
1340 1302 }
1341 1303  
1342 1304 QList<float> Distance::compare(const TemplateList &targets, const Template &query) const
... ...
sdk/openbr_plugin.h
... ... @@ -1065,15 +1065,9 @@ class BR_EXPORT Distance : public Object
1065 1065 {
1066 1066 Q_OBJECT
1067 1067  
1068   - // Score normalization
1069   - Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a)
1070   - Q_PROPERTY(float b READ get_b WRITE set_b RESET reset_b)
1071   - BR_PROPERTY(float, a, 1)
1072   - BR_PROPERTY(float, b, 0)
1073   -
1074 1068 public:
1075 1069 static QSharedPointer<Distance> fromAlgorithm(const QString &algorithm); /*!< \brief Retrieve an algorithm's distance. */
1076   - virtual void train(const TemplateList &src); /*!< \brief Train the distance. */
  1070 + virtual void train(const TemplateList &src) { (void) src; } /*!< \brief Train the distance. */
1077 1071 virtual void compare(const TemplateList &target, const TemplateList &query, Output *output) const; /*!< \brief Compare two template lists. */
1078 1072 float compare(const Template &target, const Template &query) const; /*!< \brief Compute the normalized distance between two templates. */
1079 1073 QList<float> compare(const TemplateList &targets, const Template &query) const; /*!< \brief Compute the normalized distance between a template and a template list. */
... ...
sdk/plugins/quality.cpp
... ... @@ -74,6 +74,119 @@ class IUMTransform : public Transform
74 74  
75 75 BR_REGISTER(Transform, IUMTransform)
76 76  
  77 +/* Kernel Density Estimator */
  78 +struct KDE
  79 +{
  80 + float min, max;
  81 + QList<float> bins;
  82 +
  83 + KDE() : min(0), max(1) {}
  84 + KDE(const QList<float> &scores)
  85 + {
  86 + Common::MinMax(scores, &min, &max);
  87 + double h = Common::KernelDensityBandwidth(scores);
  88 + const int size = 255;
  89 + bins.reserve(size);
  90 + for (int i=0; i<size; i++)
  91 + bins.append(Common::KernelDensityEstimation(scores, min + (max-min)*i/(size-1), h));
  92 + }
  93 +
  94 + float operator()(float score) const
  95 + {
  96 + if (score <= min) return bins.first();
  97 + if (score >= max) return bins.last();
  98 + const float x = (score-min)/(max-min)*bins.size();
  99 + const float y1 = bins[floor(x)];
  100 + const float y2 = bins[ceil(x)];
  101 + return y1 + (y2-y1)*(x-floor(x));
  102 + }
  103 +};
  104 +
  105 +QDataStream &operator<<(QDataStream &stream, const KDE &kde)
  106 +{
  107 + return stream << kde.min << kde.max << kde.bins;
  108 +}
  109 +
  110 +QDataStream &operator>>(QDataStream &stream, KDE &kde)
  111 +{
  112 + return stream >> kde.min >> kde.max >> kde.bins;
  113 +}
  114 +
  115 +/* Non-match Probability */
  116 +struct NMP
  117 +{
  118 + KDE genuine, impostor;
  119 + NMP() {}
  120 + NMP(const QList<float> &genuineScores, const QList<float> &impostorScores)
  121 + : genuine(genuineScores), impostor(impostorScores) {}
  122 + float operator()(float score) const { float g = genuine(score); return g / (impostor(score) + g); }
  123 +};
  124 +
  125 +QDataStream &operator<<(QDataStream &stream, const NMP &nmp)
  126 +{
  127 + return stream << nmp.genuine << nmp.impostor;
  128 +}
  129 +
  130 +QDataStream &operator>>(QDataStream &stream, NMP &nmp)
  131 +{
  132 + return stream >> nmp.genuine >> nmp.impostor;
  133 +}
  134 +
  135 +/*!
  136 + * \ingroup distances
  137 + * \brief Impostor Uniqueness Distance \cite klare12
  138 + * \author Josh Klontz \cite jklontz
  139 + */
  140 +class IUMDistance : public Distance
  141 +{
  142 + Q_OBJECT
  143 + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  144 + BR_PROPERTY(br::Distance*, distance, Factory<Distance>::make(".Dist(L2)"))
  145 +
  146 + QList<NMP> nmps;
  147 +
  148 + void train(const TemplateList &src)
  149 + {
  150 + distance->train(src);
  151 +
  152 + const QList<float> labels = src.labels<float>();
  153 + QScopedPointer<MatrixOutput> memoryOutput(dynamic_cast<MatrixOutput*>(Output::make(".Matrix", FileList(src.size()), FileList(src.size()))));
  154 + distance->compare(src, src, memoryOutput.data());
  155 +
  156 + const int IUM_Bins = 3;
  157 + QVector< QList<float> > genuineScores(IUM_Bins), impostorScores(IUM_Bins);
  158 + for (int i=0; i<src.size(); i++)
  159 + for (int j=0; j<i; j++) {
  160 + const float score = memoryOutput.data()->data.at<float>(i, j);
  161 + const int bin = src[i].file.getInt("IUM_Bin");
  162 + if (labels[i] == labels[j]) genuineScores[bin].append(score);
  163 + else impostorScores[bin].append(score);
  164 + }
  165 +
  166 + for (int i=0; i<IUM_Bins; i++)
  167 + nmps.append(NMP(genuineScores[i], impostorScores[i]));
  168 + }
  169 +
  170 + float _compare(const Template &target, const Template &query) const
  171 + {
  172 + return nmps[query.file.getInt("IUM_Bin")](distance->compare(target, query));
  173 + }
  174 +
  175 + void store(QDataStream &stream) const
  176 + {
  177 + distance->store(stream);
  178 + stream << nmps;
  179 + }
  180 +
  181 + void load(QDataStream &stream)
  182 + {
  183 + distance->load(stream);
  184 + stream >> nmps;
  185 + }
  186 +};
  187 +
  188 +BR_REGISTER(Distance, IUMDistance)
  189 +
77 190 } // namespace br
78 191  
79 192 #include "quality.moc"
... ...