diff --git a/CHANGELOG.md b/CHANGELOG.md index 0313c69..4b44fab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * NEC3 refactored * Updated transform API to add support for time-varying transforms per issue (#23) * Refactored File class to improve point and rect storage (#22) +* Added algorithm to show face detection results (#25) 0.2.0 - 2/23/13 =============== diff --git a/app/br/CMakeLists.txt b/app/br/CMakeLists.txt index fc37e7f..128c671 100644 --- a/app/br/CMakeLists.txt +++ b/app/br/CMakeLists.txt @@ -8,3 +8,4 @@ install(TARGETS br RUNTIME DESTINATION bin) add_test(NAME br_initialize WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND br) add_test(NAME br_objects WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND br -objects) +add_test(NAME br_draw_face_detection WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND br -algorithm DrawFaceDetection -enroll ../data/family.jpg) diff --git a/app/br/br.cpp b/app/br/br.cpp index dfe1fe2..f16642c 100644 --- a/app/br/br.cpp +++ b/app/br/br.cpp @@ -31,10 +31,20 @@ * \endcode * * \section cli_examples Examples + * - \ref cli_show_face_detection * - \ref cli_age_estimation * - \ref cli_face_recognition * - \ref cli_face_recognition_evaluation * - \ref cli_gender_estimation + * - \ref cli_show_face_detection + */ + +/*! + * \ingroup cli + * \page cli_show_face_detection Show Face Detection + * \code + * $ br -algorithm ShowFaceDetection -enrollAll -enroll ../data/family.jpg # Press 'Enter' to cycle through the results + * \endcode */ static void help() diff --git a/data b/data deleted file mode 160000 index 3501de8..0000000 --- a/data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3501de8f90e2ec366ea418c7d5d2ef8beb612e73 diff --git a/scripts/trainAgeRegression-PCSO.sh b/scripts/trainAgeRegression-PCSO.sh new file mode 100755 index 0000000..2a73e83 --- /dev/null +++ b/scripts/trainAgeRegression-PCSO.sh @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ! -f trainAgeRegression-PCSO.sh ]; then + echo "Run this script from the scripts folder!" + exit +fi + +#rm -f ../models/features/FaceClassificationRegistration +#rm -f ../models/features/FaceClassificationExtraction +rm -f ../models/algorithms/AgeRegression + +br -algorithm AgeRegression -path ../data/PCSO/Images -train "../data/PCSO/PCSO.db[query='SELECT File,Age,PersonID FROM PCSO WHERE Age >= 15 AND AGE <= 75', subset=0:200]" ../share/openbr/models/algorithms/AgeRegression diff --git a/scripts/trainFaceRecognition-PCSO.sh b/scripts/trainFaceRecognition-PCSO.sh new file mode 100755 index 0000000..fc09eb7 --- /dev/null +++ b/scripts/trainFaceRecognition-PCSO.sh @@ -0,0 +1,13 @@ +#!/bin/bash +if [ ! -f trainFaceRecognition-PCSO.sh ]; then + echo "Run this script from the scripts folder!" + exit +fi + +#rm -f ../models/features/FaceRecognitionRegistration +#rm -f ../models/features/FaceRecognitionExtraction +#rm -f ../models/features/FaceRecognitionEmbedding +#rm -f ../models/features/FaceRecognitionQuantization +rm -f ../models/algorithms/FaceRecognition + +br -algorithm FaceRecognition -path ../data/PCSO/Images -train "../data/PCSO/PCSO.db[query='SELECT File,'S'||PersonID,PersonID FROM PCSO', subset=0:5:6000]" ../share/openbr/models/algorithms/FaceRecognition diff --git a/scripts/trainGenderClassification-PCSO.sh b/scripts/trainGenderClassification-PCSO.sh new file mode 100755 index 0000000..88cfafe --- /dev/null +++ b/scripts/trainGenderClassification-PCSO.sh @@ -0,0 +1,11 @@ +#!/bin/bash +if [ ! -f trainGenderClassification-PCSO.sh ]; then + echo "Run this script from the scripts folder!" + exit +fi + +#rm -f ../models/features/FaceClassificationRegistration +#rm -f ../models/features/FaceClassificationExtraction +rm -f ../models/algorithms/GenderClassification + +br -algorithm GenderClassification -path ../data/PCSO/Images -train "../data/PCSO/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=0:8000]" ../share/openbr/models/algorithms/GenderClassification diff --git a/sdk/core/bee.cpp b/sdk/core/bee.cpp index 1bbca0d..982cdde 100644 --- a/sdk/core/bee.cpp +++ b/sdk/core/bee.cpp @@ -199,6 +199,7 @@ void writeMatrix(const Mat &m, const QString &matrix, const QString &targetSigse char buff[4]; QFile file(matrix); + QtUtils::touchDir(file); bool success = file.open(QFile::WriteOnly); if (!success) qFatal("Unable to open %s for writing.", qPrintable(matrix)); file.write("S2\n"); file.write(qPrintable(QFileInfo(targetSigset).fileName())); diff --git a/sdk/openbr_plugin.cpp b/sdk/openbr_plugin.cpp index d54f016..edb9480 100644 --- a/sdk/openbr_plugin.cpp +++ b/sdk/openbr_plugin.cpp @@ -1108,7 +1108,7 @@ private: QList templatesList; foreach (const Template &t, data) { if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) - qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable((QString)t.file), t.size(), templatesList.size()); + qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable(t.file.name), t.size(), templatesList.size()); while (templatesList.size() < t.size()) templatesList.append(TemplateList()); for (int i=0; i mats; for (int i=0; iproject(Template(src.file, src[i]), m); - dst.merge(m); + transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst); + mats.append(dst); + dst.clear(); } + dst.append(mats); } void store(QDataStream &stream) const diff --git a/sdk/plugins/algorithms.cpp b/sdk/plugins/algorithms.cpp index 018ba0a..28efccc 100644 --- a/sdk/plugins/algorithms.cpp +++ b/sdk/plugins/algorithms.cpp @@ -38,6 +38,8 @@ class AlgorithmsInitializer : public Initializer Globals->abbreviations.insert("FaceQuality", "Open!Cascade(FrontalFace)+ASEFEyes+Affine(64,64,0.25,0.35)+ImageQuality+Cvt(Gray)+DFFS+Discard"); Globals->abbreviations.insert("MedianFace", "Open!Cascade(FrontalFace)+ASEFEyes+Affine(256,256,0.37,0.45)+Center(Median)"); Globals->abbreviations.insert("BlurredFaceDetection", "Open+LimitSize(1024)+SkinMask/(Cvt(Gray)+GradientMask)+And+Morph(Erode,16)+LargestConvexArea"); + Globals->abbreviations.insert("DrawFaceDetection", "Open+Cascade(FrontalFace)!ASEFEyes+Draw"); + Globals->abbreviations.insert("ShowFaceDetection", "DrawFaceDetection!Show"); Globals->abbreviations.insert("OpenBR", "FaceRecognition"); Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); @@ -48,6 +50,7 @@ class AlgorithmsInitializer : public Initializer Globals->abbreviations.insert("SmallSIFT", "Open+LimitSize(512)+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); Globals->abbreviations.insert("SmallSURF", "Open+LimitSize(512)+KeyPointDetector(SURF)+KeyPointDescriptor(SURF):KeyPointMatcher(BruteForce)"); Globals->abbreviations.insert("ColorHist", "Open+LimitSize(512)!EnsureChannels(3)+SplitChannels+Hist(256,0,8)+Cat+Normalize(L1):L2"); + Globals->abbreviations.insert("IHH", "Open+SplitChannels/(Cvt(Gray)+Gradient+Bin(0,6.283,8,true))+Integral+Merge+IntegralSampler"); // Hash Globals->abbreviations.insert("FileName", "Name+Identity:Identical"); diff --git a/sdk/plugins/ct8.cpp b/sdk/plugins/ct8.cpp index 7da0579..21417c0 100644 --- a/sdk/plugins/ct8.cpp +++ b/sdk/plugins/ct8.cpp @@ -236,7 +236,6 @@ struct CT8Context FRsdk::SampleSet sampleSet; sampleSet.push_back(sample); - FRsdk::EnrolOpenCVFeedback * feedback_body = new FRsdk::EnrolOpenCVFeedback(m); FRsdk::CountedPtr feedback_ptr(feedback_body); @@ -300,14 +299,14 @@ protected: * \author Josh Klontz \cite jklontz * \author Charles Otto \cite caotto */ -struct CT8Detect : public UntrainableTransform - , public CT8Context +class CT8DetectTransform : public UntrainableTransform + , public CT8Context { -public: Q_OBJECT - Q_PROPERTY(float minRelEyeDistance READ get_minRelEyeDistance WRITE set_minRelEyeDistance RESET reset_minRelEyeDistance STORED false) Q_PROPERTY(float maxRelEyeDistance READ get_maxRelEyeDistance WRITE set_maxRelEyeDistance RESET reset_maxRelEyeDistance STORED false) + BR_PROPERTY(float, minRelEyeDistance, 0.01f) + BR_PROPERTY(float, maxRelEyeDistance, 0.4f) // Perform face, then eye detection using the facevacs SDK void project(const Template &src, Template &dst) const @@ -316,57 +315,39 @@ public: // Build an FRsdk image from the input openCV mat FRsdk::CountedPtr i(new FRsdk::OpenCVImageBody(src)); FRsdk::Image img(i); - FRsdk::Face::LocationSet faceLocations = faceFinder->find(img, minRelEyeDistance, maxRelEyeDistance); - - // If the face finder doesn't find anything mark the output as a failure - if (faceLocations.empty() ) { - dst.file.setBool("FTE"); - return; - } - - QList ROIs; - QList landmarks; - FRsdk::Face::LocationSet::const_iterator faceLocationSetIterator = faceLocations.begin(); - bool any_eyes = false; // Attempt to detect eyes in any face ROIs that were detected + QList rects; + QList points; + FRsdk::Face::LocationSet::const_iterator faceLocationSetIterator = faceLocations.begin(); while (faceLocationSetIterator != faceLocations.end()) { FRsdk::Face::Location faceLocation = *faceLocationSetIterator; faceLocationSetIterator++; FRsdk::Eyes::LocationSet currentEyesLocations = eyesFinder->find(img, faceLocation); if (currentEyesLocations.size() > 0) { - any_eyes = true; - ROIs.append(QRectF(faceLocation.pos.x(), faceLocation.pos.y(), faceLocation.width, faceLocation.width)); - landmarks.append(QPointF(currentEyesLocations.front().first.x(), currentEyesLocations.front().first.y())); - landmarks.append(QPointF(currentEyesLocations.front().second.x(), currentEyesLocations.front().second.y())); - - dst += src; + rects.append(QRectF(faceLocation.pos.x(), faceLocation.pos.y(), faceLocation.width, faceLocation.width)); + points.append(QPointF(currentEyesLocations.front().first.x(), currentEyesLocations.front().first.y())); + points.append(QPointF(currentEyesLocations.front().second.x(), currentEyesLocations.front().second.y())); + dst += src.m(); + if (!Globals->enrollAll) break; } - - if (any_eyes && !Globals->enrollAll && !dst.isEmpty()) break; } // If eye detection failed, mark the output as a failure - if (!any_eyes) { - dst.file.setBool("FTE"); - return; + if (dst.isEmpty()) { + dst.file.set("FTE", true); + if (!Globals->enrollAll) dst += Mat(); } - - dst.file.setROIs(ROIs); - dst.file.setLandmarks(landmarks); + dst.file.appendRects(rects); + dst.file.appendPoints(points); } catch (std::exception &e) { qFatal("CT8Enroll Exception: %s", e.what()); } - - if (!Globals->enrollAll && dst.isEmpty()) dst += Mat(); - } -private: - BR_PROPERTY(float, minRelEyeDistance, 0.01f) - BR_PROPERTY(float, maxRelEyeDistance, 0.4f) + } }; -BR_REGISTER(Transform, CT8Detect) +BR_REGISTER(Transform, CT8DetectTransform) /*! * \ingroup transforms @@ -374,10 +355,11 @@ BR_REGISTER(Transform, CT8Detect) * \author Josh Klontz \cite jklontz * \author Charles Otto \cite caotto */ -struct CT8Enroll : public UntrainableTransform - , public CT8Context +class CT8EnrollTransform : public UntrainableTransform + , public CT8Context { Q_OBJECT + // enroll an image using the facevacs sdk. Generates a facevacs "fir" which // is their face representation. void project(const Template &src, Template &dst) const @@ -387,37 +369,31 @@ struct CT8Enroll : public UntrainableTransform FRsdk::Image img(i); // If we already have eye locations, use them - QList landmarks = src.file.landmarks(); - bool enroll_succeeded = false; - if (landmarks.size() == 2) { - enroll_succeeded = enroll(img, FRsdk::Eyes::Location(toPosition(landmarks[0]), toPosition(landmarks[1])), &(dst.m())); + QList points = src.file.points(); + bool enrollSucceeded = false; + if (points.size() == 2) { + enrollSucceeded = enroll(img, FRsdk::Eyes::Location(toPosition(points[0]), toPosition(points[1])), &(dst.m())); // Transfer previously detectd eye and face locations to the output dst. - dst.file.insert("CT8_First_Eye_X", landmarks[0].x()); - dst.file.insert("CT8_First_Eye_Y", landmarks[0].y()); - dst.file.insert("CT8_Second_Eye_X", landmarks[1].x()); - dst.file.insert("CT8_Second_Eye_Y", landmarks[1].y()); - - QList ROIs = src.file.ROIs(); - if (ROIs.size() == 1) { - dst.file.insert("CT8_Face_X", ROIs.first().x()); - dst.file.insert("CT8_Face_Y", ROIs.first().y()); - dst.file.insert("CT8_Face_Width", ROIs.first().width()); - dst.file.insert("CT8_Face_Height", ROIs.first().height()); - } + dst.file.set("First_Eye", points[0]); + dst.file.set("Second_Eye", points[1]); + + QList rects = src.file.rects(); + if (rects.size() == 1) + dst.file.set("Face", rects.first()); } else { // If we don't have eye locations already, calling enroll here // will cause facevacs to perform detection using default // parameters (and we will not receive the detected locations // as output). - enroll_succeeded = enroll(img, &(dst.m())); + enrollSucceeded = enroll(img, &(dst.m())); } + // If enrollment failed, mark this image as a failure. This will // typically only happen if we aren't using pre-detected eye // locations - if (!enroll_succeeded) - { - dst.file.setBool("FTE"); + if (!enrollSucceeded) { + dst.file.set("FTE", true); dst.m() = Mat(); } } catch (std::exception &e) { @@ -426,7 +402,7 @@ struct CT8Enroll : public UntrainableTransform } }; -BR_REGISTER(Transform, CT8Enroll) +BR_REGISTER(Transform, CT8EnrollTransform) /*! * \ingroup distances diff --git a/sdk/plugins/draw.cpp b/sdk/plugins/draw.cpp index 529b218..6fd0c74 100644 --- a/sdk/plugins/draw.cpp +++ b/sdk/plugins/draw.cpp @@ -32,14 +32,14 @@ namespace br class DrawTransform : public UntrainableTransform { Q_OBJECT - Q_PROPERTY(bool verbose READ get_verbose WRITE set_verbose RESET reset_verbose STORED false) Q_PROPERTY(bool named READ get_named WRITE set_named RESET reset_named STORED false) - Q_PROPERTY(bool unnamed READ get_unnamed WRITE set_unnamed RESET reset_unnamed STORED false) - Q_PROPERTY(bool ROI READ get_ROI WRITE set_ROI RESET reset_ROI STORED false) - BR_PROPERTY(bool, verbose, false) + Q_PROPERTY(bool verbose READ get_verbose WRITE set_verbose RESET reset_verbose STORED false) + Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false) + Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) BR_PROPERTY(bool, named, true) - BR_PROPERTY(bool, unnamed, true) - BR_PROPERTY(bool, ROI, true) + BR_PROPERTY(bool, verbose, false) + BR_PROPERTY(bool, points, true) + BR_PROPERTY(bool, rects, true) void project(const Template &src, Template &dst) const { @@ -47,26 +47,18 @@ class DrawTransform : public UntrainableTransform const Scalar verboseColor(255, 255, 0); dst = src.m().clone(); - QList landmarks = OpenCVUtils::toPoints(src.file.points()); - - if (unnamed) { - foreach (const Point2f &landmark, landmarks) - circle(dst, landmark, 3, color, -1); - } - if (named) { - QList namedLandmarks = OpenCVUtils::toPoints(src.file.namedPoints()); - foreach (const Point2f &landmark, namedLandmarks) - circle(dst, landmark, 3, color); + if (points) { + const QList pointsList = OpenCVUtils::toPoints(named ? src.file.namedPoints() : src.file.points()); + for (int i=0; i ROIs = OpenCVUtils::toRects(src.file.rects()); - foreach (const Rect ROI, ROIs) - rectangle(dst, ROI, color); + if (rects) { + foreach (const Rect &rect, OpenCVUtils::toRects(named ? src.file.namedRects() : src.file.rects())) + rectangle(dst, rect, color); } - - if (verbose) - for (int i=0; i(i+scale,(j+scale)*bins+k) - - integral.at(i+scale, j *bins+k) - - integral.at(i ,(j+scale)*bins+k) - + integral.at(i , j *bins+k); - mean += k*buffer[k]; - } - mean /= count; - - float variance = 0; - for (int k=0; k::max(); - QRectF bestRect; - - const int rows = m.rows; - const int cols = m.cols/bins; - const int maxSize = min(m.rows, m.cols/bins); - int scale = 2; - while (scale < maxSize) { - const int step = std::max(1, scale/6); - for (int i=0; i+scale < rows; i+=step) { - for (int j=0; j+scale < cols; j+=step) { - float internalStdDev = stddev(m, i, j, scale, buffer); - float externalStdDev = std::numeric_limits::max(); - externalStdDev = std::min(externalStdDev, ((i-2*scale >= 0) && (j-2*scale >= 0)) ? stddev(m, i-2*scale, j-2*scale, scale, buffer) : 0); - externalStdDev = std::min(externalStdDev, (i-2*scale >= 0) ? stddev(m, i-2*scale, j , scale, buffer) : 0); - externalStdDev = std::min(externalStdDev, ((i-2*scale >= 0) && (j+3*scale < cols)) ? stddev(m, i-2*scale, j+2*scale, scale, buffer) : 0); - externalStdDev = std::min(externalStdDev, (j+3*scale < cols) ? stddev(m, i , j+2*scale, scale, buffer) : 0); - externalStdDev = std::min(externalStdDev, ((i+3*scale < rows) && (j+3*scale < cols)) ? stddev(m, i+2*scale, j+2*scale, scale, buffer) : 0); - externalStdDev = std::min(externalStdDev, (i+3*scale < rows) ? stddev(m, i+2*scale, j , scale, buffer) : 0); - externalStdDev = std::min(externalStdDev, ((i+3*scale < rows) && (j-2*scale >= 0)) ? stddev(m, i+2*scale, j-2*scale, scale, buffer) : 0); - externalStdDev = std::min(externalStdDev, (j-2*scale >= 0) ? stddev(m, i , j-2*scale, scale, buffer) : 0); - - float ratio; - if (externalStdDev == 0) ratio = 0; - else if (internalStdDev == 0) ratio = std::numeric_limits::max() * (float(scale)/float(maxSize)); - else ratio = scale*scale * pow(externalStdDev,2) / pow(internalStdDev, 2); - - if (ratio > bestRatio) { - bestRatio = ratio; - bestRect = QRect(j*radius, i*radius, scale*radius, scale*radius); - } - } - } - scale = std::max(scale+1, int(scale*1.25)); - } - - delete[] buffer; - dst.file.appendRect(bestRect); - dst.file.setLabel(bestRatio); - } -}; - -BR_REGISTER(Transform, VarianceChangeDetectorTransform) - } // namespace br #include "hist.moc" diff --git a/sdk/plugins/integral.cpp b/sdk/plugins/integral.cpp index 152cb41..f19fdc0 100644 --- a/sdk/plugins/integral.cpp +++ b/sdk/plugins/integral.cpp @@ -1,6 +1,9 @@ #include +#include #include +using namespace cv; + namespace br { @@ -15,7 +18,7 @@ class IntegralTransform : public UntrainableTransform void project(const Template &src, Template &dst) const { - cv::integral(src, dst); + integral(src, dst); } }; @@ -23,6 +26,71 @@ BR_REGISTER(Transform, IntegralTransform) /*! * \ingroup transforms + * \brief Sliding window object recognition from a multi-channel intergral image. + * \author Josh Klontz \cite jklontz + */ +class IntegralSampler : public UntrainableTransform +{ + Q_OBJECT + Q_PROPERTY(int scales READ get_scales WRITE set_scales RESET reset_scales STORED false) + Q_PROPERTY(float scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) + Q_PROPERTY(float stepFactor READ get_stepFactor WRITE set_stepFactor RESET reset_stepFactor STORED false) + Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) + BR_PROPERTY(int, scales, 1) + BR_PROPERTY(float, scaleFactor, 1.25) + BR_PROPERTY(float, stepFactor, 0.25) + BR_PROPERTY(int, minSize, 8) + + void project(const Template &src, Template &dst) const + { + typedef Eigen::Map< const Eigen::Matrix > InputDescriptor; + typedef Eigen::Map< Eigen::Matrix > OutputDescriptor; + const Mat &m = src.m(); + if (m.depth() != CV_32S) qFatal("Expected CV_32S matrix depth."); + const int channels = m.channels(); + const int rowStep = channels * m.cols; + + int descriptors = 0; + int currentSize = min(m.rows, m.cols)-1; + for (int scale=0; scale("ForceEnrollment", false) && !dst.isEmpty()) break; } - dst.file.appendLandmarks(landmarks); + dst.file.appendPoints(landmarks); contexts.release(context); - if (!src.file.getBool("enrollAll") && dst.isEmpty()) dst += cv::Mat(); + if (!src.file.get("enrollAll", false) && dst.isEmpty()) dst += cv::Mat(); } }; diff --git a/sdk/plugins/quality.cpp b/sdk/plugins/quality.cpp index 561fa48..be2730c 100644 --- a/sdk/plugins/quality.cpp +++ b/sdk/plugins/quality.cpp @@ -79,7 +79,7 @@ struct KDE double mean, stddev; QList bins; - KDE() : min(0), max(1) {} + KDE() : min(0), max(1), mean(0), stddev(1) {} KDE(const QList &scores) { Common::MinMax(scores, &min, &max); diff --git a/sdk/plugins/regions.cpp b/sdk/plugins/regions.cpp index 7f13a9e..6248879 100644 --- a/sdk/plugins/regions.cpp +++ b/sdk/plugins/regions.cpp @@ -111,6 +111,26 @@ BR_REGISTER(Transform, CatTransform) /*! * \ingroup transforms + * \brief Wraps OpenCV merge + * \author Josh Klontz \cite jklontz + */ +class MergeTransform : public UntrainableMetaTransform +{ + Q_OBJECT + + void project(const Template &src, Template &dst) const + { + std::vector mv; + foreach (const Mat &m, src) + mv.push_back(m); + merge(mv, dst); + } +}; + +BR_REGISTER(Transform, MergeTransform) + +/*! + * \ingroup transforms * \brief Duplicates the template data. * \author Josh Klontz \cite jklontz */ diff --git a/sdk/plugins/youtube.cpp b/sdk/plugins/youtube.cpp index 1a96ddc..8954fe6 100644 --- a/sdk/plugins/youtube.cpp +++ b/sdk/plugins/youtube.cpp @@ -1,3 +1,4 @@ +#include #include #include "core/common.h" @@ -16,16 +17,6 @@ class YouTubeFacesDBTransform : public UntrainableMetaTransform Q_PROPERTY(QString algorithm READ get_algorithm WRITE set_algorithm RESET reset_algorithm STORED false) BR_PROPERTY(QString, algorithm, "") - QSharedPointer transform; - QSharedPointer distance; - - void init() - { - if (algorithm.isEmpty()) return; - transform = Transform::fromAlgorithm(algorithm); - distance = Distance::fromAlgorithm(algorithm); - } - void project(const TemplateList &src, TemplateList &dst) const { Transform::project(src.mid(1) /* First template is the header in 'splits.txt' */, dst); @@ -33,22 +24,19 @@ class YouTubeFacesDBTransform : public UntrainableMetaTransform void project(const Template &src, Template &dst) const { + static QMutex mutex; const QStringList words = src.file.name.split(", "); - dst.file.name = words[0] + "_" + words[1] + "_" + words[4] + ".mtx"; - - TemplateList queryTemplates = TemplateList::fromGallery(File(words[2]).resolved()); - sort(queryTemplates); - queryTemplates >> *transform; - - TemplateList targetTemplates = TemplateList::fromGallery(File(words[3]).resolved()); - sort(targetTemplates); - targetTemplates >> *transform; - - QScopedPointer memoryOutput(MatrixOutput::make(targetTemplates.files(), queryTemplates.files())); - distance->compare(targetTemplates, queryTemplates, memoryOutput.data()); - - dst.clear(); - dst.m() = memoryOutput.data()->data; + const QString matrix = "YTF-"+algorithm+"/"+words[0] + "_" + words[1] + "_" + words[4] + ".mtx"; + const QStringList arguments = QStringList() << "-algorithm" << algorithm + << "-parallelism" << QString::number(Globals->parallelism) + << "-path" << Globals->path + << "-compare" << File(words[2]).resolved() << File(words[3]).resolved() << matrix; + mutex.lock(); + int result = QProcess::execute(QCoreApplication::applicationFilePath(), arguments); + mutex.unlock(); + if (result != 0) + qWarning("Process for computing %s returned %d.", qPrintable(matrix), result); + dst = Template(); } static void sort(TemplateList &templates)