diff --git a/app/br/br.cpp b/app/br/br.cpp index e62e9ab..a1d9aa4 100644 --- a/app/br/br.cpp +++ b/app/br/br.cpp @@ -100,9 +100,6 @@ public: } else if (!strcmp(fun, "compare")) { check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'compare'."); br_compare(parv[0], parv[1], parc == 3 ? parv[2] : ""); - } else if (!strcmp(fun, "pairwiseCompare")) { - check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'pairwiseCompare'."); - br_pairwise_compare(parv[0], parv[1], parc == 3 ? parv[2] : ""); } else if (!strcmp(fun, "eval")) { check((parc >= 1) && (parc <= 4), "Incorrect parameter count for 'eval'."); if (parc == 1) { @@ -126,9 +123,6 @@ public: } else { br_eval(parv[0], parv[1], parv[2], atoi(parv[3])); } - } else if (!strcmp(fun, "inplaceEval")) { - check((parc >= 3) && (parc <= 4), "Incorrect parameter count for 'inplaceEval'."); - br_inplace_eval(parv[0], parv[1], parv[2], parc == 4 ? parv[3] : ""); } else if (!strcmp(fun, "plot")) { check(parc >= 2, "Incorrect parameter count for 'plot'."); br_plot(parc-1, parv, parv[parc-1], true); @@ -174,6 +168,12 @@ public: } else if (!strcmp(fun, "evalRegression")) { check(parc >= 2 && parc <= 4, "Incorrect parameter count for 'evalRegression'."); br_eval_regression(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? parv[3] : ""); + } else if (!strcmp(fun, "pairwiseCompare")) { + check((parc >= 2) && (parc <= 3), "Incorrect parameter count for 'pairwiseCompare'."); + br_pairwise_compare(parv[0], parv[1], parc == 3 ? parv[2] : ""); + } else if (!strcmp(fun, "inplaceEval")) { + check((parc >= 3) && (parc <= 4), "Incorrect parameter count for 'inplaceEval'."); + br_inplace_eval(parv[0], parv[1], parv[2], parc == 4 ? parv[3] : ""); } else if (!strcmp(fun, "plotDetection")) { check(parc >= 2, "Incorrect parameter count for 'plotDetection'."); br_plot_detection(parc-1, parv, parv[parc-1], true); @@ -257,10 +257,8 @@ private: "-train ... [{model}]\n" "-enroll ... {output_gallery}\n" "-compare [{output}]\n" - "-pairwiseCompare [{output}]\n" "-eval [] [{csv}] [{matches}]\n" - "-inplaceEval [{csv}]\n" - "-plot ... {destination}\n" + "-plot ... {destination}\n" "\n" "==== Other Commands ====\n" "-fuse ... (None|MinMax|ZScore|WScore) (Min|Max|Sum[W1:W2:...:Wn]|Replace|Difference|None) {simmat}\n" @@ -275,6 +273,8 @@ private: "-evalDetection [{csv}] [{normalize}] [{minSize}] [{maxSize}]\n" "-evalLandmarking [{csv} [ ] [sample_index] [total_examples]]\n" "-evalRegression \n" + "-pairwiseCompare [{output}]\n" + "-inplaceEval [{csv}]\n" "-assertEval \n" "-plotDetection ... {destination}\n" "-plotLandmarking ... {destination}\n" diff --git a/openbr/core/core.cpp b/openbr/core/core.cpp index d236cdd..b1de4c4 100644 --- a/openbr/core/core.cpp +++ b/openbr/core/core.cpp @@ -266,7 +266,7 @@ struct AlgorithmCore void retrieveOrEnroll(const File &file, QScopedPointer &gallery, FileList &galleryFiles) { - if (!file.getBool("enroll") && (QStringList() << "gal" << "mem" << "template" << "ut").contains(file.suffix())) { + if (!file.getBool("enroll") && (QStringList() << "gal" << "mem" << "template" << "t").contains(file.suffix())) { // Retrieve it gallery.reset(Gallery::make(file)); galleryFiles = gallery->files(); @@ -443,7 +443,7 @@ struct AlgorithmCore colEnrolledGallery = colGallery.baseName() + colGallery.hash() + '.' + targetExtension; // Check if we have to do real enrollment, and not just convert the gallery's type. - if (!(QStringList() << "gal" << "template" << "mem" << "ut").contains(colGallery.suffix())) + if (!(QStringList() << "gal" << "template" << "mem" << "t").contains(colGallery.suffix())) enroll(colGallery, colEnrolledGallery); // If the gallery does have enrolled templates, but is not the right type, we do a simple @@ -465,7 +465,7 @@ struct AlgorithmCore // which compares incoming templates against a gallery, we will handle enrollment of the row set by simply // building a transform that does enrollment (using the current algorithm), then does the comparison in one // step. This way, we don't have to retain the complete enrolled row gallery in memory, or on disk. - else if (!(QStringList() << "gal" << "mem" << "template" << "ut").contains(rowGallery.suffix())) + else if (!(QStringList() << "gal" << "mem" << "template" << "t").contains(rowGallery.suffix())) needEnrollRows = true; // At this point, we have decided how we will structure the comparison (either in transpose mode, or not), diff --git a/openbr/janus b/openbr/janus index 8cdda77..bab25ea 160000 --- a/openbr/janus +++ b/openbr/janus @@ -1 +1 @@ -Subproject commit 8cdda77000209ea279093b0d4fad3988f22f0548 +Subproject commit bab25ea9b9f26791859415abe953f6df82ace86e diff --git a/openbr/janus.cpp b/openbr/janus.cpp index 79f635e..39974fb 100644 --- a/openbr/janus.cpp +++ b/openbr/janus.cpp @@ -24,13 +24,13 @@ janus_error janus_initialize(const char *sdk_path, const char *temp_path, const Globals->enrollAll = true; Globals->file.set(QString("temp_path"), QString(temp_path)); const QString algorithm = model_file; + detect.reset(Transform::make("Cvt(Gray)+Cascade(FrontalFace,ROCMode=true)", NULL)); if (algorithm.isEmpty()) { - detect.reset(Transform::make("Cvt(Gray)+Cascade(FrontalFace,ROCMode=true)", NULL)); augment.reset(Transform::make("Cvt(Gray)+Affine(88,88,0.25,0.35)+++", NULL)); distance = Distance::fromAlgorithm("FaceRecognition"); } else { - augment.reset(Transform::make(algorithm + "Enroll", NULL)); - distance.reset(Distance::make(algorithm + "Compare", NULL)); + augment = Transform::fromAlgorithm(algorithm); + distance = Distance::fromAlgorithm(algorithm); } return JANUS_SUCCESS; } diff --git a/openbr/plugins/imgproc/cropfromlandmarks.cpp b/openbr/plugins/imgproc/cropfromlandmarks.cpp new file mode 100644 index 0000000..c23e2aa --- /dev/null +++ b/openbr/plugins/imgproc/cropfromlandmarks.cpp @@ -0,0 +1,54 @@ +#include + +using namespace cv; + +namespace br +{ + +/*! + * \ingroup transforms + * \brief Crops around the landmarks numbers provided. + * \author Brendan Klare \cite bklare + * \param padding Percentage of height and width to pad the image. + */ +class CropFromLandmarksTransform : public UntrainableTransform +{ + Q_OBJECT + + Q_PROPERTY(QList indices READ get_indices WRITE set_indices RESET reset_indices STORED false) + Q_PROPERTY(float paddingHorizontal READ get_paddingHorizontal WRITE set_paddingHorizontal RESET reset_paddingHorizontal STORED false) + Q_PROPERTY(float paddingVertical READ get_paddingVertical WRITE set_paddingVertical RESET reset_paddingVertical STORED false) + BR_PROPERTY(QList, indices, QList()) + BR_PROPERTY(float, paddingHorizontal, .1) + BR_PROPERTY(float, paddingVertical, .1) + + void project(const Template &src, Template &dst) const + { + int minX = src.m().cols - 1, + maxX = 1, + minY = src.m().rows - 1, + maxY = 1; + + for (int i = 0; i src.file.points()[indices[i]].x()) + minX = src.file.points()[indices[i]].x(); + if (minY > src.file.points()[indices[i]].y()) + minY = src.file.points()[indices[i]].y(); + if (maxX < src.file.points()[indices[i]].x()) + maxX = src.file.points()[indices[i]].x(); + if (maxY < src.file.points()[indices[i]].y()) + maxY = src.file.points()[indices[i]].y(); + } + + int padW = qRound((maxX - minX) * (paddingHorizontal / 2)); + int padH = qRound((maxY - minY) * (paddingVertical / 2)); + + dst = Mat(src, Rect(minX - padW, minY - padH, (maxX - minX + 1) + padW * 2, (maxY - minY + 1) + padH * 2)); + } +}; + +BR_REGISTER(Transform, CropFromLandmarksTransform) + +} // namespace br + +#include "imgproc/cropfromlandmarks.moc" diff --git a/openbr/plugins/metadata/cascade.cpp b/openbr/plugins/metadata/cascade.cpp index d694b32..3a44e25 100644 --- a/openbr/plugins/metadata/cascade.cpp +++ b/openbr/plugins/metadata/cascade.cpp @@ -401,18 +401,22 @@ class CascadeTransform : public MetaTransform } for (int i=0; i("MaxDetections", std::numeric_limits::max()); + const int flags = (enrollAll && (maxDetections != 1)) ? 0 : CASCADE_FIND_BIGGEST_OBJECT; + Mat m; OpenCVUtils::cvtUChar(t[i], m); std::vector rects; std::vector rejectLevels; std::vector levelWeights; - if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, minNeighbors, (enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT) | CASCADE_SCALE_IMAGE, Size(minSize, minSize), Size(), true); - else cascade->detectMultiScale(m, rects, 1.2, minNeighbors, enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); + if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, minNeighbors, flags | CASCADE_SCALE_IMAGE, Size(minSize, minSize), Size(), true); + else cascade->detectMultiScale(m, rects, 1.2, minNeighbors, flags, Size(minSize, minSize)); if (!enrollAll && rects.empty()) rects.push_back(Rect(0, 0, m.cols, m.rows)); - for (size_t j=0; j j) u.file.set("Confidence", rejectLevels[j]*levelWeights[j]); diff --git a/scripts/evalFaceRecognition-LFW.sh b/scripts/evalFaceRecognition-LFW.sh index 53e5636..af3c7c0 100755 --- a/scripts/evalFaceRecognition-LFW.sh +++ b/scripts/evalFaceRecognition-LFW.sh @@ -20,7 +20,7 @@ if [ ! -e Algorithm_Dataset ]; then fi # Run the LFW test protocol -br -algorithm $ALGORITHM -path ../data/LFW/img/ -crossValidate 10 -pairwiseCompare ../data/LFW/sigset/test_image_restricted_target.xml ../data/LFW/sigset/test_image_restricted_query.xml ${ALGORITHM}_LFW.mtx -convert Output ${ALGORITHM}_lfw.mtx Algorithm_Dataset/${ALGORITHM}_LFW%1.eval +br -algorithm $ALGORITHM -path ../data/LFW/img/ -crossValidate 10 -pairwiseCompare ../data/LFW/sigset/test_image_restricted_target.xml ../data/LFW/sigset/test_image_restricted_query.xml ${ALGORITHM}_LFW.mtx -convert Output ${ALGORITHM}_LFW.mtx Algorithm_Dataset/${ALGORITHM}_LFW%1.eval # Plot results -br -plot Algorithm_Dataset/* 'lfw_results.pdf[smooth=Dataset,rocOptions[yLimits=(0,1)]]' +br -plot Algorithm_Dataset/* 'lfw_results.pdf[smooth=Dataset,rocOptions=[yLimits=(0,1)]]'