Commit 0fb1cef2dfc9eea657ee80b6730aba9a54e07994
1 parent
4b34805a
finished IUM draft
Showing
3 changed files
with
115 additions
and
46 deletions
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 &target, const Template &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" | ... | ... |