Commit dff99e3e7bc9947e4820a099e2312b6b8a8015f2

Authored by Brendan Klare
2 parents a3d263f0 dc2f8017

Merge branch 'master' of https://github.com/biometrics/openbr

3rdparty/stasm4.0.0/stasm/asm.cpp
@@ -5,8 +5,6 @@ @@ -5,8 +5,6 @@
5 #include "stasm.h" 5 #include "stasm.h"
6 #include "stasmhash.h" 6 #include "stasmhash.h"
7 7
8 -#include <QDebug>  
9 -  
10 namespace stasm 8 namespace stasm
11 { 9 {
12 static void TraceShape( // write an image file showing current shape on the image 10 static void TraceShape( // write an image file showing current shape on the image
3rdparty/stasm4.0.0/stasm/faceroi.cpp
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 // Copyright (C) 2005-2013, Stephen Milborrow 3 // Copyright (C) 2005-2013, Stephen Milborrow
4 4
5 #include "stasm.h" 5 #include "stasm.h"
6 -#include <QDebug>  
7 6
8 namespace stasm 7 namespace stasm
9 { 8 {
3rdparty/stasm4.0.0/stasm/pinstart.cpp
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 // Copyright (C) 2005-2013, Stephen Milborrow 3 // Copyright (C) 2005-2013, Stephen Milborrow
4 4
5 #include "stasm.h" 5 #include "stasm.h"
6 -#include <QDebug>  
7 6
8 namespace stasm 7 namespace stasm
9 { 8 {
3rdparty/stasm4.0.0/stasm/stasm_lib.cpp
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 // Copyright (C) 2005-2013, Stephen Milborrow 3 // Copyright (C) 2005-2013, Stephen Milborrow
4 4
5 #include "stasm.h" 5 #include "stasm.h"
6 -#include <QDebug>  
7 6
8 using namespace stasm; 7 using namespace stasm;
9 8
app/br/br.cpp
@@ -138,8 +138,8 @@ public: @@ -138,8 +138,8 @@ public:
138 check(parc >= 2 && parc <= 4, "Incorrect parameter count for 'evalClassification'."); 138 check(parc >= 2 && parc <= 4, "Incorrect parameter count for 'evalClassification'.");
139 br_eval_classification(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? parv[3] : ""); 139 br_eval_classification(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? parv[3] : "");
140 } else if (!strcmp(fun, "evalClustering")) { 140 } else if (!strcmp(fun, "evalClustering")) {
141 - check(parc == 2, "Incorrect parameter count for 'evalClustering'.");  
142 - br_eval_clustering(parv[0], parv[1]); 141 + check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'evalClustering'.");
  142 + br_eval_clustering(parv[0], parv[1], parc == 3 ? parv[2] : "");
143 } else if (!strcmp(fun, "evalDetection")) { 143 } else if (!strcmp(fun, "evalDetection")) {
144 check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'evalDetection'."); 144 check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'evalDetection'.");
145 br_eval_detection(parv[0], parv[1], parc == 3 ? parv[2] : ""); 145 br_eval_detection(parv[0], parv[1], parc == 3 ? parv[2] : "");
openbr/core/cluster.cpp
@@ -100,7 +100,9 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats) @@ -100,7 +100,9 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats)
100 int currentRows = -1; 100 int currentRows = -1;
101 int columnOffset = 0; 101 int columnOffset = 0;
102 for (int j=0; j<numGalleries; j++) { 102 for (int j=0; j<numGalleries; j++) {
103 - cv::Mat m = BEE::readMat(simmats[i*numGalleries+j]); 103 + QScopedPointer<br::Format> format(br::Factory<br::Format>::make(simmats[i*numGalleries+j]));
  104 + br::Template t = format->read();
  105 + cv::Mat m = t.m();
104 if (j==0) { 106 if (j==0) {
105 currentRows = m.rows; 107 currentRows = m.rows;
106 allNeighbors.resize(currentRows); 108 allNeighbors.resize(currentRows);
@@ -115,8 +117,9 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats) @@ -115,8 +117,9 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats)
115 float val = m.at<float>(k,l); 117 float val = m.at<float>(k,l);
116 if ((i==j) && (k==l)) continue; // Skips self-similarity scores 118 if ((i==j) && (k==l)) continue; // Skips self-similarity scores
117 119
118 - if ((val != -std::numeric_limits<float>::infinity()) &&  
119 - (val != std::numeric_limits<float>::infinity())) { 120 + if (val != -std::numeric_limits<float>::max()
  121 + && val != -std::numeric_limits<float>::infinity()
  122 + && val != std::numeric_limits<float>::infinity()) {
120 globalMax = std::max(globalMax, val); 123 globalMax = std::max(globalMax, val);
121 globalMin = std::min(globalMin, val); 124 globalMin = std::min(globalMin, val);
122 } 125 }
@@ -157,7 +160,7 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats) @@ -157,7 +160,7 @@ Neighborhood getNeighborhood(const QStringList &amp;simmats)
157 // Zhu et al. "A Rank-Order Distance based Clustering Algorithm for Face Tagging", CVPR 2011 160 // Zhu et al. "A Rank-Order Distance based Clustering Algorithm for Face Tagging", CVPR 2011
158 br::Clusters br::ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv) 161 br::Clusters br::ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv)
159 { 162 {
160 - qDebug("Clustering %d simmat(s)", simmats.size()); 163 + qDebug("Clustering %d simmat(s), aggressiveness %f", simmats.size(), aggressiveness);
161 164
162 // Read in gallery parts, keeping top neighbors of each template 165 // Read in gallery parts, keeping top neighbors of each template
163 Neighborhood neighborhood = getNeighborhood(simmats); 166 Neighborhood neighborhood = getNeighborhood(simmats);
@@ -275,13 +278,14 @@ float jaccardIndex(const QVector&lt;int&gt; &amp;indicesA, const QVector&lt;int&gt; &amp;indicesB) @@ -275,13 +278,14 @@ float jaccardIndex(const QVector&lt;int&gt; &amp;indicesA, const QVector&lt;int&gt; &amp;indicesB)
275 278
276 // Evaluates clustering algorithms based on metrics described in 279 // Evaluates clustering algorithms based on metrics described in
277 // Santo Fortunato "Community detection in graphs", Physics Reports 486 (2010) 280 // Santo Fortunato "Community detection in graphs", Physics Reports 486 (2010)
278 -void br::EvalClustering(const QString &csv, const QString &input) 281 +void br::EvalClustering(const QString &csv, const QString &input, QString truth_property)
279 { 282 {
  283 + if (truth_property.isEmpty())
  284 + truth_property = "Label";
280 qDebug("Evaluating %s against %s", qPrintable(csv), qPrintable(input)); 285 qDebug("Evaluating %s against %s", qPrintable(csv), qPrintable(input));
281 286
282 - // We assume clustering algorithms store assigned cluster labels as integers (since the clusters are  
283 - // not named). Direct use of ClusterID is not general -cao  
284 - QList<int> labels = File::get<int>(TemplateList::fromGallery(input), "ClusterID"); 287 + TemplateList tList = TemplateList::fromGallery(input);
  288 + QList<int> labels = tList.indexProperty(truth_property);
285 289
286 QHash<int, int> labelToIndex; 290 QHash<int, int> labelToIndex;
287 int nClusters = 0; 291 int nClusters = 0;
openbr/core/cluster.h
@@ -28,7 +28,7 @@ namespace br @@ -28,7 +28,7 @@ namespace br
28 typedef QVector<Cluster> Clusters; 28 typedef QVector<Cluster> Clusters;
29 29
30 Clusters ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv); 30 Clusters ClusterGallery(const QStringList &simmats, float aggressiveness, const QString &csv);
31 - void EvalClustering(const QString &csv, const QString &input); 31 + void EvalClustering(const QString &csv, const QString &input, QString truth_property);
32 32
33 Clusters ReadClusters(const QString &csv); 33 Clusters ReadClusters(const QString &csv);
34 void WriteClusters(const Clusters &clusters, const QString &csv); 34 void WriteClusters(const Clusters &clusters, const QString &csv);
openbr/core/core.cpp
@@ -21,14 +21,16 @@ @@ -21,14 +21,16 @@
21 #include "qtutils.h" 21 #include "qtutils.h"
22 #include "../plugins/openbr_internal.h" 22 #include "../plugins/openbr_internal.h"
23 23
24 -using namespace br; 24 +namespace br {
25 25
26 -/**** ALGORITHM_CORE ****/  
27 struct AlgorithmCore 26 struct AlgorithmCore
28 { 27 {
29 QSharedPointer<Transform> transform; 28 QSharedPointer<Transform> transform;
30 QSharedPointer<Distance> distance; 29 QSharedPointer<Distance> distance;
31 30
  31 + QString transformString;
  32 + QString distanceString;
  33 +
32 AlgorithmCore(const QString &name) 34 AlgorithmCore(const QString &name)
33 { 35 {
34 this->name = name; 36 this->name = name;
@@ -134,6 +136,8 @@ struct AlgorithmCore @@ -134,6 +136,8 @@ struct AlgorithmCore
134 } 136 }
135 TemplateList data(TemplateList::fromGallery(input)); 137 TemplateList data(TemplateList::fromGallery(input));
136 138
  139 + bool multiProcess = Globals->file.getBool("multiProcess", false);
  140 +
137 if (gallery.contains("append")) 141 if (gallery.contains("append"))
138 { 142 {
139 // Remove any templates which are already in the gallery 143 // Remove any templates which are already in the gallery
@@ -155,20 +159,27 @@ struct AlgorithmCore @@ -155,20 +159,27 @@ struct AlgorithmCore
155 Globals->currentStep = 0; 159 Globals->currentStep = 0;
156 Globals->totalSteps = data.length(); 160 Globals->totalSteps = data.length();
157 161
158 - // Trust me, this makes complete sense.  
159 - // We're just going to make a pipe with a placeholder first transform  
160 - QString pipeDesc = "Identity+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard";  
161 - QScopedPointer<Transform> basePipe(Transform::make(pipeDesc,NULL)); 162 + QScopedPointer<Transform> basePipe;
162 163
163 - CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(basePipe.data());  
164 - if (downcast == NULL)  
165 - qFatal("downcast failed?"); 164 + if (!multiProcess)
  165 + {
  166 + QString pipeDesc = "Identity+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard";
  167 + basePipe.reset(Transform::make(pipeDesc,NULL));
  168 + CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(basePipe.data());
  169 + if (downcast == NULL)
  170 + qFatal("downcast failed?");
166 171
167 - // replace that placeholder with the current algorithm  
168 - downcast->transforms[0] = this->transform.data(); 172 + // replace that placeholder with the current algorithm
  173 + downcast->transforms[0] = this->transform.data();
169 174
170 - // call init on the pipe to collapse the algorithm (if its top level is a pipe)  
171 - downcast->init(); 175 + // call init on the pipe to collapse the algorithm (if its top level is a pipe)
  176 + downcast->init();
  177 + }
  178 + else
  179 + {
  180 + QString pipeDesc = "ProcessWrapper("+transformString+")"+"+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard";
  181 + basePipe.reset(Transform::make(pipeDesc,NULL));
  182 + }
172 183
173 // Next, we make a Stream (with placeholder transform) 184 // Next, we make a Stream (with placeholder transform)
174 QString streamDesc = "Stream(Identity, readMode=DistributeFrames)"; 185 QString streamDesc = "Stream(Identity, readMode=DistributeFrames)";
@@ -176,7 +187,7 @@ struct AlgorithmCore @@ -176,7 +187,7 @@ struct AlgorithmCore
176 WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data()); 187 WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data());
177 188
178 // replace that placeholder with the pipe we built 189 // replace that placeholder with the pipe we built
179 - wrapper->transform = downcast; 190 + wrapper->transform = basePipe.data();
180 191
181 // and get the final stream's stages by reinterpreting the pipe. Perfectly straightforward. 192 // and get the final stream's stages by reinterpreting the pipe. Perfectly straightforward.
182 wrapper->init(); 193 wrapper->init();
@@ -241,17 +252,14 @@ struct AlgorithmCore @@ -241,17 +252,14 @@ struct AlgorithmCore
241 dummyTarget.append(targets[0]); 252 dummyTarget.append(targets[0]);
242 QScopedPointer<Output> realOutput(Output::make(output, dummyTarget, queryFiles)); 253 QScopedPointer<Output> realOutput(Output::make(output, dummyTarget, queryFiles));
243 254
244 - // Some outputs assume Globals->blockSize is a real thing, of course we have no interest in it.  
245 - int old_block_size = Globals->blockSize;  
246 - Globals->blockSize = INT_MAX; 255 + realOutput->set_blockRows(INT_MAX);
  256 + realOutput->set_blockCols(INT_MAX);
247 realOutput->setBlock(0,0); 257 realOutput->setBlock(0,0);
248 for (int i=0; i < queries.length(); i++) 258 for (int i=0; i < queries.length(); i++)
249 { 259 {
250 float res = distance->compare(queries[i], targets[i]); 260 float res = distance->compare(queries[i], targets[i]);
251 realOutput->setRelative(res, 0,i); 261 realOutput->setRelative(res, 0,i);
252 } 262 }
253 -  
254 - Globals->blockSize = old_block_size;  
255 } 263 }
256 264
257 void deduplicate(const File &inputGallery, const File &outputGallery, const float threshold) 265 void deduplicate(const File &inputGallery, const File &outputGallery, const float threshold)
@@ -310,7 +318,11 @@ struct AlgorithmCore @@ -310,7 +318,11 @@ struct AlgorithmCore
310 qPrintable(queryGallery.flat()), 318 qPrintable(queryGallery.flat()),
311 output.isNull() ? "" : qPrintable(" to " + output.flat())); 319 output.isNull() ? "" : qPrintable(" to " + output.flat()));
312 320
313 - if (output.exists() && output.get<bool>("cache", false)) return; 321 + // Escape hatch for distances that need to operate directly on the gallery files
  322 + if (distance->compare(targetGallery, queryGallery, output))
  323 + return;
  324 +
  325 + if (output.exists() && output.get<bool>("cache")) return;
314 if (queryGallery == ".") queryGallery = targetGallery; 326 if (queryGallery == ".") queryGallery = targetGallery;
315 327
316 QScopedPointer<Gallery> t, q; 328 QScopedPointer<Gallery> t, q;
@@ -327,11 +339,13 @@ struct AlgorithmCore @@ -327,11 +339,13 @@ struct AlgorithmCore
327 File splitOutputFile = output.name.arg(i); 339 File splitOutputFile = output.name.arg(i);
328 outputFiles.append(splitOutputFile); 340 outputFiles.append(splitOutputFile);
329 } 341 }
  342 + } else {
  343 + outputFiles.append(output);
330 } 344 }
331 - else outputFiles.append(output);  
332 345
333 QList<Output*> outputs; 346 QList<Output*> outputs;
334 - foreach (const File &outputFile, outputFiles) outputs.append(Output::make(outputFile, targetFiles, queryFiles)); 347 + foreach (const File &outputFile, outputFiles)
  348 + outputs.append(Output::make(outputFile, targetFiles, queryFiles));
335 349
336 if (distance.isNull()) qFatal("Null distance."); 350 if (distance.isNull()) qFatal("Null distance.");
337 Globals->currentStep = 0; 351 Globals->currentStep = 0;
@@ -361,7 +375,6 @@ struct AlgorithmCore @@ -361,7 +375,6 @@ struct AlgorithmCore
361 else targetPartitions.append(targets); 375 else targetPartitions.append(targets);
362 376
363 outputs[i]->setBlock(queryBlock, targetBlock); 377 outputs[i]->setBlock(queryBlock, targetBlock);
364 -  
365 distance->compare(targetPartitions[i], queryPartitions[i], outputs[i]); 378 distance->compare(targetPartitions[i], queryPartitions[i], outputs[i]);
366 379
367 Globals->currentStep += double(targets.size()) * double(queries.size()); 380 Globals->currentStep += double(targets.size()) * double(queries.size());
@@ -407,14 +420,22 @@ private: @@ -407,14 +420,22 @@ private:
407 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format."); 420 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format.");
408 //! [Parsing the algorithm description] 421 //! [Parsing the algorithm description]
409 422
  423 + transformString = words[0];
  424 +
