Commit 05d60bddb89cbfe7dd08a88b4572d51b7d05aefc

Authored by Charles Otto
2 parents c0adb3c5 e9f1e88d

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

data/README.md
... ... @@ -7,9 +7,9 @@
7 7 * [FRGC](FRGC/README.md)
8 8 * [LFW](LFW/LFW.md)
9 9 * [MEDS](MEDS/README.md)
  10 +* [MNIST](MNIST/README.md)
10 11 * [PCSO](PCSO/README.md)
11 12  
12   -For both practical and legal reasons we don't include images in this repository.
13   -Open source datasets can be downloaded using `../scripts/downloadDatasets.sh`.
  13 +For both practical and legal reasons we only include images for some of the datasets in this repository.
14 14 Researchers should contact the respective owners of the other datasets in order to obtain a copy.
15 15 The provided sigsets indicate how the images are expected to be arranged in directories, generally following the conventions established by the original authors.
... ...
openbr/core/classify.cpp
... ... @@ -45,8 +45,12 @@ void br::EvalClassification(const QString &predictedInput, const QString &truthI
45 45 qFatal("Input order mismatch.");
46 46  
47 47 // Typically these lists will be of length one, but this generalization allows measuring multi-class labeling accuracy.
48   - QStringList predictedSubjects = predicted[i].file.get<QStringList>("Subject");
49   - QStringList trueSubjects = truth[i].file.get<QStringList>("Subject");
  48 + QString predictedSubject = predicted[i].file.subject();
  49 + QString trueSubject = truth[i].file.subject();
  50 +
  51 + QStringList predictedSubjects(predictedSubject);
  52 + QStringList trueSubjects(trueSubject);
  53 +
50 54 foreach (const QString &subject, trueSubjects.toVector() /* Hack to copy the list. */) {
51 55 if (predictedSubjects.contains(subject)) {
52 56 counters[subject].truePositive++;
... ...
openbr/core/core.cpp
... ... @@ -248,9 +248,8 @@ struct AlgorithmCore
248 248 if (!partitionSizes.empty()) targetPartitions = targets.partition(partitionSizes);
249 249 else targetPartitions.append(targets);
250 250  
251   - if (queryPartitions[i].first().size() != targetPartitions[i].first().size()) qFatal("Query and target templates have different number of matrices.");
252   -
253 251 outputs[i]->setBlock(queryBlock, targetBlock);
  252 +
254 253 distance->compare(targetPartitions[i], queryPartitions[i], outputs[i]);
255 254  
256 255 Globals->currentStep += double(targets.size()) * double(queries.size());
... ...
openbr/core/plot.cpp
... ... @@ -248,24 +248,29 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv)
248 248 lines.append(qPrintable(QString("BC,0.001,%1").arg(QString::number(getTAR(operatingPoints, 0.001), 'f', 3))));
249 249 lines.append(qPrintable(QString("BC,0.01,%1").arg(QString::number(result = getTAR(operatingPoints, 0.01), 'f', 3))));
250 250  
  251 +
251 252 // Write SD & KDE
252 253 points = qMin(qMin(Max_Points, genuines.size()), impostors.size());
253 254 QList<double> sampledGenuineScores; sampledGenuineScores.reserve(points);
254 255 QList<double> sampledImpostorScores; sampledImpostorScores.reserve(points);
255   - for (int i=0; i<points; i++) {
256   - float genuineScore = genuines[double(i) / double(points-1) * double(genuines.size()-1)];
257   - float impostorScore = impostors[double(i) / double(points-1) * double(impostors.size()-1)];
258   - if (genuineScore == -std::numeric_limits<float>::max()) genuineScore = minGenuineScore;
259   - if (impostorScore == -std::numeric_limits<float>::max()) impostorScore = minImpostorScore;
260   - lines.append(QString("SD,%1,Genuine").arg(QString::number(genuineScore)));
261   - lines.append(QString("SD,%1,Impostor").arg(QString::number(impostorScore)));
262   - sampledGenuineScores.append(genuineScore);
263   - sampledImpostorScores.append(impostorScore);
  256 +
  257 + if (points > 1) {
  258 + for (int i=0; i<points; i++) {
  259 + float genuineScore = genuines[double(i) / double(points-1) * double(genuines.size()-1)];
  260 + float impostorScore = impostors[double(i) / double(points-1) * double(impostors.size()-1)];
  261 + if (genuineScore == -std::numeric_limits<float>::max()) genuineScore = minGenuineScore;
  262 + if (impostorScore == -std::numeric_limits<float>::max()) impostorScore = minImpostorScore;
  263 + lines.append(QString("SD,%1,Genuine").arg(QString::number(genuineScore)));
  264 + lines.append(QString("SD,%1,Impostor").arg(QString::number(impostorScore)));
  265 + sampledGenuineScores.append(genuineScore);
  266 + sampledImpostorScores.append(impostorScore);
  267 + }
264 268 }
265 269  
266 270 // Write Cumulative Match Characteristic (CMC) curve
267   - const int Max_Retrieval = 100;
  271 + const int Max_Retrieval = 200;
268 272 const int Report_Retrieval = 5;
  273 +
269 274 float reportRetrievalRate = -1;
270 275 for (int i=1; i<=Max_Retrieval; i++) {
271 276 int realizedReturns = 0, possibleReturns = 0;
... ... @@ -467,6 +472,8 @@ struct RPlot
467 472 }
468 473 };
469 474  
  475 +// Does not work if dataset folder starts with a number
  476 +
470 477 bool Plot(const QStringList &files, const br::File &destination, bool show)
471 478 {
472 479 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination));
... ...
openbr/openbr_plugin.cpp
... ... @@ -52,7 +52,7 @@ QString File::flat() const
52 52 const QVariant value = this->value(key);
53 53 if (value.isNull()) values.append(key);
54 54 else {
55   - if (QString(value.typeName()) == "QVariantList" || QString(value.typeName()) == "QStringList") {
  55 + if (QString(value.typeName()) == "QVariantList") {
56 56 QStringList variants;
57 57 foreach(const QVariant &variant, qvariant_cast<QVariantList>(value)) {
58 58 variants.append(QtUtils::toString(variant));
... ... @@ -137,7 +137,7 @@ QVariant File::value(const QString &amp;key) const
137 137  
138 138 QVariant File::parse(const QString &value)
139 139 {
140   - bool ok;
  140 + bool ok = false;
141 141 const QPointF point = QtUtils::toPoint(value, &ok);
142 142 if (ok) return point;
143 143 const QRectF rect = QtUtils::toRect(value, &ok);
... ... @@ -183,6 +183,11 @@ float File::label() const
183 183 if (s.isNull()) return -1;
184 184  
185 185 const QString subject = s.toString();
  186 +
  187 + bool is_num = false;
  188 + float num = subject.toFloat(&is_num);
  189 + if (is_num) return num;
  190 +
186 191 static QMutex mutex;
187 192 QMutexLocker mutexLocker(&mutex);
188 193 if (!Globals->subjects.contains(subject))
... ... @@ -1003,7 +1008,7 @@ void Output::reformat(const FileList &amp;targetFiles, const FileList &amp;queryFiles, c
1003 1008 const int columns = targetFiles.size();
1004 1009 for (int i=0; i<rows; i++)
1005 1010 for (int j=0; j<columns; j++)
1006   - o->setRelative(m.at<float>(i,i), i, j);
  1011 + o->setRelative(m.at<float>(i,j), i, j);
1007 1012 }
1008 1013  
1009 1014 /* Output - protected methods */
... ...
openbr/openbr_plugin.h
... ... @@ -410,7 +410,7 @@ struct TemplateList : public QList&lt;Template&gt;
410 410 sum+=partitionSizes[i];
411 411 }
412 412  
413   - if (sum != first().size()) qFatal("Partition sizes do not span template matrices properly");
  413 + if (sum != first().size()) qFatal("Partition sizes %i do not span template matrices %i properly", sum, first().size());
414 414  
415 415 foreach (const Template &t, *this) {
416 416 int index = 0;
... ...
openbr/plugins/ct8.cpp
... ... @@ -11,9 +11,9 @@
11 11 #include <exception>
12 12 #include <string>
13 13 #include <vector>
14   -#include "openbr_internal.h"
15 14  
16   -#include "core/resource.h"
  15 +#include "openbr_internal.h"
  16 +#include "openbr/core/resource.h"
17 17  
18 18 using namespace cv;
19 19 using namespace br;
... ...
openbr/plugins/eigen3.cpp
... ... @@ -330,6 +330,7 @@ class LDATransform : public Transform
330 330 void train(const TemplateList &_trainingSet)
331 331 {
332 332 TemplateList trainingSet = TemplateList::relabel(_trainingSet);
  333 +
333 334 int instances = trainingSet.size();
334 335  
335 336 // Perform PCA dimensionality reduction
... ...
openbr/plugins/format.cpp
... ... @@ -317,6 +317,7 @@ BR_REGISTER(Format, maskFormat)
317 317 * \brief MATLAB <tt>.mat</tt> format.
318 318 * \author Josh Klontz \cite jklontz
319 319 * http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf
  320 + * \note matFormat is known not to work with compressed matrices
320 321 */
321 322 class matFormat : public Format
322 323 {
... ... @@ -324,12 +325,18 @@ class matFormat : public Format
324 325  
325 326 struct Element
326 327 {
  328 + // It is always best to cast integers to a Qt integer type, such as qint16 or quint32, when reading and writing.
  329 + // This ensures that you always know exactly what size integers you are reading and writing, no matter what the
  330 + // underlying platform and architecture the application happens to be running on.
  331 + // http://qt-project.org/doc/qt-4.8/datastreamformat.html
327 332 quint32 type, bytes;
328 333 QByteArray data;
329 334 Element() : type(0), bytes(0) {}
330 335 Element(QDataStream &stream)
331 336 : type(0), bytes(0)
332 337 {
  338 + // Read first 4 bytes into type (32 bit integer),
  339 + // specifying the type of data used
333 340 if (stream.readRawData((char*)&type, 4) != 4)
334 341 qFatal("Unexpected end of file.");
335 342  
... ... @@ -340,11 +347,16 @@ class matFormat : public Format
340 347 bytes = bytes >> 16;
341 348 } else {
342 349 // Regular format
  350 + // Read 4 bytes into bytes (32 bit integer),
  351 + // specifying the size of the element
343 352 if (stream.readRawData((char*)&bytes, 4) != 4)
344 353 qFatal("Unexpected end of file.");
345 354 }
346 355  
  356 + // Set the size of data to bytes
347 357 data.resize(bytes);
  358 +
  359 + // Read bytes amount of data from the file into data
348 360 if (int(bytes) != stream.readRawData(data.data(), bytes))
349 361 qFatal("Unexpected end of file.");
350 362  
... ... @@ -372,8 +384,9 @@ class matFormat : public Format
372 384 while (!f.atEnd()) {
373 385 Element element(f);
374 386  
375   - // miCOMPRESS
  387 + // miCOMPRESSED
376 388 if (element.type == 15) {
  389 + // Prepend the number of bytes to element.data
377 390 element.data.prepend((char*)&element.bytes, 4); // Qt zlib wrapper requires this to preallocate the buffer
378 391 QDataStream uncompressed(qUncompress(element.data));
379 392 element = Element(uncompressed);
... ...
openbr/plugins/meta.cpp
... ... @@ -76,7 +76,7 @@ class PipeTransform : public CompositeTransform
76 76 {
77 77 Q_OBJECT
78 78  
79   - void _projectPartial(Template *srcdst, int startIndex, int stopIndex)
  79 + void _projectPartial(TemplateList *srcdst, int startIndex, int stopIndex)
80 80 {
81 81 for (int i=startIndex; i<stopIndex; i++)
82 82 *srcdst >> *transforms[i];
... ... @@ -87,6 +87,14 @@ class PipeTransform : public CompositeTransform
87 87 if (!trainable) return;
88 88  
89 89 TemplateList copy(data);
  90 + QList<TemplateList> singleItemLists;
  91 + for (int i=0; i < copy.size(); i++)
  92 + {
  93 + TemplateList temp;
  94 + temp.append(copy[i]);
  95 + singleItemLists.append(temp);
  96 + }
  97 +
90 98 int i = 0;
91 99 while (i < transforms.size()) {
92 100 fprintf(stderr, "\n%s", qPrintable(transforms[i]->objectName()));
... ... @@ -109,9 +117,14 @@ class PipeTransform : public CompositeTransform
109 117  
110 118 fprintf(stderr, " projecting...");
111 119 QFutureSynchronizer<void> futures;
112   - for (int j=0; j<copy.size(); j++)
113   - futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &copy[j], i, nextTrainableTransform));
  120 + for (int j=0; j < singleItemLists.size(); j++)
  121 + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &singleItemLists[j], i, nextTrainableTransform));
114 122 futures.waitForFinished();
  123 +
  124 + copy.clear();
  125 + for (int j=0; j < singleItemLists.size(); j++)
  126 + copy.append(singleItemLists[j]);
  127 +
115 128 i = nextTrainableTransform;
116 129 }
117 130 }
... ...
openbr/plugins/stasm.cpp
... ... @@ -34,7 +34,7 @@ BR_REGISTER(Initializer, StasmInitializer)
34 34 * \author Scott Klum \cite sklum
35 35 */
36 36 // TODO: Use a global mutex to prevent concurrent calls to AsmSearchDll
37   -#if 0
  37 +
38 38 class StasmTransform : public UntrainableTransform
39 39 {
40 40 Q_OBJECT
... ... @@ -46,6 +46,9 @@ class StasmTransform : public UntrainableTransform
46 46  
47 47 void project(const Template &src, Template &dst) const
48 48 {
  49 + static QMutex mutex;
  50 + QMutexLocker locker(&mutex);
  51 +
49 52 int nlandmarks;
50 53 int landmarks[500];
51 54  
... ... @@ -68,7 +71,6 @@ class StasmTransform : public UntrainableTransform
68 71 };
69 72  
70 73 BR_REGISTER(Transform, StasmTransform)
71   -#endif
72 74  
73 75 } // namespace br
74 76  
... ...
openbr/plugins/validate.cpp
... ... @@ -52,8 +52,13 @@ class CrossValidateTransform : public MetaTransform
52 52 }
53 53  
54 54 void project(const Template &src, Template &dst) const
55   - {
56   - transforms[src.file.get<int>("Partition", 0)]->project(src, dst);
  55 + {
  56 + // If the src partition is greater than the number of training partitions,
  57 + // assume that projection should be done using the same training data for all partitions.
  58 + int partition = src.file.get<int>("Partition", 0);
  59 + if (partition >= transforms.size()-1) partition = 0;
  60 +
  61 + transforms[partition]->project(src, dst);
57 62 }
58 63  
59 64 void store(QDataStream &stream) const
... ...
1   -Subproject commit c11ff0f0bb451fb5576bd4b8122c32278e52042a
  1 +Subproject commit 1394fbec42897c1a53373443c32a6f62a010294f
... ...
share/openbr/openbr.bib
... ... @@ -40,6 +40,11 @@
40 40 Title = {{OpenBR} - {Open} {Biometric} {Recognition}},
41 41 Year = {2012}}
42 42  
  43 +@misc{libface,
  44 + Howpublished = {http://libface.sourceforge.net/file/Home.html},
  45 + Title = {libface},
  46 + Year = {2011}}
  47 +
43 48 @misc{CT8,
44 49 Author = {Cognitec},
45 50 Howpublished = {www.cognitec-systems.de/FaceVACS-SDK.19.0.html},
... ... @@ -77,21 +82,49 @@
77 82 Year = 2000}
78 83  
79 84 @manual{R,
80   - Title = {R: A Language and Environment for Statistical Computing},
81   - Author = {{R Core Team}},
82   - Organization = {R Foundation for Statistical Computing},
83   - Address = {Vienna, Austria},
84   - Year = 2013,
85   - Url = {http://www.R-project.org}}
  85 + Title = {R: A Language and Environment for Statistical Computing},
  86 + Author = {{R Core Team}},
  87 + Organization = {R Foundation for Statistical Computing},
  88 + Address = {Vienna, Austria},
  89 + Year = 2013,
  90 + Url = {http://www.R-project.org}}
86 91  
87 92 % Papers
  93 +@incollection{ahonen04,
  94 + Author = {Ahonen, Timo and Hadid, Abdenour and Pietik{\"a}inen, Matti},
  95 + Booktitle = {Computer Vision-ECCV 2004},
  96 + Pages = {469-481},
  97 + Publisher = {Springer},
  98 + Title = {Face recognition with local binary patterns},
  99 + Year = {2004}}
  100 +
88 101 @inproceedings{arandjelovic12,
89   - Author={Arandjelovic, R. and Zisserman, A.},
90   - Booktitle={Computer Vision and Pattern Recognition (CVPR), 2012 IEEE Conference on},
91   - Title={Three things everyone should know to improve object retrieval},
92   - Month={June},
93   - Year={2012},
94   - Pages={2911-2918}}
  102 + Author = {Arandjelovic, R. and Zisserman, A.},
  103 + Booktitle = {Computer Vision and Pattern Recognition (CVPR), 2012 IEEE Conference on},
  104 + Title = {Three things everyone should know to improve object retrieval},
  105 + Month = {June},
  106 + Year = {2012},
  107 + Pages = {2911-2918}}
  108 +
  109 +@article{bradski00,
  110 + Author = {Bradski, Gary},
  111 + Journal = {Doctor Dobbs Journal},
  112 + Number = {11},
  113 + Pages = {120-126},
  114 + Publisher = {M AND T PUBLISHING INC},
  115 + Title = {The {OpenCV} library},
  116 + Volume = {25},
  117 + Year = {2000}}
  118 +
  119 +@article{belhumeur97,
  120 + Author = {Belhumeur, Peter N. and Hespanha, Joao P. and Kriegman, David J.},
  121 + Journal = {Pattern Analysis and Machine Intelligence, IEEE Transactions on},
  122 + Number = {7},
  123 + Pages = {711-720},
  124 + Publisher = {IEEE},
  125 + Title = {Eigenfaces vs. fisherfaces: Recognition using class specific linear projection},
  126 + Volume = {19},
  127 + Year = {1997}}
95 128  
96 129 @inproceedings{belhumeur11,
97 130 Author = {Belhumeur, P.N. and Jacobs, D.W. and Kriegman, D.J. and Kumar, N.},
... ... @@ -136,11 +169,31 @@
136 169 Month = {jan},
137 170 Year = {2013}}
138 171  
  172 +@article{hall09,
  173 + Author = {Hall, Mark and Frank, Eibe and Holmes, Geoffrey and Pfahringer, Bernhard and Reutemann, Peter and Witten, Ian H},
  174 + Journal = {ACM SIGKDD Explorations Newsletter},
  175 + Number = {1},
  176 + Pages = {10-18},
  177 + Publisher = {ACM},
  178 + Title = {The WEKA data mining software: an update},
  179 + Volume = {11},
  180 + Year = {2009}}
  181 +
139 182 @inproceedings{huang08,
140   - Author={Huang, Gary B and Mattar, Marwan and Berg, Tamara and Learned-Miller, Eric and others},
141   - Booktitle={Workshop on Faces in 'Real-Life' Images: Detection, Alignment, and Recognition},
142   - Title={Labeled faces in the wild: A database forstudying face recognition in unconstrained environments},
143   - Year={2008}}
  183 + Author = {Huang, Gary B and Mattar, Marwan and Berg, Tamara and Learned-Miller, Eric and others},
  184 + Booktitle = {Workshop on Faces in 'Real-Life' Images: Detection, Alignment, and Recognition},
  185 + Title = {Labeled faces in the wild: A database forstudying face recognition in unconstrained environments},
  186 + Year = {2008}}
  187 +
  188 +@article{ihaka96,
  189 + Author = {Ihaka, Ross and Gentleman, Robert},
  190 + Journal = {Journal of computational and graphical statistics},
  191 + Number = {3},
  192 + Pages = {299-314},
  193 + Publisher = {Taylor \& Francis},
  194 + Title = {R: A language for data analysis and graphics},
  195 + Volume = {5},
  196 + Year = {1996}}
144 197  
145 198 @article{jegou11,
146 199 Author = {J{\'e}gou, H. and Douze, M. and Schmid, C.},
... ... @@ -173,6 +226,14 @@
173 226 Title = {{The HFB Face Database} for {Heterogeneous Face Biometrics} Research},
174 227 Year = {2009}}
175 228  
  229 +@inproceedings{lui12,
  230 + Author = {Lui, Yui Man and Bolme, D and Phillips, PJ and Beveridge, JR and Draper, BA},
  231 + Booktitle = {Computer Vision and Pattern Recognition Workshops (CVPRW), 2012 IEEE Computer Society Conference on},
  232 + Organization = {IEEE},
  233 + Pages = {9-16},
  234 + Title = {Preliminary studies on the Good, the Bad, and the Ugly face recognition challenge problem},
  235 + Year = {2012}}
  236 +
176 237 @article{martinez98,
177 238 Author = {Martinez, A.M.},
178 239 Journal = {CVC Technical Report},
... ...