diff --git a/openbr/core/core.cpp b/openbr/core/core.cpp index 8da6cf0..f44b1bb 100644 --- a/openbr/core/core.cpp +++ b/openbr/core/core.cpp @@ -223,7 +223,7 @@ struct AlgorithmCore if (!output.fileName().contains("%1")) qFatal("Output file name missing split number place marker (%%1)"); partitionSizes = output.getList("split"); for (int i=0; i Pair; foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector(data.row(i)), true, limit)) { @@ -384,7 +384,7 @@ class evalOutput : public MatrixOutput double mean, stddev; Common::MeanStdDev(TARs, &mean, &stddev); - qDebug("TAR @ FAR = 0.001: %.3f +/- %.3f", mean, stddev); + qDebug("TAR @ FAR = 0.01: %.3f +/- %.3f", mean, stddev); } } } diff --git a/openbr/plugins/stasm4.cpp b/openbr/plugins/stasm4.cpp index 0e9f667..acb7911 100644 --- a/openbr/plugins/stasm4.cpp +++ b/openbr/plugins/stasm4.cpp @@ -5,7 +5,6 @@ #include "openbr/core/qtutils.h" #include "openbr/core/opencvutils.h" #include -#include using namespace std; using namespace cv; @@ -77,7 +76,7 @@ class StasmTransform : public UntrainableTransform StasmCascadeClassifier *stasmCascade = stasmCascadeResource.acquire(); - int foundface; + int foundFace = 0; int nLandmarks = stasm_NLANDMARKS; float landmarks[2 * stasm_NLANDMARKS]; @@ -109,13 +108,14 @@ class StasmTransform : public UntrainableTransform else if (i == 39) /*Stasm Left Eye*/ { eyes[2*i] = leftEye.x(); eyes[2*i+1] = leftEye.y(); } else { eyes[2*i] = 0; eyes[2*i+1] = 0; } } - } else qFatal("Unable to interpret pinned eyes."); + stasm_search_pinned(landmarks, eyes, reinterpret_cast(src.m().data), src.m().cols, src.m().rows, NULL); - stasm_search_pinned(landmarks, eyes, reinterpret_cast(src.m().data), src.m().cols, src.m().rows, NULL); + // The ASM in Stasm is guaranteed to converge in this case + foundFace = 1; + } + } - // The ASM in Stasm is guaranteed to converge in this case - foundface = 1; - } stasm_search_single(&foundface, landmarks, reinterpret_cast(src.m().data), src.m().cols, src.m().rows, *stasmCascade, NULL, NULL); + if (!foundFace) stasm_search_single(&foundFace, landmarks, reinterpret_cast(src.m().data), src.m().cols, src.m().rows, *stasmCascade, NULL, NULL); if (stasm3Format) { nLandmarks = 76; @@ -130,8 +130,8 @@ class StasmTransform : public UntrainableTransform dst.file.clearRects(); } - if (!foundface) { - qWarning("No face found in %s", qPrintable(src.file.fileName())); + if (!foundFace) { + qWarning("No face found in %s.", qPrintable(src.file.fileName())); } else { for (int i = 0; i < nLandmarks; i++) { QPointF point(landmarks[2 * i], landmarks[2 * i + 1]); diff --git a/openbr/plugins/validate.cpp b/openbr/plugins/validate.cpp index ff17fa2..c77dff3 100644 --- a/openbr/plugins/validate.cpp +++ b/openbr/plugins/validate.cpp @@ -74,9 +74,7 @@ class CrossValidateTransform : public MetaTransform // Remove template that was repeated to make the testOnly template if (subjectIndices.size() > 1 && subjectIndices.size() <= i) { removed.append(subjectIndices[i%subjectIndices.size()]); - } - // For the time being, we don't support addition training data added to every fold in the case of leaveOneImageOut - else if (partitionsBuffer[j] == i) { + } else if (partitionsBuffer[j] == i) { removed.append(j); } @@ -88,10 +86,6 @@ class CrossValidateTransform : public MetaTransform } else { j--; } - } else if (partitions[j] == -1) { - // Keep data for training, but modify the partition so we project into the correct space - partitionedData[j].file.set("Partition",i); - j--; } else if (partitions[j] == i) { // Remove data, it's designated for testing partitionedData.removeAt(j); @@ -106,7 +100,19 @@ class CrossValidateTransform : public MetaTransform void project(const Template &src, Template &dst) const { - transforms[src.file.get("Partition", 0)]->project(src, dst); + // Remember, the partition should never be -1 + // since it is assumed that the allPartitions + // flag is only used during comparison + // (i.e. only used when making a mask) + if (src.file.getBool("Train", false)) dst = src; + else { + // If we want to duplicate templates but use the same training data + // for all partitions (i.e. transforms.size() == 1), we need to + // restrict the partition + int partition = src.file.get("Partition", 0); + partition = (partition >= transforms.size()) ? 0 : partition; + transforms[partition]->project(src, dst); + } } void store(QDataStream &stream) const @@ -231,6 +237,40 @@ class MetadataDistance : public Distance BR_REGISTER(Distance, MetadataDistance) +/*! + * \ingroup distances + * \brief Sets distance to -FLOAT_MAX if a target template has/doesn't have a key. + * \author Scott Klum \cite sklum + */ +class RejectDistance : public Distance +{ + Q_OBJECT + + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) + BR_PROPERTY(QStringList, keys, QStringList()) + Q_PROPERTY(bool rejectIfContains READ get_rejectIfContains WRITE set_rejectIfContains RESET reset_rejectIfContains STORED false) + BR_PROPERTY(bool, rejectIfContains, false) + + float compare(const Template &a, const Template &b) const + { + (void) b; + bool keep = true; + + foreach (const QString &key, keys) { + if ((rejectIfContains && a.file.contains(key)) || + (!rejectIfContains && !a.file.contains(key))) + keep = false; + + if (!keep) return -std::numeric_limits::max(); + } + + return 0; + } +}; + + +BR_REGISTER(Distance, RejectDistance) + } // namespace br #include "validate.moc"