410 425
411 //! [Creating the template generation and comparison methods] 426 //! [Creating the template generation and comparison methods]
412 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); 427 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL));
413 - if (words.size() > 1) distance = QSharedPointer<Distance>(Distance::make(words[1], NULL)); 428 + if (words.size() > 1) {
  429 + distance = QSharedPointer<Distance>(Distance::make(words[1], NULL));
  430 + distanceString = words[1];
  431 + }
414 //! [Creating the template generation and comparison methods] 432 //! [Creating the template generation and comparison methods]
415 } 433 }
416 }; 434 };
417 435
  436 +} // namespace br
  437 +
  438 +using namespace br;
418 439
419 class AlgorithmManager : public Initializer 440 class AlgorithmManager : public Initializer
420 { 441 {
openbr/core/plot.cpp
@@ -247,7 +247,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -247,7 +247,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
247 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) + 247 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
248 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) + 248 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
249 QString(" + scale_x_log10(labels=trans_format(\"log10\", math_format()))") + 249 QString(" + scale_x_log10(labels=trans_format(\"log10\", math_format()))") +
250 - (rocOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent, limits=%3)").arg("c"+QtUtils::toString(rocOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) + 250 + (rocOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent) + coord_cartesian(ylim=%1)").arg("c"+QtUtils::toString(rocOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) +
251 QString(" + annotation_logticks(sides=\"b\")") + 251 QString(" + annotation_logticks(sides=\"b\")") +
252 QString(" + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1)," 252 QString(" + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1),"
253 " legend.position=%2, legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = \"gray\"), panel.grid.minor = element_line(colour = \"gray\", linetype = \"dashed\"), legend.text = element_text(size = %1))\n\n").arg(QString::number(rocOpts.get<float>("textSize",12)), rocOpts.contains("legendPosition") ? "c"+QtUtils::toString(rocOpts.get<QPointF>("legendPosition")) : "'right'"))); 253 " legend.position=%2, legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = \"gray\"), panel.grid.minor = element_line(colour = \"gray\", linetype = \"dashed\"), legend.text = element_text(size = %1))\n\n").arg(QString::number(rocOpts.get<float>("textSize",12)), rocOpts.contains("legendPosition") ? "c"+QtUtils::toString(rocOpts.get<QPointF>("legendPosition")) : "'right'")));
@@ -273,7 +273,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -273,7 +273,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
273 (minimalist ? "" : " + scale_x_log10(labels=c(1,5,10,50,100), breaks=c(1,5,10,50,100)) + annotation_logticks(sides=\"b\")") + 273 (minimalist ? "" : " + scale_x_log10(labels=c(1,5,10,50,100), breaks=c(1,5,10,50,100)) + annotation_logticks(sides=\"b\")") +
274 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) + 274 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
275 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) + 275 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
276 - (cmcOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent, limits=%3)").arg("c"+QtUtils::toString(cmcOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) + 276 + (cmcOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent) + coord_cartesian(ylim=%1)").arg("c"+QtUtils::toString(cmcOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) +
277 QString(" + theme_minimal() + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1)," 277 QString(" + theme_minimal() + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1),"
278 " legend.position=%2, legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = \"gray\"), panel.grid.minor = element_line(colour = \"gray\", linetype = \"dashed\"), legend.text = element_text(size = %1))\n\n").arg(QString::number(cmcOpts.get<float>("textSize",12)), cmcOpts.contains("legendPosition") ? "c"+QtUtils::toString(cmcOpts.get<QPointF>("legendPosition")) : "'right'"))); 278 " legend.position=%2, legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = \"gray\"), panel.grid.minor = element_line(colour = \"gray\", linetype = \"dashed\"), legend.text = element_text(size = %1))\n\n").arg(QString::number(cmcOpts.get<float>("textSize",12)), cmcOpts.contains("legendPosition") ? "c"+QtUtils::toString(cmcOpts.get<QPointF>("legendPosition")) : "'right'")));
279 279
openbr/openbr.cpp
@@ -109,9 +109,9 @@ void br_eval_classification(const char *predicted_gallery, const char *truth_gal @@ -109,9 +109,9 @@ void br_eval_classification(const char *predicted_gallery, const char *truth_gal
109 EvalClassification(predicted_gallery, truth_gallery, predicted_property, truth_property); 109 EvalClassification(predicted_gallery, truth_gallery, predicted_property, truth_property);
110 } 110 }
111 111
112 -void br_eval_clustering(const char *csv, const char *gallery) 112 +void br_eval_clustering(const char *csv, const char *gallery, const char * truth_property)
113 { 113 {
114 - EvalClustering(csv, gallery); 114 + EvalClustering(csv, gallery, truth_property);
115 } 115 }
116 116
117 float br_eval_detection(const char *predicted_gallery, const char *truth_gallery, const char *csv) 117 float br_eval_detection(const char *predicted_gallery, const char *truth_gallery, const char *csv)
@@ -435,7 +435,14 @@ br_template_list br_load_from_gallery(br_gallery gallery) @@ -435,7 +435,14 @@ br_template_list br_load_from_gallery(br_gallery gallery)
435 return (br_template_list)tl; 435 return (br_template_list)tl;
436 } 436 }
437 437
438 -void br_add_to_gallery(br_gallery gallery, br_template_list tl) 438 +void br_add_template_to_gallery(br_gallery gallery, br_template tmpl)
  439 +{
  440 + Gallery *gal = reinterpret_cast<Gallery*>(gallery);
  441 + Template *t = reinterpret_cast<Template*>(tmpl);
  442 + gal->write(*t);
  443 +}
  444 +
  445 +void br_add_template_list_to_gallery(br_gallery gallery, br_template_list tl)
