diff --git a/openbr/core/bee.cpp b/openbr/core/bee.cpp index facafe9..6458049 100644 --- a/openbr/core/bee.cpp +++ b/openbr/core/bee.cpp @@ -14,17 +14,10 @@ * limitations under the License. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include -#include -#include -#include -#include +#include #ifndef BR_EMBEDDED #include #endif // BR_EMBEDDED -#include -#include -#include #include "bee.h" #include "opencvutils.h" @@ -33,23 +26,21 @@ using namespace cv; using namespace br; -/**** BEE ****/ -FileList BEE::readSigset(const File &sigset, bool ignoreMetadata) +namespace BEE +{ + +FileList readSigset(const File &sigset, bool ignoreMetadata) { FileList fileList; #ifndef BR_EMBEDDED QDomDocument doc(sigset.fileName()); - QFile file(sigset.resolved()); - bool success; - success = file.open(QIODevice::ReadOnly); if (!success) qFatal("Unable to open %s for reading.", qPrintable(sigset)); - success = doc.setContent(&file); - - file.close(); - - if (!success) { - qWarning("Unable to parse %s.", qPrintable(sigset)); - return fileList; + { + QFile file(sigset.resolved()); + if (!file.open(QIODevice::ReadOnly)) + qFatal("Unable to open %s for reading.", qPrintable(sigset)); + if (!doc.setContent(&file)) + qFatal("Unable to parse %s.", qPrintable(sigset)); } QDomElement docElem = doc.documentElement(); @@ -105,7 +96,7 @@ FileList BEE::readSigset(const File &sigset, bool ignoreMetadata) return fileList; } -void BEE::writeSigset(const QString &sigset, const br::FileList &files, bool ignoreMetadata) +void writeSigset(const QString &sigset, const FileList &files, bool ignoreMetadata) { QStringList lines; lines.reserve(3*files.size()+3); lines.append(""); @@ -137,7 +128,7 @@ void BEE::writeSigset(const QString &sigset, const br::FileList &files, bool ign QtUtils::writeFile(sigset, lines); } -Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySigset) +Mat readMatrix(const File &matrix, QString *targetSigset, QString *querySigset) { QFile file(matrix); bool success = file.open(QFile::ReadOnly); @@ -148,7 +139,6 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi bool isDistance = (format[0] == 'D'); if (format[1] != '2') qFatal("Invalid matrix header."); - // Read sigsets if (targetSigset != NULL) *targetSigset = file.readLine().simplified(); else file.readLine(); @@ -156,57 +146,52 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi else file.readLine(); // Get matrix size - QStringList words = QString(file.readLine()).split(" "); - int rows = words[1].toInt(); - int cols = words[2].toInt(); - - bool isMask = words[0][1] == 'B'; - int typeSize = isMask ? sizeof(BEE::Mask_t) : sizeof(BEE::Simmat_t); + const QStringList words = QString(file.readLine()).split(" "); + const int rows = words[1].toInt(); + const int cols = words[2].toInt(); + const bool isMask = words[0][1] == 'B'; + const int typeSize = isMask ? sizeof(BEE::MaskValue) : sizeof(BEE::SimmatValue); // Get matrix data Mat m; if (isMask) - m.create(rows, cols, OpenCVType::make()); + m.create(rows, cols, OpenCVType::make()); else - m.create(rows, cols, OpenCVType::make()); + m.create(rows, cols, OpenCVType::make()); - qint64 bytesPerRow = m.cols * typeSize; - - for (int i=0; i < m.rows;i++) - { - cv::Mat aRow = m.row(i); + const qint64 bytesPerRow = m.cols * typeSize; + for (int i=0; i("negate", false)) m.convertTo(result, -1, -1); - + if (isDistance ^ matrix.get("negate", false)) + m.convertTo(result, -1, -1); return result; } -void BEE::writeMat(const Mat &m, const QString &matrix, const QString &targetSigset, const QString &querySigset) +void writeMatrix(const Mat &m, const QString &fileName, const QString &targetSigset, const QString &querySigset) { bool isMask = false; - if (m.type() == OpenCVType::make()) + if (m.type() == OpenCVType::make()) isMask = true; - else if (m.type() != OpenCVType::make()) + else if (m.type() != OpenCVType::make()) qFatal("Invalid matrix type, .mtx files can only contain single channel float or uchar matrices."); - int elemSize = isMask ? sizeof(BEE::Mask_t) : sizeof(BEE::Simmat_t); - - QString matrixType = isMask ? "B" : "F"; + const int elemSize = isMask ? sizeof(BEE::MaskValue) : sizeof(BEE::SimmatValue); + const QString matrixType = isMask ? "B" : "F"; char buff[4]; - QFile file(matrix); + QFile file(fileName); QtUtils::touchDir(file); - bool success = file.open(QFile::WriteOnly); if (!success) qFatal("Unable to open %s for writing.", qPrintable(matrix)); + if (!file.open(QFile::WriteOnly)) + qFatal("Unable to open %s for writing.", qPrintable(fileName)); file.write("S2\n"); file.write(qPrintable(targetSigset)); file.write("\n"); @@ -219,7 +204,7 @@ void BEE::writeMat(const Mat &m, const QString &matrix, const QString &targetSig file.write(" "); file.write(qPrintable(QString::number(m.cols))); file.write(" "); - int endian = 0x12345678; + const int endian = 0x12345678; memcpy(&buff, &endian, 4); file.write(buff, 4); file.write("\n"); @@ -227,57 +212,58 @@ void BEE::writeMat(const Mat &m, const QString &matrix, const QString &targetSig file.close(); } -void BEE::readMatrixHeader(const QString &matrix, QString *targetSigset, QString *querySigset) +void readMatrixHeader(const QString &matrix, QString *targetSigset, QString *querySigset) { qDebug("Reading %s header.", qPrintable(matrix)); - readMat(matrix, targetSigset, querySigset); + readMatrix(matrix, targetSigset, querySigset); } -void BEE::writeMatrixHeader(const QString &matrix, const QString &targetSigset, const QString &querySigset) +void writeMatrixHeader(const QString &matrix, const QString &targetSigset, const QString &querySigset) { qDebug("Writing %s header to %s %s.", qPrintable(matrix), qPrintable(targetSigset), qPrintable(querySigset)); - - writeMat(readMat(matrix), matrix, targetSigset, querySigset); + writeMatrix(readMatrix(matrix), matrix, targetSigset, querySigset); } -void BEE::makeMask(const QString &targetInput, const QString &queryInput, const QString &mask) +void makeMask(const QString &targetInput, const QString &queryInput, const QString &mask) { qDebug("Making mask from %s and %s to %s", qPrintable(targetInput), qPrintable(queryInput), qPrintable(mask)); - FileList targets = TemplateList::fromGallery(targetInput).files(); - FileList queries = (queryInput == ".") ? targets : TemplateList::fromGallery(queryInput).files(); - int partitions = targets.first().get("crossValidate"); - if (partitions == 0) writeMat(makeMask(targets, queries), mask, targetInput, queryInput); - else { + const FileList targets = TemplateList::fromGallery(targetInput).files(); + const FileList queries = (queryInput == ".") ? targets : TemplateList::fromGallery(queryInput).files(); + const int partitions = targets.first().get("crossValidate"); + if (partitions == 0) { + writeMatrix(makeMask(targets, queries), mask, targetInput, queryInput); + } else { if (!mask.contains("%1")) qFatal("Mask file name missing partition number place marker (%%1)"); for (int i=0; i("crossValidate"); - if (partitions == 0) writeMat(makePairwiseMask(targets, queries), mask, targetInput, queryInput); - else { + qDebug("Making pairwise mask from %s and %s to %s", qPrintable(targetInput), qPrintable(queryInput), qPrintable(mask)); + const FileList targets = TemplateList::fromGallery(targetInput).files(); + const FileList queries = (queryInput == ".") ? targets : TemplateList::fromGallery(queryInput).files(); + const int partitions = targets.first().get("crossValidate"); + if (partitions == 0) { + writeMatrix(makePairwiseMask(targets, queries), mask, targetInput, queryInput); + } else { if (!mask.contains("%1")) qFatal("Mask file name missing partition number place marker (%%1)"); for (int i=0; i targetLabels = File::get(targets, "Label", "-1"); - QList queryLabels = File::get(queries, "Label", "-1"); - - QList targetPartitions = targets.crossValidationPartitions(); - QList queryPartitions = queries.crossValidationPartitions(); + const QStringList targetLabels = File::get(targets, "Label", "-1"); + const QStringList queryLabels = File::get(queries, "Label", "-1"); + const QList targetPartitions = targets.crossValidationPartitions(); + const QList queryPartitions = queries.crossValidationPartitions(); Mat mask(queries.size(), 1, CV_8UC1); for (int i=0; i(i,0) = val; + mask.at(i,0) = val; } return mask; } -cv::Mat BEE::makeMask(const br::FileList &targets, const br::FileList &queries, int partition) +Mat makeMask(const FileList &targets, const FileList &queries, int partition) { - // Direct use of "Label" isn't general, also would prefer to use indexProperty, rather than + // TODO: Direct use of "Label" isn't general, also would prefer to use indexProperty, rather than // doing string comparisons (but that isn't implemented yet for FileList) -cao - QList targetLabels = File::get(targets, "Label", "-1"); - QList queryLabels = File::get(queries, "Label", "-1"); - - QList targetPartitions = targets.crossValidationPartitions(); - QList queryPartitions = queries.crossValidationPartitions(); - - QList targetsOnly = File::get(queries, "targetOnly", false); + const QStringList targetLabels = File::get(targets, "Label", "-1"); + const QStringList queryLabels = File::get(queries, "Label", "-1"); + const QList targetPartitions = targets.crossValidationPartitions(); + const QList queryPartitions = queries.crossValidationPartitions(); + const QList targetsOnly = File::get(queries, "targetOnly", false); Mat mask(queries.size(), targets.size(), CV_8UC1); for (int i=0; i(i,j) = val; + mask.at(i,j) = val; } } return mask; } -void BEE::combineMasks(const QStringList &inputMasks, const QString &outputMask, const QString &method) +void combineMasks(const QStringList &inputMasks, const QString &outputMask, const QString &method) { qDebug("Combining %d masks to %s with method %s", inputMasks.size(), qPrintable(outputMask), qPrintable(method)); @@ -356,12 +340,12 @@ void BEE::combineMasks(const QStringList &inputMasks, const QString &outputMask, QList masks; foreach (const QString &inputMask, inputMasks) - masks.append(readMat(inputMask)); - if (masks.size() < 2) qFatal("Expected at least two masks."); + masks.append(readMatrix(inputMask)); + if (masks.size() < 2) + qFatal("Expected at least two masks."); const int rows = masks.first().rows; const int columns = masks.first().cols; - Mat combinedMask(rows, columns, CV_8UC1); for (int i=0; i(i,j)) { + switch (masks[k].at(i,j)) { case Match: genuineCount++; break; @@ -383,14 +367,16 @@ void BEE::combineMasks(const QStringList &inputMasks, const QString &outputMask, } if ((genuineCount != 0) && (imposterCount != 0)) qFatal("Comparison is both a genuine and an imposter."); - Mask_t val; + MaskValue val; if (genuineCount > 0) val = Match; else if (imposterCount > 0) val = NonMatch; else val = DontCare; if (AND && (dontcareCount > 0)) val = DontCare; - combinedMask.at(i,j) = val; + combinedMask.at(i,j) = val; } } - writeMat(combinedMask, outputMask, "Combined_Targets", "Combined_Queries"); + writeMatrix(combinedMask, outputMask, "Combined_Targets", "Combined_Queries"); } + +} // namespace BEE diff --git a/openbr/core/bee.h b/openbr/core/bee.h index 313708a..e4c7fa9 100644 --- a/openbr/core/bee.h +++ b/openbr/core/bee.h @@ -17,30 +17,29 @@ #ifndef BEE_BEE_H #define BEE_BEE_H -#include -#include -#include #include #include #include #include -/*** Functions for parsing BEE style data structures. ***/ +/*! + * Functions for parsing NIST BEE data structures. + */ namespace BEE { - const uchar Match(0xff); - const uchar NonMatch(0x7f); - const uchar DontCare(0x00); - typedef float Simmat_t; - typedef uchar Mask_t; + typedef float SimmatValue; + typedef uchar MaskValue; + const MaskValue Match(0xff); + const MaskValue NonMatch(0x7f); + const MaskValue DontCare(0x00); // Sigset br::FileList readSigset(const br::File &sigset, bool ignoreMetadata = false); void writeSigset(const QString &sigset, const br::FileList &files, bool ignoreMetadata = false); // Matrix - cv::Mat readMat(const br::File & mat, QString * targetSigset = NULL, QString * querySigset = NULL); - void writeMat(const cv::Mat &m, const QString &simmat, const QString &targetSigset = "Unknown_Target", const QString &querySigset = "Unknown_Query"); + cv::Mat readMatrix(const br::File &mat, QString *targetSigset = NULL, QString *querySigset = NULL); + void writeMatrix(const cv::Mat &m, const QString &fileName, const QString &targetSigset = "Unknown_Target", const QString &querySigset = "Unknown_Query"); void readMatrixHeader(const QString &matrix, QString *targetSigset, QString *querySigset); void writeMatrixHeader(const QString &matrix, const QString &targetSigset, const QString &querySigset); diff --git a/openbr/core/core.cpp b/openbr/core/core.cpp index bf13564..20b82d4 100644 --- a/openbr/core/core.cpp +++ b/openbr/core/core.cpp @@ -672,7 +672,7 @@ void br::Convert(const File &fileType, const File &inputFile, const File &output while (!done) after->writeBlock(before->readBlock(&done)); } else if (fileType == "Output") { QString target, query; - cv::Mat m = BEE::readMat(inputFile, &target, &query); + cv::Mat m = BEE::readMatrix(inputFile, &target, &query); const FileList targetFiles = TemplateList::fromGallery(target).files(); const FileList queryFiles = TemplateList::fromGallery(query).files(); diff --git a/openbr/core/eval.cpp b/openbr/core/eval.cpp index e71fd9c..f3bc694 100644 --- a/openbr/core/eval.cpp +++ b/openbr/core/eval.cpp @@ -99,7 +99,7 @@ float Evaluate(const QString &simmat, const QString &mask, const QString &csv) QString target, query; Mat scores; if (simmat.endsWith(".mtx")) { - scores = BEE::readMat(simmat, &target, &query); + scores = BEE::readMatrix(simmat, &target, &query); } else { QScopedPointer format(Factory::make(simmat)); scores = format->read(); @@ -144,8 +144,8 @@ float Evaluate(const Mat &simmat, const Mat &mask, const QString &csv) int genuineCount = 0, impostorCount = 0, numNaNs = 0; for (int i=0; i(i,j); - const BEE::Simmat_t simmat_val = simmat.at(i,j); + const BEE::MaskValue mask_val = mask.at(i,j); + const BEE::SimmatValue simmat_val = simmat.at(i,j); if (mask_val == BEE::DontCare) continue; if (simmat_val != simmat_val) { numNaNs++; continue; } comparisons.append(Comparison(simmat_val, j, i, mask_val == BEE::Match)); @@ -315,7 +315,7 @@ float InplaceEval(const QString & simmat, const QString & target, const QString qint64 cols = words[2].toLongLong(); bool isMask = words[0][1] == 'B'; - qint64 typeSize = isMask ? sizeof(BEE::Mask_t) : sizeof(BEE::Simmat_t); + qint64 typeSize = isMask ? sizeof(BEE::MaskValue) : sizeof(BEE::SimmatValue); // Get matrix data qint64 rowSize = cols * typeSize; diff --git a/openbr/core/fuse.cpp b/openbr/core/fuse.cpp index 146fa90..56e4782 100644 --- a/openbr/core/fuse.cpp +++ b/openbr/core/fuse.cpp @@ -39,7 +39,7 @@ static void normalizeMatrix(Mat &matrix, const Mat &mask, const QString &method) for (int i=0; i(i,j); - if ((mask.at(i,j) == BEE::DontCare) || + if ((mask.at(i,j) == BEE::DontCare) || (val == -std::numeric_limits::max()) || (val == std::numeric_limits::max())) continue; @@ -55,7 +55,7 @@ static void normalizeMatrix(Mat &matrix, const Mat &mask, const QString &method) if (method == "MinMax") { for (int i=0; i(i,j) == BEE::DontCare) continue; + if (mask.at(i,j) == BEE::DontCare) continue; float &val = matrix.at(i,j); if (val == -std::numeric_limits::max()) val = 0; else if (val == std::numeric_limits::max()) val = 1; @@ -66,7 +66,7 @@ static void normalizeMatrix(Mat &matrix, const Mat &mask, const QString &method) if (stddev == 0) qFatal("Stddev is 0."); for (int i=0; i(i,j) == BEE::DontCare) continue; + if (mask.at(i,j) == BEE::DontCare) continue; float &val = matrix.at(i,j); if (val == -std::numeric_limits::max()) val = (min - mean) / stddev; else if (val == std::numeric_limits::max()) val = (max - mean) / stddev; @@ -85,7 +85,7 @@ void br::Fuse(const QStringList &inputSimmats, const QString &normalization, con QString target, query, previousTarget, previousQuery; QList originalMatrices; foreach (const QString &simmat, inputSimmats) { - originalMatrices.append(BEE::readMat(simmat,&target,&query)); + originalMatrices.append(BEE::readMatrix(simmat,&target,&query)); // Make we're fusing score matrices for the same set of targets and querys if (!previousTarget.isEmpty() && !previousQuery.isEmpty() && (previousTarget != target || previousQuery != query)) qFatal("Target or query files are not the same across fused matrices."); @@ -163,5 +163,5 @@ void br::Fuse(const QStringList &inputSimmats, const QString &normalization, con } while (partition < crossValidate); - BEE::writeMat(buffer, outputSimmat); + BEE::writeMatrix(buffer, outputSimmat); } diff --git a/openbr/plugins/format.cpp b/openbr/plugins/format.cpp index b573b8b..66a8f4b 100644 --- a/openbr/plugins/format.cpp +++ b/openbr/plugins/format.cpp @@ -293,12 +293,12 @@ class mtxFormat : public Format Template read() const { - return BEE::readMat(file); + return BEE::readMatrix(file); } void write(const Template &t) const { - BEE::writeMat(t, file); + BEE::writeMatrix(t, file); } };