Commit 7d2c5ba7c4ad289c4f86e34b65f36463d37d80d5
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
10 changed files
with
52 additions
and
25 deletions
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/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 &simmat, const Mat &mask, const QString &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 &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); |
| ... | ... | @@ -1003,7 +1003,7 @@ void Output::reformat(const FileList &targetFiles, const FileList &queryFiles, c |
| 1003 | 1003 | const int columns = targetFiles.size(); |
| 1004 | 1004 | for (int i=0; i<rows; i++) |
| 1005 | 1005 | for (int j=0; j<columns; j++) |
| 1006 | - o->setRelative(m.at<float>(i,i), i, j); | |
| 1006 | + o->setRelative(m.at<float>(i,j), i, j); | |
| 1007 | 1007 | } |
| 1008 | 1008 | |
| 1009 | 1009 | /* Output - protected methods */ | ... | ... |
openbr/openbr_plugin.h
| ... | ... | @@ -410,7 +410,7 @@ struct TemplateList : public QList<Template> |
| 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/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 | ... | ... |