439 { 446 {
440 Gallery *gal = reinterpret_cast<Gallery*>(gallery); 447 Gallery *gal = reinterpret_cast<Gallery*>(gallery);
441 TemplateList *realTL = reinterpret_cast<TemplateList*>(tl); 448 TemplateList *realTL = reinterpret_cast<TemplateList*>(tl);
openbr/openbr.h
@@ -167,9 +167,10 @@ BR_EXPORT void br_eval_classification(const char *predicted_gallery, const char @@ -167,9 +167,10 @@ BR_EXPORT void br_eval_classification(const char *predicted_gallery, const char
167 * \brief Evaluates and prints clustering accuracy to the terminal. 167 * \brief Evaluates and prints clustering accuracy to the terminal.
168 * \param csv The cluster results file. 168 * \param csv The cluster results file.
169 * \param gallery The br::Gallery used to generate the \ref simmat that was clustered. 169 * \param gallery The br::Gallery used to generate the \ref simmat that was clustered.
  170 + * \param truth_property (Optional) which metadata key to use from <i>gallery</i/>, defaults to Label
170 * \see br_cluster 171 * \see br_cluster
171 */ 172 */
172 -BR_EXPORT void br_eval_clustering(const char *csv, const char *gallery); 173 +BR_EXPORT void br_eval_clustering(const char *csv, const char *gallery, const char * truth_property);
173 174
174 /*! 175 /*!
175 * \brief Evaluates and prints detection accuracy to terminal. 176 * \brief Evaluates and prints detection accuracy to terminal.
@@ -562,9 +563,13 @@ BR_EXPORT br_gallery br_make_gallery(const char *gallery); @@ -562,9 +563,13 @@ BR_EXPORT br_gallery br_make_gallery(const char *gallery);
562 */ 563 */
563 BR_EXPORT br_template_list br_load_from_gallery(br_gallery gallery); 564 BR_EXPORT br_template_list br_load_from_gallery(br_gallery gallery);
564 /*! 565 /*!
  566 + * \brief Write a br::Template to the br::Gallery on disk.
  567 + */
  568 +BR_EXPORT void br_add_template_to_gallery(br_gallery gallery, br_template tmpl);
  569 +/*!
565 * \brief Write a br::TemplateList to the br::Gallery on disk. 570 * \brief Write a br::TemplateList to the br::Gallery on disk.
566 */ 571 */
567 -BR_EXPORT void br_add_to_gallery(br_gallery gallery, br_template_list tl); 572 +BR_EXPORT void br_add_template_list_to_gallery(br_gallery gallery, br_template_list tl);
568 /*! 573 /*!
569 * \brief Close the br::Gallery. 574 * \brief Close the br::Gallery.
570 */ 575 */
openbr/openbr_plugin.cpp
@@ -408,7 +408,7 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery) @@ -408,7 +408,7 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery)
408 QStringList labels; 408 QStringList labels;
409 for (int i=newTemplates.size()-1; i>=0; i--) { 409 for (int i=newTemplates.size()-1; i>=0; i--) {
410 newTemplates[i].file.set("Index", i+templates.size()); 410 newTemplates[i].file.set("Index", i+templates.size());
411 - newTemplates[i].file.set("Gallery", gallery.name); 411 + newTemplates[i].file.set("Gallery", file.name);
412 412
413 QString label = newTemplates.at(i).file.get<QString>("Label"); 413 QString label = newTemplates.at(i).file.get<QString>("Label");
414 // Have we seen this subject before? 414 // Have we seen this subject before?
@@ -436,7 +436,7 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery) @@ -436,7 +436,7 @@ TemplateList TemplateList::fromGallery(const br::File &amp;gallery)
436 } else { 436 } else {
437 for (int i=newTemplates.size()-1; i>=0; i--) { 437 for (int i=newTemplates.size()-1; i>=0; i--) {
438 newTemplates[i].file.set("Index", i+templates.size()); 438 newTemplates[i].file.set("Index", i+templates.size());
439 - newTemplates[i].file.set("Gallery", gallery.name); 439 + newTemplates[i].file.set("Gallery", file.name);
440 440
441 if (crossValidate > 0) { 441 if (crossValidate > 0) {
442 if (newTemplates[i].file.getBool("duplicatePartitions")) { 442 if (newTemplates[i].file.getBool("duplicatePartitions")) {
@@ -1101,13 +1101,19 @@ void Output::initialize(const FileList &amp;targetFiles, const FileList &amp;queryFiles) @@ -1101,13 +1101,19 @@ void Output::initialize(const FileList &amp;targetFiles, const FileList &amp;queryFiles)
1101 { 1101 {
1102 this->targetFiles = targetFiles; 1102 this->targetFiles = targetFiles;
1103 this->queryFiles = queryFiles; 1103 this->queryFiles = queryFiles;
  1104 + if (this->blockRows == -1)
  1105 + blockRows = Globals->blockSize;
  1106 +
  1107 + if (this->blockCols == -1)
  1108 + blockCols = Globals->blockSize;
  1109 +
1104 selfSimilar = (queryFiles == targetFiles) && (targetFiles.size() > 1) && (queryFiles.size() > 1); 1110 selfSimilar = (queryFiles == targetFiles) && (targetFiles.size() > 1) && (queryFiles.size() > 1);
1105 } 1111 }
1106 1112
1107 void Output::setBlock(int rowBlock, int columnBlock) 1113 void Output::setBlock(int rowBlock, int columnBlock)
1108 { 1114 {
1109 - offset = QPoint((columnBlock == -1) ? 0 : Globals->blockSize*columnBlock,  
1110 - (rowBlock == -1) ? 0 : Globals->blockSize*rowBlock); 1115 + offset = QPoint((columnBlock == -1) ? 0 : blockCols*columnBlock,
  1116 + (rowBlock == -1) ? 0 : blockRows*rowBlock);
1111 if (!next.isNull()) next->setBlock(rowBlock, columnBlock); 1117 if (!next.isNull()) next->setBlock(rowBlock, columnBlock);
1112 } 1118 }
1113 1119
openbr/openbr_plugin.h
@@ -996,6 +996,11 @@ class BR_EXPORT Output : public Object @@ -996,6 +996,11 @@ class BR_EXPORT Output : public Object
996 Q_OBJECT 996 Q_OBJECT
997 997
998 public: 998 public:
  999 + Q_PROPERTY(int blockRows READ get_blockRows WRITE set_blockRows RESET reset_blockRows STORED false)
  1000 + Q_PROPERTY(int blockCols READ get_blockCols WRITE set_blockCols RESET reset_blockCols STORED false)
  1001 + BR_PROPERTY(int, blockRows, -1)
  1002 + BR_PROPERTY(int, blockCols, -1)
  1003 +
999 FileList targetFiles; /*!< \brief List of files representing the gallery templates. */ 1004 FileList targetFiles; /*!< \brief List of files representing the gallery templates. */
1000 FileList queryFiles; /*!< \brief List of files representing the probe templates. */ 1005 FileList queryFiles; /*!< \brief List of files representing the probe templates. */
1001 bool selfSimilar; /*!< \brief \c true if the \em targetFiles == \em queryFiles, \c false otherwise. */ 1006 bool selfSimilar; /*!< \brief \c true if the \em targetFiles == \em queryFiles, \c false otherwise. */
@@ -1074,9 +1079,11 @@ public: @@ -1074,9 +1079,11 @@ public:
1074 */ 1079 */
1075 class BR_EXPORT Gallery : public Object 1080 class BR_EXPORT Gallery : public Object
1076 { 1081 {
1077 - Q_OBJECT  
1078 - 1082 + Q_OBJECT
1079 public: 1083 public:
  1084 + Q_PROPERTY(int readBlockSize READ get_readBlockSize WRITE set_readBlockSize RESET reset_readBlockSize STORED false)
  1085 + BR_PROPERTY(int, readBlockSize, Globals->blockSize)
  1086 +
1080 virtual ~Gallery() {} 1087 virtual ~Gallery() {}
1081 TemplateList read(); /*!< \brief Retrieve all the stored templates. */ 1088 TemplateList read(); /*!< \brief Retrieve all the stored templates. */
1082 FileList files(); /*!< \brief Retrieve all the stored template files. */ 1089 FileList files(); /*!< \brief Retrieve all the stored template files. */
@@ -1324,6 +1331,10 @@ protected: @@ -1324,6 +1331,10 @@ protected:
1324 1331
1325 private: 1332 private:
1326 virtual void compareBlock(const TemplateList &target, const TemplateList &query, Output *output, int targetOffset, int queryOffset) const; 1333 virtual void compareBlock(const TemplateList &target, const TemplateList &query, Output *output, int targetOffset, int queryOffset) const;
  1334 +
  1335 + friend struct AlgorithmCore;
  1336 + virtual bool compare(const File &targetGallery, const File &queryGallery, const File &output) const /*!< \brief Escape hatch for algorithms that need customized file I/O during comparison. */
  1337 + { (void) targetGallery; (void) queryGallery; (void) output; return false; }
1327 }; 1338 };
1328 1339
1329 /*! 1340 /*!
openbr/plugins/algorithms.cpp
@@ -64,6 +64,7 @@ class AlgorithmsInitializer : public Initializer @@ -64,6 +64,7 @@ class AlgorithmsInitializer : public Initializer
64 Globals->abbreviations.insert("SmallSIFT", "Open+LimitSize(512)+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); 64 Globals->abbreviations.insert("SmallSIFT", "Open+LimitSize(512)+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)");
65 Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)"); 65 Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)");
66 Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)+Expand+EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2"); 66 Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)+Expand+EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2");
  67 + Globals->abbreviations.insert("ImageSimilarity", "Open+EnsureChannels(3)+Resize(256,256)+SplitChannels+RectRegions(64,64,64,64)+Hist(256,0,8)+Cat:NegativeLogPlusOne(L2)");
67 Globals->abbreviations.insert("ImageClassification", "Open+CropSquare+LimitSize(256)+Cvt(Gray)+Gradient+Bin(0,360,9,true)+Merge+Integral+RecursiveIntegralSampler(4,2,8,Singleton(KMeans(256)))+Cat+CvtFloat+Hist(256)+KNN(5,Dist(L1),false,5)+Rename(KNN,Subject)"); 68 Globals->abbreviations.insert("ImageClassification", "Open+CropSquare+LimitSize(256)+Cvt(Gray)+Gradient+Bin(0,360,9,true)+Merge+Integral+RecursiveIntegralSampler(4,2,8,Singleton(KMeans(256)))+Cat+CvtFloat+Hist(256)+KNN(5,Dist(L1),false,5)+Rename(KNN,Subject)");
68 Globals->abbreviations.insert("TanTriggs", "Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)"); 69 Globals->abbreviations.insert("TanTriggs", "Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)");
69 70
openbr/plugins/distance.cpp
@@ -460,12 +460,13 @@ BR_REGISTER(Distance, SumDistance) @@ -460,12 +460,13 @@ BR_REGISTER(Distance, SumDistance)
460 class GalleryCompareTransform : public Transform 460 class GalleryCompareTransform : public Transform
461 { 461 {
462 Q_OBJECT 462 Q_OBJECT
463 - Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED false) 463 + Q_PROPERTY(QString distanceAlgorithm READ get_distanceAlgorithm WRITE set_distanceAlgorithm RESET reset_distanceAlgorithm STORED false)
464 Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) 464 Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false)
465 - BR_PROPERTY(br::Distance*, distance, NULL) 465 + BR_PROPERTY(QString, distanceAlgorithm, "")
466 BR_PROPERTY(QString, galleryName, "") 466 BR_PROPERTY(QString, galleryName, "")
467 467
468 TemplateList gallery; 468 TemplateList gallery;
  469 + QSharedPointer<Distance> distance;
469 470
470 void project(const Template &src, Template &dst) const 471 void project(const Template &src, Template &dst) const
471 { 472 {
@@ -479,8 +480,13 @@ class GalleryCompareTransform : public Transform @@ -479,8 +480,13 @@ class GalleryCompareTransform : public Transform
479 480
480 void init() 481 void init()
481 { 482 {
482 - if (!galleryName.isEmpty()) 483 + if (!galleryName.isEmpty()) {
483 gallery = TemplateList::fromGallery(galleryName); 484 gallery = TemplateList::fromGallery(galleryName);
  485 + }
  486 + if (!distanceAlgorithm.isEmpty())
  487 + {
  488 + distance = Distance::fromAlgorithm(distanceAlgorithm);
  489 + }
484 } 490 }
485 }; 491 };
486 492
openbr/plugins/gallery.cpp
@@ -123,7 +123,7 @@ class galGallery : public Gallery @@ -123,7 +123,7 @@ class galGallery : public Gallery
123 gallery.seek(0); 123 gallery.seek(0);
124 124
125 TemplateList templates; 125 TemplateList templates;
126 - while ((templates.size() < Globals->blockSize) && !stream.atEnd()) { 126 + while ((templates.size() < readBlockSize) && !stream.atEnd()) {
127 Template m; 127 Template m;
128 stream >> m; 128 stream >> m;
129 templates.append(m); 129 templates.append(m);
@@ -348,8 +348,8 @@ class memGallery : public Gallery @@ -348,8 +348,8 @@ class memGallery : public Gallery
348 MemoryGalleries::aligned[file] = true; 348 MemoryGalleries::aligned[file] = true;
349 } 349 }
350 350
351 - TemplateList templates = MemoryGalleries::galleries[file].mid(block*Globals->blockSize, Globals->blockSize);  
352 - *done = (templates.size() < Globals->blockSize); 351 + TemplateList templates = MemoryGalleries::galleries[file].mid(block*readBlockSize, readBlockSize);
  352 + *done = (templates.size() < readBlockSize);
353 block = *done ? 0 : block+1; 353 block = *done ? 0 : block+1;
354 return templates; 354 return templates;
355 } 355 }
openbr/plugins/independent.cpp
@@ -9,12 +9,13 @@ using namespace cv; @@ -9,12 +9,13 @@ using namespace cv;
9 namespace br 9 namespace br
10 { 10 {
11 11
12 -static TemplateList Downsample(const TemplateList &templates, int classes, int instances, float fraction, const QString & inputVariable) 12 +static TemplateList Downsample(const TemplateList &templates, int classes, int instances, float fraction, const QString & inputVariable, const QStringList &gallery)
13 { 13 {
14 // Return early when no downsampling is required 14 // Return early when no downsampling is required
15 if ((classes == std::numeric_limits<int>::max()) && 15 if ((classes == std::numeric_limits<int>::max()) &&
16 (instances == std::numeric_limits<int>::max()) && 16 (instances == std::numeric_limits<int>::max()) &&
17 - (fraction >= 1)) 17 + (fraction >= 1) &&
  18 + (gallery.isEmpty()))
18 return templates; 19 return templates;
19 20
20 const bool atLeast = instances < 0; 21 const bool atLeast = instances < 0;
@@ -60,6 +61,11 @@ static TemplateList Downsample(const TemplateList &amp;templates, int classes, int i @@ -60,6 +61,11 @@ static TemplateList Downsample(const TemplateList &amp;templates, int classes, int i
60 downsample = downsample.mid(0, downsample.size()*fraction); 61 downsample = downsample.mid(0, downsample.size()*fraction);
61 } 62 }
62 63
  64 + if (!gallery.isEmpty())
  65 + for (int i=downsample.size()-1; i>=0; i--)
  66 + if (!gallery.contains(downsample[i].file.get<QString>("Gallery")))
  67 + downsample.removeAt(i);
  68 +
63 return downsample; 69 return downsample;
64 } 70 }
65 71
@@ -71,11 +77,13 @@ class DownsampleTrainingTransform : public Transform @@ -71,11 +77,13 @@ class DownsampleTrainingTransform : public Transform
71 Q_PROPERTY(int instances READ get_instances WRITE set_instances RESET reset_instances STORED false) 77 Q_PROPERTY(int instances READ get_instances WRITE set_instances RESET reset_instances STORED false)
72 Q_PROPERTY(float fraction READ get_fraction WRITE set_fraction RESET reset_fraction STORED false) 78 Q_PROPERTY(float fraction READ get_fraction WRITE set_fraction RESET reset_fraction STORED false)
73 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) 79 Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  80 + Q_PROPERTY(QStringList gallery READ get_gallery WRITE set_gallery RESET reset_gallery STORED false)
74 BR_PROPERTY(br::Transform*, transform, NULL) 81 BR_PROPERTY(br::Transform*, transform, NULL)
75 BR_PROPERTY(int, classes, std::numeric_limits<int>::max()) 82 BR_PROPERTY(int, classes, std::numeric_limits<int>::max())
76 BR_PROPERTY(int, instances, std::numeric_limits<int>::max()) 83 BR_PROPERTY(int, instances, std::numeric_limits<int>::max())
77 BR_PROPERTY(float, fraction, 1) 84 BR_PROPERTY(float, fraction, 1)
78 BR_PROPERTY(QString, inputVariable, "Label") 85 BR_PROPERTY(QString, inputVariable, "Label")
  86 + BR_PROPERTY(QStringList, gallery, QStringList())
79 87
80 void project(const Template & src, Template & dst) const 88 void project(const Template & src, Template & dst) const
81 { 89 {
@@ -88,7 +96,8 @@ class DownsampleTrainingTransform : public Transform @@ -88,7 +96,8 @@ class DownsampleTrainingTransform : public Transform
88 if (!transform || !transform->trainable) 96 if (!transform || !transform->trainable)
89 return; 97 return;
90 98
91 - TemplateList downsampled = Downsample(data, classes, instances, fraction, inputVariable); 99 + TemplateList downsampled = Downsample(data, classes, instances, fraction, inputVariable, gallery);
  100 +
92 transform->train(downsampled); 101 transform->train(downsampled);
93 } 102 }
94 }; 103 };
openbr/plugins/likely.cmake 0 โ†’ 100644
  1 +set(BR_WITH_LIKELY OFF CACHE BOOL "Build with Likely")
  2 +
  3 +if(${BR_WITH_LIKELY})
  4 + find_package(Likely REQUIRED)
  5 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/likely.cpp)
  6 + set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Likely_LIBS})
  7 +endif()
openbr/plugins/likely.cpp 0 โ†’ 100644
  1 +#include <likely.h>
  2 +#include <likely/opencv.hpp>
  3 +
  4 +#include "openbr_internal.h"
  5 +
  6 +namespace br
  7 +{
  8 +
  9 +/*!
  10 + * \ingroup transforms
  11 + * \brief Generic interface to Likely JIT compiler
  12 + *
  13 + * www.liblikely.org
  14 + * \author Josh Klontz \cite jklontz
  15 + */
  16 +class LikelyTransform : public UntrainableTransform
  17 +{
  18 + Q_OBJECT
  19 + Q_PROPERTY(QString kernel READ get_kernel WRITE set_kernel RESET reset_kernel STORED false)
  20 + BR_PROPERTY(QString, kernel, "")
  21 +
  22 + likely_function function;
  23 +
  24 + void init()
  25 + {
  26 + likely_ast ast = likely_ast_from_string(qPrintable(kernel));
  27 + likely_env env = likely_new_env();
  28 + function = likely_compile(ast, env, likely_type_null);
  29 + likely_release_env(env);
  30 + likely_release_ast(ast);
  31 + }
  32 +
  33 + void project(const Template &src, Template &dst) const
  34 + {
  35 + likely_const_mat srcl = likely::fromCvMat(src);
  36 + likely_const_mat dstl = function(srcl);
  37 + dst = likely::toCvMat(dstl);
  38 + likely_release(dstl);
  39 + likely_release(srcl);
  40 + }
  41 +};
  42 +
  43 +BR_REGISTER(Transform, LikelyTransform)
  44 +
  45 +/*!
  46 + * \ingroup formats
  47 + * \brief Likely matrix format
  48 + *
  49 + * www.liblikely.org
  50 + * \author Josh Klontz \cite jklontz
  51 + */
  52 +class lmFormat : public Format
  53 +{
  54 + Q_OBJECT
  55 +
  56 + Template read() const
  57 + {
  58 + likely_const_mat m = likely_read(qPrintable(file.name));
  59 + Template result(likely::toCvMat(m));
  60 + likely_release(m);
  61 + return result;
  62 + }
  63 +
  64 + void write(const Template &t) const
  65 + {
  66 + likely_const_mat m = likely::fromCvMat(t);
  67 + likely_write(m, qPrintable(file.name));
  68 + likely_release(m);
  69 + }
  70 +};
  71 +
  72 +BR_REGISTER(Format, lmFormat)
  73 +
  74 +} // namespace br
  75 +
  76 +#include "likely.moc"
openbr/plugins/misc.cpp
@@ -552,6 +552,146 @@ public: @@ -552,6 +552,146 @@ public:
552 552
553 BR_REGISTER(Transform, ProgressCounterTransform) 553 BR_REGISTER(Transform, ProgressCounterTransform)
554 554
  555 +
  556 +class OutputTransform : public TimeVaryingTransform
  557 +{
  558 + Q_OBJECT
  559 +
  560 + Q_PROPERTY(QString outputString READ get_outputString WRITE set_outputString RESET reset_outputString STORED false)
  561 + // names of mem galleries containing filelists we need.
  562 + Q_PROPERTY(QString targetName READ get_targetName WRITE set_targetName RESET reset_targetName STORED false)
  563 + Q_PROPERTY(QString queryName READ get_queryName WRITE set_queryName RESET reset_queryName STORED false)
  564 + Q_PROPERTY(bool transposeMode READ get_transposeMode WRITE set_transposeMode RESET reset_transposeMode STORED false)
  565 +
  566 + BR_PROPERTY(QString, outputString, "")
  567 + BR_PROPERTY(QString, targetName, "")
  568 + BR_PROPERTY(QString, queryName, "")
  569 +
  570 + BR_PROPERTY(bool,transposeMode, false)
  571 + ;
  572 +
  573 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  574 + {
  575 + dst = src;
  576 +
  577 + if (src.empty())
  578 + return;
  579 +
  580 + // we received a template, which is the next row/column in order
  581 + foreach(const Template & t, dst) {
  582 + for (int i=0; i < t.m().cols; i++)
  583 + {
  584 + output->setRelative(t.m().at<float>(0, i), currentRow, currentCol);
  585 +
  586 + // row-major input
  587 + if (!transposeMode)
  588 + currentCol++;
  589 + // col-major input
  590 + else
  591 + currentRow++;
  592 + }
  593 + // filled in a row, advance to the next, reset column position
  594 + if (!transposeMode) {
  595 + currentRow++;
  596 + currentCol = 0;
  597 + }
  598 + // filled in a column, advance, reset row
  599 + else {
  600 + currentCol++;
  601 + currentRow = 0;
  602 + }
  603 + }
  604 +
  605 + bool blockDone = false;
  606 + // In direct mode, we don't buffer rows
  607 + if (!transposeMode)
  608 + {
  609 + currentBlockRow++;
  610 + blockDone = true;
  611 + }
  612 + // in transpose mode, we buffer 100 cols before writing the block
  613 + else if (currentCol == bufferedSize)
  614 + {
  615 + currentBlockCol++;
  616 + blockDone = true;
  617 + }
  618 + else return;
  619 +
  620 + if (blockDone)
  621 + {
  622 + // set the next block, only necessary if we haven't buffered the current item
  623 + output->setBlock(currentBlockRow, currentBlockCol);
  624 + currentRow = 0;
  625 + currentCol = 0;
  626 + }
  627 + }
  628 +
  629 + void train(const TemplateList& data)
  630 + {
  631 + (void) data;
  632 + }
  633 +
  634 + void init()
  635 + {
  636 + if (targetName.isEmpty() || queryName.isEmpty() || outputString.isEmpty())
  637 + return;
  638 +
  639 + QScopedPointer<Gallery> tGallery(Gallery::make(targetName));
  640 + QScopedPointer<Gallery> qGallery(Gallery::make(queryName));
  641 +
  642 + FileList targetFiles = tGallery->files();
  643 + FileList queryFiles = qGallery->files();
  644 +
  645 + currentBlockRow = 0;
  646 + currentBlockCol = 0;
  647 +
  648 + currentRow = 0;
  649 + currentCol = 0;
  650 +
  651 + bufferedSize = 100;
  652 +
  653 + if (transposeMode)
  654 + {
  655 + // buffer 100 cols at a time
  656 + fragmentsPerRow = bufferedSize;
  657 + // a single col contains comparisons to all query files
  658 + fragmentsPerCol = queryFiles.size();
  659 + }
  660 + else
  661 + {
  662 + // a single row contains comparisons to all target files
  663 + fragmentsPerRow = targetFiles.size();
  664 + // we output rows one at a time
  665 + fragmentsPerCol = 1;
  666 + }
  667 +
  668 + output = QSharedPointer<Output>(Output::make(outputString, targetFiles, queryFiles));
  669 + output->blockRows = fragmentsPerCol;
  670 + output->blockCols = fragmentsPerRow;
  671 + output->initialize(targetFiles, queryFiles);
  672 +
  673 + output->setBlock(currentBlockRow, currentBlockCol);
  674 + }
  675 +
  676 + QSharedPointer<Output> output;
  677 +
  678 + int bufferedSize;
  679 +
  680 + int currentRow;
  681 + int currentCol;
  682 +
  683 + int currentBlockRow;
  684 + int currentBlockCol;
  685 +
  686 + int fragmentsPerRow;
  687 + int fragmentsPerCol;
  688 +
  689 +public:
  690 + OutputTransform() : TimeVaryingTransform(false,false) {}
  691 +};
  692 +
  693 +BR_REGISTER(Transform, OutputTransform)
  694 +
555 } 695 }
556 696
557 #include "misc.moc" 697 #include "misc.moc"
openbr/plugins/output.cpp
@@ -215,9 +215,11 @@ class mtxOutput : public Output @@ -215,9 +215,11 @@ class mtxOutput : public Output
215 215
216 this->rowBlock = rowBlock; 216 this->rowBlock = rowBlock;
217 this->columnBlock = columnBlock; 217 this->columnBlock = columnBlock;
218 - blockScores = cv::Mat(std::min(queryFiles.size()-rowBlock*Globals->blockSize, Globals->blockSize),  
219 - std::min(targetFiles.size()-columnBlock*Globals->blockSize, Globals->blockSize),  
220 - CV_32FC1); 218 +
  219 + int matrixRows = std::min(queryFiles.size()-rowBlock*this->blockRows, blockRows);
  220 + int matrixCols = std::min(targetFiles.size()-columnBlock*this->blockCols, blockCols);
  221 +
  222 + blockScores = cv::Mat(matrixRows, matrixCols, CV_32FC1);
221 } 223 }
222 224
223 void setRelative(float value, int i, int j) 225 void setRelative(float value, int i, int j)
@@ -237,7 +239,7 @@ class mtxOutput : public Output @@ -237,7 +239,7 @@ class mtxOutput : public Output
237 if (!f.open(QFile::ReadWrite)) 239 if (!f.open(QFile::ReadWrite))
238 qFatal("Unable to open %s for modifying.", qPrintable(file)); 240 qFatal("Unable to open %s for modifying.", qPrintable(file));
239 for (int i=0; i<blockScores.rows; i++) { 241 for (int i=0; i<blockScores.rows; i++) {
240 - f.seek(headerSize + sizeof(float)*(quint64(rowBlock*Globals->blockSize+i)*targetFiles.size()+(columnBlock*Globals->blockSize))); 242 + f.seek(headerSize + sizeof(float)*(quint64(rowBlock*this->blockRows+i)*targetFiles.size()+(columnBlock*this->blockCols)));
241 f.write((const char*)blockScores.row(i).data, sizeof(float)*blockScores.cols); 243 f.write((const char*)blockScores.row(i).data, sizeof(float)*blockScores.cols);
242 } 244 }
243 f.close(); 245 f.close();
openbr/plugins/pp5.cpp
@@ -306,6 +306,22 @@ class PP5CompareDistance : public Distance @@ -306,6 +306,22 @@ class PP5CompareDistance : public Distance
306 { 306 {
307 Q_OBJECT 307 Q_OBJECT
308 308
  309 + struct NativeGallery
  310 + {
  311 + FileList files;
  312 + QList<int> faceIDs;
  313 + ppr_gallery_type gallery;
  314 + };
  315 +
  316 + mutable QMap<QString, NativeGallery> cache;
  317 + mutable QMutex cacheLock;
  318 +
  319 + ~PP5CompareDistance()
  320 + {
  321 + foreach (const NativeGallery &gallery, cache.values())
  322 + ppr_free_gallery(gallery.gallery);
  323 + }
  324 +
309 float compare(const Template &target, const Template &query) const 325 float compare(const Template &target, const Template &query) const
310 { 326 {
311 TemplateList targetList; 327 TemplateList targetList;
@@ -315,7 +331,6 @@ class PP5CompareDistance : public Distance @@ -315,7 +331,6 @@ class PP5CompareDistance : public Distance
315 MatrixOutput *score = MatrixOutput::make(targetList.files(), queryList.files()); 331 MatrixOutput *score = MatrixOutput::make(targetList.files(), queryList.files());
316 compare(targetList, queryList, score); 332 compare(targetList, queryList, score);
317 return score->data.at<float>(0); 333 return score->data.at<float>(0);
318 -  
319 } 334 }
320 335
321 void compare(const TemplateList &target, const TemplateList &query, Output *output) const 336 void compare(const TemplateList &target, const TemplateList &query, Output *output) const
@@ -326,25 +341,27 @@ class PP5CompareDistance : public Distance @@ -326,25 +341,27 @@ class PP5CompareDistance : public Distance
326 QList<int> target_face_ids, query_face_ids; 341 QList<int> target_face_ids, query_face_ids;
327 enroll(target, &target_gallery, target_face_ids); 342 enroll(target, &target_gallery, target_face_ids);
328 enroll(query, &query_gallery, query_face_ids); 343 enroll(query, &query_gallery, query_face_ids);
  344 + compareNative(target_gallery, target_face_ids, query_gallery, query_face_ids, output);
  345 + ppr_free_gallery(target_gallery);
  346 + ppr_free_gallery(query_gallery);
  347 + }
329 348
330 - ppr_similarity_matrix_type similarity_matrix;  
331 - TRY(ppr_compare_galleries(context, query_gallery, target_gallery, &similarity_matrix))  
332 -  
333 - for (int i=0; i<query_face_ids.size(); i++) {  
334 - int query_face_id = query_face_ids[i];  
335 - for (int j=0; j<target_face_ids.size(); j++) {  
336 - int target_face_id = target_face_ids[j]; 349 + void compareNative(ppr_gallery_type target, const QList<int> &targetIDs, ppr_gallery_type query, const QList<int> &queryIDs, Output *output) const
  350 + {
  351 + ppr_similarity_matrix_type simmat;
  352 + TRY(ppr_compare_galleries(context, query, target, &simmat))
  353 + for (int i=0; i<queryIDs.size(); i++) {
  354 + int query_face_id = queryIDs[i];
  355 + for (int j=0; j<targetIDs.size(); j++) {
  356 + int target_face_id = targetIDs[j];
337 float score = -std::numeric_limits<float>::max(); 357 float score = -std::numeric_limits<float>::max();
338 if ((query_face_id != -1) && (target_face_id != -1)) { 358 if ((query_face_id != -1) && (target_face_id != -1)) {
339 - TRY(ppr_get_face_similarity_score(context, similarity_matrix, query_face_id, target_face_id, &score)) 359 + TRY(ppr_get_face_similarity_score(context, simmat, query_face_id, target_face_id, &score))
340 } 360 }
341 output->setRelative(score, i, j); 361 output->setRelative(score, i, j);
342 } 362 }
343 } 363 }
344 -  
345 - ppr_free_similarity_matrix(similarity_matrix);  
346 - ppr_free_gallery(target_gallery);  
347 - ppr_free_gallery(query_gallery); 364 + ppr_free_similarity_matrix(simmat);
348 } 365 }
349 366
350 void enroll(const TemplateList &templates, ppr_gallery_type *gallery, QList<int> &face_ids) const 367 void enroll(const TemplateList &templates, ppr_gallery_type *gallery, QList<int> &face_ids) const
@@ -363,6 +380,53 @@ class PP5CompareDistance : public Distance @@ -363,6 +380,53 @@ class PP5CompareDistance : public Distance
363 } 380 }
364 } 381 }
365 } 382 }
  383 +
  384 + NativeGallery cacheRetain(const File &gallery) const
  385 + {
  386 + QMutexLocker locker(&cacheLock);
  387 + NativeGallery nativeGallery;
  388 + if (cache.contains(gallery.name)) {
  389 + nativeGallery = cache[gallery.name];
  390 + } else {
  391 + ppr_create_gallery(context, &nativeGallery.gallery);
  392 + TemplateList templates = TemplateList::fromGallery(gallery);
  393 + enroll(templates, &nativeGallery.gallery, nativeGallery.faceIDs);
  394 + nativeGallery.files = templates.files();
  395 + if (gallery.get<bool>("retain"))
  396 + cache.insert(gallery.name, nativeGallery);
  397 + }
  398 + return nativeGallery;
  399 + }
  400 +
  401 + void cacheRelease(const File &gallery, const NativeGallery &nativeGallery) const
  402 + {
  403 + QMutexLocker locker(&cacheLock);
  404 + if (cache.contains(gallery.name)) {
  405 + if (gallery.get<bool>("release")) {
  406 + cache.remove(gallery.name);
  407 + ppr_free_gallery(nativeGallery.gallery);
  408 + }
  409 + } else {
  410 + ppr_free_gallery(nativeGallery.gallery);
  411 + }
  412 + }
  413 +
  414 + bool compare(const File &targetGallery, const File &queryGallery, const File &output) const
  415 + {
  416 + if (!targetGallery.get<bool>("native") || !queryGallery.get<bool>("native"))
  417 + return false;
  418 +
  419 + NativeGallery nativeTarget = cacheRetain(targetGallery);
  420 + NativeGallery nativeQuery = cacheRetain(queryGallery);
  421 +
  422 + QScopedPointer<Output> o(Output::make(output, nativeTarget.files, nativeQuery.files));
  423 + o->setBlock(0, 0);
  424 + compareNative(nativeTarget.gallery, nativeTarget.faceIDs, nativeQuery.gallery, nativeQuery.faceIDs, o.data());
  425 +
  426 + cacheRelease(targetGallery, nativeTarget);
  427 + cacheRelease(queryGallery, nativeQuery);
  428 + return true;
  429 + }
