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,9 +7,9 @@
7 * [FRGC](FRGC/README.md) 7 * [FRGC](FRGC/README.md)
8 * [LFW](LFW/LFW.md) 8 * [LFW](LFW/LFW.md)
9 * [MEDS](MEDS/README.md) 9 * [MEDS](MEDS/README.md)
  10 +* [MNIST](MNIST/README.md)
10 * [PCSO](PCSO/README.md) 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 Researchers should contact the respective owners of the other datasets in order to obtain a copy. 14 Researchers should contact the respective owners of the other datasets in order to obtain a copy.
15 The provided sigsets indicate how the images are expected to be arranged in directories, generally following the conventions established by the original authors. 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,8 +45,12 @@ void br::EvalClassification(const QString &predictedInput, const QString &truthI
45 qFatal("Input order mismatch."); 45 qFatal("Input order mismatch.");
46 46
47 // Typically these lists will be of length one, but this generalization allows measuring multi-class labeling accuracy. 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 foreach (const QString &subject, trueSubjects.toVector() /* Hack to copy the list. */) { 54 foreach (const QString &subject, trueSubjects.toVector() /* Hack to copy the list. */) {
51 if (predictedSubjects.contains(subject)) { 55 if (predictedSubjects.contains(subject)) {
52 counters[subject].truePositive++; 56 counters[subject].truePositive++;
openbr/core/core.cpp
@@ -248,9 +248,8 @@ struct AlgorithmCore @@ -248,9 +248,8 @@ struct AlgorithmCore
248 if (!partitionSizes.empty()) targetPartitions = targets.partition(partitionSizes); 248 if (!partitionSizes.empty()) targetPartitions = targets.partition(partitionSizes);
249 else targetPartitions.append(targets); 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 outputs[i]->setBlock(queryBlock, targetBlock); 251 outputs[i]->setBlock(queryBlock, targetBlock);
  252 +
254 distance->compare(targetPartitions[i], queryPartitions[i], outputs[i]); 253 distance->compare(targetPartitions[i], queryPartitions[i], outputs[i]);
255 254
256 Globals->currentStep += double(targets.size()) * double(queries.size()); 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,24 +248,29 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv)
248 lines.append(qPrintable(QString("BC,0.001,%1").arg(QString::number(getTAR(operatingPoints, 0.001), 'f', 3)))); 248 lines.append(qPrintable(QString("BC,0.001,%1").arg(QString::number(getTAR(operatingPoints, 0.001), 'f', 3))));
249 lines.append(qPrintable(QString("BC,0.01,%1").arg(QString::number(result = getTAR(operatingPoints, 0.01), 'f', 3)))); 249 lines.append(qPrintable(QString("BC,0.01,%1").arg(QString::number(result = getTAR(operatingPoints, 0.01), 'f', 3))));
250 250
  251 +
251 // Write SD & KDE 252 // Write SD & KDE
252 points = qMin(qMin(Max_Points, genuines.size()), impostors.size()); 253 points = qMin(qMin(Max_Points, genuines.size()), impostors.size());
253 QList<double> sampledGenuineScores; sampledGenuineScores.reserve(points); 254 QList<double> sampledGenuineScores; sampledGenuineScores.reserve(points);
254 QList<double> sampledImpostorScores; sampledImpostorScores.reserve(points); 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 // Write Cumulative Match Characteristic (CMC) curve 270 // Write Cumulative Match Characteristic (CMC) curve
267 - const int Max_Retrieval = 100; 271 + const int Max_Retrieval = 200;
268 const int Report_Retrieval = 5; 272 const int Report_Retrieval = 5;
  273 +
269 float reportRetrievalRate = -1; 274 float reportRetrievalRate = -1;
270 for (int i=1; i<=Max_Retrieval; i++) { 275 for (int i=1; i<=Max_Retrieval; i++) {
271 int realizedReturns = 0, possibleReturns = 0; 276 int realizedReturns = 0, possibleReturns = 0;
@@ -467,6 +472,8 @@ struct RPlot @@ -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 bool Plot(const QStringList &files, const br::File &destination, bool show) 477 bool Plot(const QStringList &files, const br::File &destination, bool show)
471 { 478 {
472 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination)); 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,7 +52,7 @@ QString File::flat() const
52 const QVariant value = this->value(key); 52 const QVariant value = this->value(key);
53 if (value.isNull()) values.append(key); 53 if (value.isNull()) values.append(key);
54 else { 54 else {
55 - if (QString(value.typeName()) == "QVariantList" || QString(value.typeName()) == "QStringList") { 55 + if (QString(value.typeName()) == "QVariantList") {
56 QStringList variants; 56 QStringList variants;
57 foreach(const QVariant &variant, qvariant_cast<QVariantList>(value)) { 57 foreach(const QVariant &variant, qvariant_cast<QVariantList>(value)) {
58 variants.append(QtUtils::toString(variant)); 58 variants.append(QtUtils::toString(variant));
@@ -137,7 +137,7 @@ QVariant File::value(const QString &amp;key) const @@ -137,7 +137,7 @@ QVariant File::value(const QString &amp;key) const
137 137
138 QVariant File::parse(const QString &value) 138 QVariant File::parse(const QString &value)
139 { 139 {
140 - bool ok; 140 + bool ok = false;
141 const QPointF point = QtUtils::toPoint(value, &ok); 141 const QPointF point = QtUtils::toPoint(value, &ok);
142 if (ok) return point; 142 if (ok) return point;
143 const QRectF rect = QtUtils::toRect(value, &ok); 143 const QRectF rect = QtUtils::toRect(value, &ok);
@@ -183,6 +183,11 @@ float File::label() const @@ -183,6 +183,11 @@ float File::label() const
183 if (s.isNull()) return -1; 183 if (s.isNull()) return -1;
184 184
185 const QString subject = s.toString(); 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 static QMutex mutex; 191 static QMutex mutex;
187 QMutexLocker mutexLocker(&mutex); 192 QMutexLocker mutexLocker(&mutex);
188 if (!Globals->subjects.contains(subject)) 193 if (!Globals->subjects.contains(subject))
@@ -1003,7 +1008,7 @@ void Output::reformat(const FileList &amp;targetFiles, const FileList &amp;queryFiles, c @@ -1003,7 +1008,7 @@ void Output::reformat(const FileList &amp;targetFiles, const FileList &amp;queryFiles, c
1003 const int columns = targetFiles.size(); 1008 const int columns = targetFiles.size();
1004 for (int i=0; i<rows; i++) 1009 for (int i=0; i<rows; i++)
1005 for (int j=0; j<columns; j++) 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 /* Output - protected methods */ 1014 /* Output - protected methods */
openbr/openbr_plugin.h
@@ -410,7 +410,7 @@ struct TemplateList : public QList&lt;Template&gt; @@ -410,7 +410,7 @@ struct TemplateList : public QList&lt;Template&gt;
410 sum+=partitionSizes[i]; 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 foreach (const Template &t, *this) { 415 foreach (const Template &t, *this) {
416 int index = 0; 416 int index = 0;
openbr/plugins/ct8.cpp
@@ -11,9 +11,9 @@ @@ -11,9 +11,9 @@
11 #include <exception> 11 #include <exception>
12 #include <string> 12 #include <string>
13 #include <vector> 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 using namespace cv; 18 using namespace cv;
19 using namespace br; 19 using namespace br;
openbr/plugins/eigen3.cpp
@@ -330,6 +330,7 @@ class LDATransform : public Transform @@ -330,6 +330,7 @@ class LDATransform : public Transform
330 void train(const TemplateList &_trainingSet) 330 void train(const TemplateList &_trainingSet)
331 { 331 {
332 TemplateList trainingSet = TemplateList::relabel(_trainingSet); 332 TemplateList trainingSet = TemplateList::relabel(_trainingSet);
  333 +
333 int instances = trainingSet.size(); 334 int instances = trainingSet.size();
334 335
335 // Perform PCA dimensionality reduction 336 // Perform PCA dimensionality reduction
openbr/plugins/format.cpp
@@ -317,6 +317,7 @@ BR_REGISTER(Format, maskFormat) @@ -317,6 +317,7 @@ BR_REGISTER(Format, maskFormat)
317 * \brief MATLAB <tt>.mat</tt> format. 317 * \brief MATLAB <tt>.mat</tt> format.
318 * \author Josh Klontz \cite jklontz 318 * \author Josh Klontz \cite jklontz
319 * http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf 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 class matFormat : public Format 322 class matFormat : public Format
322 { 323 {
@@ -324,12 +325,18 @@ class matFormat : public Format @@ -324,12 +325,18 @@ class matFormat : public Format
324 325
325 struct Element 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 quint32 type, bytes; 332 quint32 type, bytes;
328 QByteArray data; 333 QByteArray data;
329 Element() : type(0), bytes(0) {} 334 Element() : type(0), bytes(0) {}
330 Element(QDataStream &stream) 335 Element(QDataStream &stream)
331 : type(0), bytes(0) 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 if (stream.readRawData((char*)&type, 4) != 4) 340 if (stream.readRawData((char*)&type, 4) != 4)
334 qFatal("Unexpected end of file."); 341 qFatal("Unexpected end of file.");
335 342
@@ -340,11 +347,16 @@ class matFormat : public Format @@ -340,11 +347,16 @@ class matFormat : public Format
340 bytes = bytes >> 16; 347 bytes = bytes >> 16;
341 } else { 348 } else {
342 // Regular format 349 // Regular format
  350 + // Read 4 bytes into bytes (32 bit integer),
  351 + // specifying the size of the element
343 if (stream.readRawData((char*)&bytes, 4) != 4) 352 if (stream.readRawData((char*)&bytes, 4) != 4)
344 qFatal("Unexpected end of file."); 353 qFatal("Unexpected end of file.");
345 } 354 }
346 355
  356 + // Set the size of data to bytes
347 data.resize(bytes); 357 data.resize(bytes);
  358 +
  359 + // Read bytes amount of data from the file into data
348 if (int(bytes) != stream.readRawData(data.data(), bytes)) 360 if (int(bytes) != stream.readRawData(data.data(), bytes))
349 qFatal("Unexpected end of file."); 361 qFatal("Unexpected end of file.");
350 362
@@ -372,8 +384,9 @@ class matFormat : public Format @@ -372,8 +384,9 @@ class matFormat : public Format
372 while (!f.atEnd()) { 384 while (!f.atEnd()) {
373 Element element(f); 385 Element element(f);
374 386
375 - // miCOMPRESS 387 + // miCOMPRESSED
376 if (element.type == 15) { 388 if (element.type == 15) {
  389 + // Prepend the number of bytes to element.data
377 element.data.prepend((char*)&element.bytes, 4); // Qt zlib wrapper requires this to preallocate the buffer 390 element.data.prepend((char*)&element.bytes, 4); // Qt zlib wrapper requires this to preallocate the buffer
378 QDataStream uncompressed(qUncompress(element.data)); 391 QDataStream uncompressed(qUncompress(element.data));
379 element = Element(uncompressed); 392 element = Element(uncompressed);
openbr/plugins/meta.cpp
@@ -76,7 +76,7 @@ class PipeTransform : public CompositeTransform @@ -76,7 +76,7 @@ class PipeTransform : public CompositeTransform
76 { 76 {
77 Q_OBJECT 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 for (int i=startIndex; i<stopIndex; i++) 81 for (int i=startIndex; i<stopIndex; i++)
82 *srcdst >> *transforms[i]; 82 *srcdst >> *transforms[i];
@@ -87,6 +87,14 @@ class PipeTransform : public CompositeTransform @@ -87,6 +87,14 @@ class PipeTransform : public CompositeTransform
87 if (!trainable) return; 87 if (!trainable) return;
88 88
89 TemplateList copy(data); 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 int i = 0; 98 int i = 0;
91 while (i < transforms.size()) { 99 while (i < transforms.size()) {
92 fprintf(stderr, "\n%s", qPrintable(transforms[i]->objectName())); 100 fprintf(stderr, "\n%s", qPrintable(transforms[i]->objectName()));
@@ -109,9 +117,14 @@ class PipeTransform : public CompositeTransform @@ -109,9 +117,14 @@ class PipeTransform : public CompositeTransform
109 117
110 fprintf(stderr, " projecting..."); 118 fprintf(stderr, " projecting...");
111 QFutureSynchronizer<void> futures; 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 futures.waitForFinished(); 122 futures.waitForFinished();
  123 +
  124 + copy.clear();
  125 + for (int j=0; j < singleItemLists.size(); j++)
  126 + copy.append(singleItemLists[j]);
  127 +
115 i = nextTrainableTransform; 128 i = nextTrainableTransform;
116 } 129 }
117 } 130 }
openbr/plugins/stasm.cpp
@@ -34,7 +34,7 @@ BR_REGISTER(Initializer, StasmInitializer) @@ -34,7 +34,7 @@ BR_REGISTER(Initializer, StasmInitializer)
34 * \author Scott Klum \cite sklum 34 * \author Scott Klum \cite sklum
35 */ 35 */
36 // TODO: Use a global mutex to prevent concurrent calls to AsmSearchDll 36 // TODO: Use a global mutex to prevent concurrent calls to AsmSearchDll
37 -#if 0 37 +
38 class StasmTransform : public UntrainableTransform 38 class StasmTransform : public UntrainableTransform
39 { 39 {
40 Q_OBJECT 40 Q_OBJECT
@@ -46,6 +46,9 @@ class StasmTransform : public UntrainableTransform @@ -46,6 +46,9 @@ class StasmTransform : public UntrainableTransform
46 46
47 void project(const Template &src, Template &dst) const 47 void project(const Template &src, Template &dst) const
48 { 48 {
  49 + static QMutex mutex;
  50 + QMutexLocker locker(&mutex);
  51 +
49 int nlandmarks; 52 int nlandmarks;
50 int landmarks[500]; 53 int landmarks[500];
51 54
@@ -68,7 +71,6 @@ class StasmTransform : public UntrainableTransform @@ -68,7 +71,6 @@ class StasmTransform : public UntrainableTransform
68 }; 71 };
69 72
70 BR_REGISTER(Transform, StasmTransform) 73 BR_REGISTER(Transform, StasmTransform)
71 -#endif  
72 74
73 } // namespace br 75 } // namespace br
74 76
openbr/plugins/validate.cpp
@@ -52,8 +52,13 @@ class CrossValidateTransform : public MetaTransform @@ -52,8 +52,13 @@ class CrossValidateTransform : public MetaTransform
52 } 52 }
53 53
54 void project(const Template &src, Template &dst) const 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 void store(QDataStream &stream) const 64 void store(QDataStream &stream) const
1 -Subproject commit c11ff0f0bb451fb5576bd4b8122c32278e52042a 1 +Subproject commit 1394fbec42897c1a53373443c32a6f62a010294f
share/openbr/openbr.bib
@@ -40,6 +40,11 @@ @@ -40,6 +40,11 @@
40 Title = {{OpenBR} - {Open} {Biometric} {Recognition}}, 40 Title = {{OpenBR} - {Open} {Biometric} {Recognition}},
41 Year = {2012}} 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 @misc{CT8, 48 @misc{CT8,
44 Author = {Cognitec}, 49 Author = {Cognitec},
45 Howpublished = {www.cognitec-systems.de/FaceVACS-SDK.19.0.html}, 50 Howpublished = {www.cognitec-systems.de/FaceVACS-SDK.19.0.html},
@@ -77,21 +82,49 @@ @@ -77,21 +82,49 @@
77 Year = 2000} 82 Year = 2000}
78 83
79 @manual{R, 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 % Papers 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 @inproceedings{arandjelovic12, 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 @inproceedings{belhumeur11, 129 @inproceedings{belhumeur11,
97 Author = {Belhumeur, P.N. and Jacobs, D.W. and Kriegman, D.J. and Kumar, N.}, 130 Author = {Belhumeur, P.N. and Jacobs, D.W. and Kriegman, D.J. and Kumar, N.},
@@ -136,11 +169,31 @@ @@ -136,11 +169,31 @@
136 Month = {jan}, 169 Month = {jan},
137 Year = {2013}} 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 @inproceedings{huang08, 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 @article{jegou11, 198 @article{jegou11,
146 Author = {J{\'e}gou, H. and Douze, M. and Schmid, C.}, 199 Author = {J{\'e}gou, H. and Douze, M. and Schmid, C.},
@@ -173,6 +226,14 @@ @@ -173,6 +226,14 @@
173 Title = {{The HFB Face Database} for {Heterogeneous Face Biometrics} Research}, 226 Title = {{The HFB Face Database} for {Heterogeneous Face Biometrics} Research},
174 Year = {2009}} 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 @article{martinez98, 237 @article{martinez98,
177 Author = {Martinez, A.M.}, 238 Author = {Martinez, A.M.},
178 Journal = {CVC Technical Report}, 239 Journal = {CVC Technical Report},