366 }; 430 };
367 431
368 BR_REGISTER(Distance, PP5CompareDistance) 432 BR_REGISTER(Distance, PP5CompareDistance)
openbr/plugins/stream.cpp
@@ -25,6 +25,7 @@ class Idiocy : public QObject @@ -25,6 +25,7 @@ class Idiocy : public QObject
25 public: 25 public:
26 enum StreamModes { StreamVideo, 26 enum StreamModes { StreamVideo,
27 DistributeFrames, 27 DistributeFrames,
  28 + StreamGallery,
28 Auto}; 29 Auto};
29 30
30 Q_ENUMS(StreamModes) 31 Q_ENUMS(StreamModes)
@@ -288,6 +289,75 @@ protected: @@ -288,6 +289,75 @@ protected:
288 }; 289 };
289 290
290 291
  292 +class StreamGallery : public TemplateProcessor
  293 +{
  294 +public:
  295 + StreamGallery()
  296 + {
  297 +
  298 + }
  299 +
  300 + bool open(Template &input)
  301 + {
  302 + // Create a gallery
  303 + gallery = QSharedPointer<Gallery>(Gallery::make(input.file));
  304 + // Failed ot open the gallery?
  305 + if (gallery.isNull()) {
  306 + qDebug()<<"Failed to create gallery!";
  307 + galleryOk = false;
  308 + return false;
  309 + }
  310 +
  311 + // Set up state variables for future reads
  312 + galleryOk = true;
  313 + gallery->set_readBlockSize(100);
  314 + nextIdx = 0;
  315 + lastBlock = false;
  316 + return galleryOk;
  317 + }
  318 +
  319 + bool isOpen() { return galleryOk; }
  320 +
  321 + void close()
  322 + {
  323 + galleryOk = false;
  324 + currentData.clear();
  325 + nextIdx = 0;
  326 + lastBlock = true;
  327 + }
  328 +
  329 + bool getNextTemplate(Template & output)
  330 + {
  331 + // If we still have data available, we return one of those
  332 + if (nextIdx >= currentData.size())
  333 + {
  334 + // Otherwise, read another block
  335 + if (!lastBlock) {
  336 + currentData = gallery->readBlock(&lastBlock);
  337 + nextIdx = 0;
  338 + }
  339 + else
  340 + {
  341 + galleryOk = false;
  342 + return false;
  343 + }
  344 + }
  345 + // Return the indicated template, and advance the index
  346 + output = currentData[nextIdx++];
  347 + return true;
  348 + }
  349 +
  350 +protected:
  351 +
  352 + QSharedPointer<Gallery> gallery;
  353 + bool galleryOk;
  354 + bool lastBlock;
  355 +
  356 + TemplateList currentData;
  357 + int nextIdx;
  358 +
  359 +};
  360 +
291 class DirectReturn : public TemplateProcessor 361 class DirectReturn : public TemplateProcessor
292 { 362 {
293 public: 363 public:
@@ -731,6 +801,11 @@ protected: @@ -731,6 +801,11 @@ protected:
731 if (!frameSource) 801 if (!frameSource)
732 frameSource = new DirectReturn(); 802 frameSource = new DirectReturn();
733 } 803 }
  804 + else if (mode == br::Idiocy::StreamGallery)
  805 + {
  806 + if (!frameSource)
  807 + frameSource = new StreamGallery();
  808 + }
734 else if (mode == br::Idiocy::StreamVideo) 809 else if (mode == br::Idiocy::StreamVideo)
735 { 810 {
736 if (!frameSource) { 811 if (!frameSource) {
scripts/brpy/__init__.py
@@ -21,13 +21,27 @@ def _handle_string_func(func): @@ -21,13 +21,27 @@ def _handle_string_func(func):
21 return call_func 21 return call_func
22 22
23 def init_brpy(br_loc='/usr/local/lib'): 23 def init_brpy(br_loc='/usr/local/lib'):
24 - """Takes the ctypes lib object for br and initializes all function inputs and outputs"""  
25 - br_loc += '/libopenbr.%s'  
26 - if os.path.exists(br_loc % 'dylib'):  
27 - br = cdll.LoadLibrary(br_loc % 'dylib')  
28 - elif os.path.exists(br_loc % 'so'):  
29 - br = cdll.LoadLibrary(br_loc % 'so')  
30 - else: 24 + """Initializes all function inputs and outputs for the br ctypes lib object"""
  25 +
  26 + lib_path = os.environ.get('LD_LIBRARY_PATH')
  27 + paths = [br_loc]
  28 + if lib_path:
  29 + paths.extend(lib_path.split(':'))
  30 +
  31 + found = False
  32 + for p in paths:
  33 + dylib = '%s/%s.%s' % (p, 'libopenbr', 'dylib')
  34 + so = '%s/%s.%s' % (p, 'libopenbr', 'so')
  35 + if os.path.exists(dylib):
  36 + br = cdll.LoadLibrary(dylib)
  37 + found = True
  38 + break
  39 + elif os.path.exists(so):
  40 + br = cdll.LoadLibrary(so)
  41 + found = True
  42 + break
  43 +
  44 + if not found:
31 raise ValueError('Neither .so nor .dylib libopenbr found in %s' % br_loc) 45 raise ValueError('Neither .so nor .dylib libopenbr found in %s' % br_loc)
32 46
33 plot_args = _var_string_args(1) + [c_bool] 47 plot_args = _var_string_args(1) + [c_bool]
@@ -44,7 +58,7 @@ def init_brpy(br_loc=&#39;/usr/local/lib&#39;): @@ -44,7 +58,7 @@ def init_brpy(br_loc=&#39;/usr/local/lib&#39;):
44 br.br_eval.argtypes = _string_args(3) 58 br.br_eval.argtypes = _string_args(3)
45 br.br_eval.restype = c_float 59 br.br_eval.restype = c_float
46 br.br_eval_classification.argtypes = _string_args(4) 60 br.br_eval_classification.argtypes = _string_args(4)
47 - br.br_eval_clustering.argtypes = _string_args(2) 61 + br.br_eval_clustering.argtypes = _string_args(3)
48 br.br_eval_detection.argtypes = _string_args(3) 62 br.br_eval_detection.argtypes = _string_args(3)
49 br.br_eval_detection.restype = c_float 63 br.br_eval_detection.restype = c_float
50 br.br_eval_landmarking.argtypes = _string_args(3) + [c_int, c_int] 64 br.br_eval_landmarking.argtypes = _string_args(3) + [c_int, c_int]
@@ -129,7 +143,8 @@ def init_brpy(br_loc=&#39;/usr/local/lib&#39;): @@ -129,7 +143,8 @@ def init_brpy(br_loc=&#39;/usr/local/lib&#39;):
129 br.br_make_gallery.restype = c_void_p 143 br.br_make_gallery.restype = c_void_p
130 br.br_load_from_gallery.argtypes = [c_void_p] 144 br.br_load_from_gallery.argtypes = [c_void_p]
131 br.br_load_from_gallery.restype = c_void_p 145 br.br_load_from_gallery.restype = c_void_p
132 - br.br_add_to_gallery.argtypes = [c_void_p, c_void_p] 146 + br.br_add_template_to_gallery.argtypes = [c_void_p, c_void_p]
  147 + br.br_add_template_list_to_gallery.argtypes = [c_void_p, c_void_p]
133 br.br_close_gallery.argtypes = [c_void_p] 148 br.br_close_gallery.argtypes = [c_void_p]
134 149
135 return br 150 return br