diff --git a/app/br/br.cpp b/app/br/br.cpp index f65c1c7..938a035 100644 --- a/app/br/br.cpp +++ b/app/br/br.cpp @@ -68,12 +68,13 @@ public: if (argc == 0) printf("%s\nTry running 'br -help'\n", br_about()); bool daemon = false; + const char *daemon_pipe = NULL; while (daemon || (argc > 0)) { const char *fun; int parc; const char **parv; if (argc == 0) - br_read_stdin(&argc, &argv); + br_read_pipe(daemon_pipe, &argc, &argv); fun = argv[0]; if (fun[0] == '-') fun++; @@ -158,8 +159,9 @@ public: check(parc == 0, "No parameters expected for 'version'."); printf("%s\n", br_version()); } else if (!strcmp(fun, "daemon")) { - check(parc == 0, "No parameters expected for 'daemon'."); + check(parc == 1, "Incorrect parameter count for 'daemon'."); daemon = true; + daemon_pipe = parv[0]; } else if (!strcmp(fun, "exit")) { check(parc == 0, "No parameters expected for 'exit'."); daemon = false; diff --git a/openbr/core/core.cpp b/openbr/core/core.cpp index 639c3b3..bf1b959 100644 --- a/openbr/core/core.cpp +++ b/openbr/core/core.cpp @@ -275,17 +275,14 @@ private: return QFileInfo(file).exists() ? file : QString(); } - void init(QString description) + void init(const File &description) { // Check if a trained binary already exists for this algorithm const QString file = getFileName(description); - if (!file.isEmpty()) description = file; + if (!file.isEmpty()) return init(file); - File asdf(description); - QString distribute_status = asdf.get("distribute","true"); - - if (QFileInfo(description).exists()) { - qDebug("Loading %s", qPrintable(QFileInfo(description).fileName())); + if (description.exists()) { + qDebug("Loading %s", qPrintable(description.fileName())); load(description); return; } @@ -294,13 +291,11 @@ private: if (Globals->abbreviations.contains(description)) return init(Globals->abbreviations[description]); - QStringList words = QtUtils::parse(description, ':'); - if (words.size() > 2) qFatal("Invalid algorithm format."); + QStringList words = QtUtils::parse(description.flat(), ':'); + if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format."); - if (distribute_status == "true") { - words[0].prepend("DistributeTemplate("); - words[0].append(")"); - } + if (description.getBool("distribute", true)) + words[0] = "DistributeTemplate(" + words[0] + ")"; transform = QSharedPointer(Transform::make(words[0], NULL)); if (words.size() > 1) distance = QSharedPointer(Distance::make(words[1], NULL)); diff --git a/openbr/openbr.cpp b/openbr/openbr.cpp index 38c2980..fc48bf8 100644 --- a/openbr/openbr.cpp +++ b/openbr/openbr.cpp @@ -182,17 +182,23 @@ float br_progress() return Globals->progress(); } -void br_read_stdin(int *argc, char ***argv) +void br_read_pipe(const char *pipe, int *argc, char ***argv) { static QList byteArrayList; static QVector rawCharArrayList; + QFile file(pipe); + file.open(QFile::ReadOnly); + QTextStream stream(&file); + QStringList args; while (args.isEmpty()) { - args = QtUtils::parse(QTextStream(stdin).readLine(), ' '); - QThread::yieldCurrentThread(); + args = QtUtils::parse(stream.readAll(), ' '); + if (args.isEmpty()) QThread::sleep(100); } + file.close(); + byteArrayList.clear(); rawCharArrayList.clear(); foreach (const QString &string, args) { byteArrayList.append(string.toLocal8Bit()); diff --git a/openbr/openbr.h b/openbr/openbr.h index 9048729..9cf5df7 100644 --- a/openbr/openbr.h +++ b/openbr/openbr.h @@ -297,16 +297,15 @@ BR_EXPORT bool br_plot_metadata(int num_files, const char *files[], const char * BR_EXPORT float br_progress(); /*! - * \brief Read and parse stdin. + * \brief Read and parse arguments from a named pipe. * - * Used by the \ref cli to implement \c -daemon. + * Used by the \ref cli to implement \c -daemon, generally not useful otherwise. * Guaranteed to return at least one argument. - * Generally not useful otherwise. * \param[out] argc argument count * \param[out] argv argument list * \note \ref managed_return_value */ -BR_EXPORT void br_read_stdin(int *argc, char ***argv); +BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv); /*! * \brief Converts a simmat to a new output format. diff --git a/openbr/openbr_plugin.cpp b/openbr/openbr_plugin.cpp index 24270c7..6645796 100644 --- a/openbr/openbr_plugin.cpp +++ b/openbr/openbr_plugin.cpp @@ -801,8 +801,8 @@ void br::Context::setProperty(const QString &key, const QString &value) qDebug("Set %s%s", qPrintable(key), value.isEmpty() ? "" : qPrintable(" to " + value)); if (key == "parallelism") { - const int maxThreads = std::max(1, QThread::idealThreadCount()); - QThreadPool::globalInstance()->setMaxThreadCount(parallelism ? std::min(maxThreads, abs(parallelism)) : maxThreads); + if (parallelism <= 0) parallelism = 1; + QThreadPool::globalInstance()->setMaxThreadCount(parallelism); } else if (key == "log") { logFile.close(); if (log.isEmpty()) return; @@ -829,8 +829,17 @@ bool br::Context::checkSDKPath(const QString &sdkPath) // We create our own when the user hasn't static QCoreApplication *application = NULL; -void br::Context::initialize(int &argc, char *argv[], QString sdkPath) +void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool use_gui) { + for (int i=0; i < argc; i ++) + { + if (strcmp("-useGui", argv[i]) == 0) { + const char * val = i+1 < argc ? argv[i+1] : ""; + if (strcmp(val, "false") ==0 || strcmp(val, "0") == 0) + use_gui = false; + break; + } + } // We take in argc as a reference due to: // https://bugreports.qt-project.org/browse/QTBUG-5637 // QApplication should be initialized before anything else. @@ -861,6 +870,7 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath) Globals = new Context(); Globals->init(File()); + Globals->useGui = use_gui; qInstallMessageHandler(messageHandler); @@ -885,8 +895,7 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath) } Globals->sdkPath = sdkPath; - // Empirical evidence suggests an extra thread helps achieve full CPU utilization - QThreadPool::globalInstance()->releaseThread(); + QThreadPool::globalInstance()->setMaxThreadCount(Globals->parallelism); // Trigger registered initializers QList< QSharedPointer > initializers = Factory::makeAll(); @@ -896,9 +905,6 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath) void br::Context::finalize() { - // Undo the 'releaseThread()' in 'initialize()' - QThreadPool::globalInstance()->reserveThread(); - // Trigger registered finalizers QList< QSharedPointer > initializers = Factory::makeAll(); foreach (const QSharedPointer &initializer, initializers) @@ -1192,10 +1198,8 @@ private: templatesList[i] = Downsample(templatesList[i], transforms[i]); QFutureSynchronizer futures; - for (int i=0; iparallelism) futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); - else _train (transforms[i], &templatesList[i]); - } + for (int i=0; iparallelism == 0)) { - foreach (const Template &t, src) { - dst.append(Template()); - _project(this, &t, &dst.last()); - } - } else { - for (int i=0; i futures; - for (int i=0; i futures; + for (int i=0; i futures; for (int i=0; iparallelism) futures.addFuture(QtConcurrent::run(_backProject, this, &dst[i], &src[i])); - else _backProject (this, &dst[i], &src[i]); + futures.addFuture(QtConcurrent::run(_backProject, this, &dst[i], &src[i])); futures.waitForFinished(); } diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index bf95754..e7a03a3 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -189,6 +189,7 @@ struct BR_EXPORT File inline QString baseName() const { const QString baseName = QFileInfo(name).baseName(); return baseName.isEmpty() ? QDir(name).dirName() : baseName; } /*!< \brief Returns the file's base name. */ inline QString suffix() const { return QFileInfo(name).suffix(); } /*!< \brief Returns the file's extension. */ + inline QString path() const { return QFileInfo(name).path(); } /*! \brief Returns the file's path excluding its name. */ QString resolved() const; /*!< \brief Returns name prepended with Globals->path if name does not exist. */ bool contains(const QString &key) const; /*!< \brief Returns \c true if the key has an associated value, \c false otherwise. */ @@ -547,7 +548,13 @@ public: * \brief The number of threads to use. */ Q_PROPERTY(int parallelism READ get_parallelism WRITE set_parallelism RESET reset_parallelism) - BR_PROPERTY(int, parallelism, std::max(1, QThread::idealThreadCount())) + BR_PROPERTY(int, parallelism, std::max(1, QThread::idealThreadCount()+1)) + + /*! + * \brief Whether or not to use GUI functions + */ + Q_PROPERTY(bool useGui READ get_useGui WRITE set_useGui RESET reset_useGui) + BR_PROPERTY(bool, useGui, true) /*! * \brief The maximum number of templates to process in parallel. @@ -701,7 +708,7 @@ public: * \note Qt users should instead call this after initializing QApplication. * \see finalize */ - static void initialize(int &argc, char *argv[], QString sdkPath = ""); + static void initialize(int &argc, char *argv[], QString sdkPath = "", bool use_gui = true); /*! * \brief Call \em once at the end of the application to deallocate global variables. diff --git a/openbr/plugins/algorithms.cpp b/openbr/plugins/algorithms.cpp index 6311576..c11f534 100644 --- a/openbr/plugins/algorithms.cpp +++ b/openbr/plugins/algorithms.cpp @@ -38,11 +38,11 @@ class AlgorithmsInitializer : public Initializer 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("ShowFaceDetection", "DrawFaceDetection!Show[distribute=false]"); Globals->abbreviations.insert("OpenBR", "FaceRecognition"); Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); - Globals->abbreviations.insert("FaceRecognition2", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+(Gradient+Bin(0,360,9,true))/(Blur(1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2,true)+Bin(0,10,10,true))+Merge+Integral+RecursiveIntegralSampler(4,2,8,Center(Hellinger)+LDA(.98)+Normalize(L1)+Cat+PCA(768)+Normalize(L1)+Quantize:UCharL1"); + Globals->abbreviations.insert("FaceRecognition2", "{PP5Register+Affine(128,128,0.25,0.35)+Cvt(Gray)}+(Gradient+Bin(0,360,9,true))/(Blur(1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2,true)+Bin(0,10,10,true))+Merge+Integral+RecursiveIntegralSampler(4,2,8,LDA(.98)+Normalize(L1))+Cat+PCA(768)+Normalize(L1)+Quantize:UCharL1"); // Generic Image Processing Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); diff --git a/openbr/plugins/distance.cpp b/openbr/plugins/distance.cpp index cb07e12..f0eb470 100644 --- a/openbr/plugins/distance.cpp +++ b/openbr/plugins/distance.cpp @@ -158,8 +158,7 @@ class PipeDistance : public Distance { QFutureSynchronizer futures; foreach (br::Distance *distance, distances) - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); - else distance->train(data); + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); futures.waitForFinished(); } diff --git a/openbr/plugins/draw.cpp b/openbr/plugins/draw.cpp index 82d7edd..fcedc38 100644 --- a/openbr/plugins/draw.cpp +++ b/openbr/plugins/draw.cpp @@ -98,6 +98,8 @@ class DrawGridTransform : public UntrainableTransform BR_REGISTER(Transform, DrawGridTransform) +// TODO: re-implement EditTransform using Qt +#if 0 /*! * \ingroup transforms * \brief Remove landmarks. @@ -162,6 +164,7 @@ Template EditTransform::currentTemplate; QMutex EditTransform::currentTemplateLock; BR_REGISTER(Transform, EditTransform) +#endif } // namespace br diff --git a/openbr/plugins/format.cpp b/openbr/plugins/format.cpp index 581577d..048ed13 100644 --- a/openbr/plugins/format.cpp +++ b/openbr/plugins/format.cpp @@ -15,6 +15,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include +#include #ifndef BR_EMBEDDED #include #endif // BR_EMBEDDED @@ -547,14 +548,43 @@ BR_REGISTER(Format, nullFormat) class rawFormat : public Format { Q_OBJECT + static QHash > imageSizes; // QHash > Template read() const { + QString path = file.path(); + if (!imageSizes.contains(path)) { + static QMutex mutex; + QMutexLocker locker(&mutex); + + if (!imageSizes.contains(path)) { + const QString imageSize = path+"/ImageSize.txt"; + QStringList lines; + if (QFileInfo(imageSize).exists()) { + lines = QtUtils::readLines(imageSize); + lines.removeFirst(); // Remove header + } + + QHash sizes; + QRegExp whiteSpace("\\s+"); + foreach (const QString &line, lines) { + QStringList words = line.split(whiteSpace); + if (words.size() != 3) continue; + sizes.insert(words[0], QSize(words[2].toInt(), words[1].toInt())); + } + + imageSizes.insert(path, sizes); + } + } + QByteArray data; QtUtils::readFile(file, data); - if (data.size() != 768*800) - qFatal("Expected 768*800 bytes."); - return Template(file, Mat(768, 800, CV_8UC1, data.data()).clone()); + + QSize size = imageSizes[path][file.baseName()]; + if (!size.isValid()) size = QSize(800,768); + if (data.size() != size.width() * size.height()) + qFatal("Expected %d*%d bytes, got %d.", size.height(), size.width(), data.size()); + return Template(file, Mat(size.height(), size.width(), CV_8UC1, data.data()).clone()); } void write(const Template &t) const @@ -563,6 +593,8 @@ class rawFormat : public Format } }; +QHash > rawFormat::imageSizes; + BR_REGISTER(Format, rawFormat) /*! diff --git a/openbr/plugins/gallery.cpp b/openbr/plugins/gallery.cpp index 07ef58e..e950943 100644 --- a/openbr/plugins/gallery.cpp +++ b/openbr/plugins/gallery.cpp @@ -107,8 +107,7 @@ class EmptyGallery : public Gallery QList< QFuture > futures; foreach (const QString &folder, NaturalStringSort(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))) { const QDir subdir = dir.absoluteFilePath(folder); - if (Globals->parallelism) futures.append(QtConcurrent::run(&EmptyGallery::getTemplates, subdir)); - else templates.append(getTemplates(subdir)); + futures.append(QtConcurrent::run(&EmptyGallery::getTemplates, subdir)); } foreach (const QFuture &future, futures) templates.append(future.result()); diff --git a/openbr/plugins/gui.cpp b/openbr/plugins/gui.cpp index 9d97429..b0000b8 100644 --- a/openbr/plugins/gui.cpp +++ b/openbr/plugins/gui.cpp @@ -94,6 +94,8 @@ public slots: void createWindow() { delete window; + QApplication::instance()->removeEventFilter(this); + window = new QLabel(); window->setVisible(true); @@ -109,21 +111,25 @@ public slots: * \ingroup transforms * \brief Displays templates in a GUI pop-up window using QT. * \author Charles Otto \cite caotto - * Unlike ShowTransform, this can be used with parallelism enabled, although it - * is considered TimeVarying. + * Can be used with parallelism enabled, although it is considered TimeVarying. */ -class Show2Transform : public TimeVaryingTransform +class ShowTransform : public TimeVaryingTransform { Q_OBJECT public: Q_PROPERTY(bool waitInput READ get_waitInput WRITE set_waitInput RESET reset_waitInput STORED false) - BR_PROPERTY(bool, waitInput, false) + BR_PROPERTY(bool, waitInput, true) Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) BR_PROPERTY(QStringList, keys, QStringList("FrameNumber")) - Show2Transform() : TimeVaryingTransform(false, false) + ShowTransform() : TimeVaryingTransform(false, false) { + gui = NULL; + displayBuffer = NULL; + if (!Globals->useGui) + return; + displayBuffer = new QPixmap(); // Create our GUI proxy gui = new GUIProxy(); // Move it to the main thread, this means signals we send to it will @@ -134,16 +140,17 @@ public: connect(this, SIGNAL(updateImage(QPixmap)), gui,SLOT(showImage(QPixmap))); } - ~Show2Transform() + ~ShowTransform() { delete gui; + delete displayBuffer; } void train(const TemplateList &data) { (void) data; } void project(const TemplateList &src, TemplateList &dst) const { - Transform * non_const = (Show2Transform *) this; + Transform * non_const = (ShowTransform *) this; non_const->projectUpdate(src,dst); } @@ -151,7 +158,7 @@ public: { dst = src; - if (src.empty()) + if (src.empty() || !Globals->useGui) return; foreach (const Template & t, src) { @@ -168,12 +175,12 @@ public: foreach(const cv::Mat & m, t) { qImageBuffer = toQImage(m); - displayBuffer.convertFromImage(qImageBuffer); + displayBuffer->convertFromImage(qImageBuffer); // Emit an explicit copy of our pixmap so that the pixmap used // by the main thread isn't damaged when we update displayBuffer // later. - emit updateImage(displayBuffer.copy(displayBuffer.rect())); + emit updateImage(displayBuffer->copy(displayBuffer->rect())); // Blocking wait for a key-press if (this->waitInput) @@ -191,6 +198,9 @@ public: void init() { + if (!Globals->useGui) + return; + emit needWindow(); connect(this, SIGNAL(changeTitle(QString)), gui->window, SLOT(setWindowTitle(QString))); connect(this, SIGNAL(hideWindow()), gui->window, SLOT(hide())); @@ -199,7 +209,7 @@ public: protected: GUIProxy * gui; QImage qImageBuffer; - QPixmap displayBuffer; + QPixmap * displayBuffer; signals: void needWindow(); @@ -208,7 +218,7 @@ signals: void hideWindow(); }; -BR_REGISTER(Transform, Show2Transform) +BR_REGISTER(Transform, ShowTransform) class FPSSynch : public TimeVaryingTransform { diff --git a/openbr/plugins/meta.cpp b/openbr/plugins/meta.cpp index 59b3cb3..a018244 100644 --- a/openbr/plugins/meta.cpp +++ b/openbr/plugins/meta.cpp @@ -109,8 +109,7 @@ class PipeTransform : public CompositeTransform fprintf(stderr, " projecting..."); QFutureSynchronizer futures; for (int j=0; jparallelism) futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, ©[j], i, nextTrainableTransform)); - else _projectPartial( ©[j], i, nextTrainableTransform); + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, ©[j], i, nextTrainableTransform)); futures.waitForFinished(); i = nextTrainableTransform; } @@ -288,10 +287,8 @@ class ForkTransform : public CompositeTransform { if (!trainable) return; QFutureSynchronizer futures; - for (int i=0; iparallelism) futures.addFuture(QtConcurrent::run(_train, transforms[i], &data)); - else _train (transforms[i], &data); - } + for (int i=0; isetProperty("parallelism", "0"); // Can only work in single threaded mode - } - - void project(const Template &src, Template &dst) const - { - dst = src; - - if (Globals->parallelism) { - qWarning("Show::project() only works in single threaded mode."); - return; - } - - for (int i=0; i 1 ? "-" + QString::number(uid*src.size()+i) : QString()), false); - - if (waitKey && !src.isEmpty()) cv::waitKey(-1); - } -}; - -int ShowTransform::counter = 0; - -BR_REGISTER(Transform, ShowTransform) - -/*! - * \ingroup transforms * \brief Prints the template's file to stdout or stderr. * \author Josh Klontz \cite jklontz */ @@ -368,6 +328,8 @@ class AnonymizeTransform : public UntrainableMetaTransform BR_REGISTER(Transform, AnonymizeTransform) +// TODO: Use a global Mutex to prevent concurrent reads from stdin +#if 0 /*! * \ingroup transforms * \brief Name a point @@ -415,6 +377,7 @@ class ElicitMetadataTransform : public UntrainableMetaTransform }; BR_REGISTER(Transform, ElicitMetadataTransform) +#endif /*! * \ingroup transforms diff --git a/openbr/plugins/neclatent1.cpp b/openbr/plugins/neclatent1.cpp index cf1a461..525fe9d 100644 --- a/openbr/plugins/neclatent1.cpp +++ b/openbr/plugins/neclatent1.cpp @@ -18,9 +18,12 @@ class NECLatent1Initialier : public Initializer void initialize() const { - Globals->abbreviations.insert("NECTenprint1", "Open+Cvt(Gray)+NECLatent1Enroll:NECLatent1Compare"); - Globals->abbreviations.insert("NECLatent1", "Open+Cvt(Gray)+NECLatent1Enroll(true):NECLatent1Compare"); - Globals->abbreviations.insert("NECLatentLFFS1", "Open+NECLatent1Enroll(true,ELFT_M):NECLatent1Compare(ELFT_M)"); + Globals->abbreviations.insert("NECTenprintLFML", "Open+Cvt(Gray)+NECLatent1Enroll(false,LFML):NECLatent1Compare(LFML)"); + Globals->abbreviations.insert("NECTenprintELFT", "Open+Cvt(Gray)+NECLatent1Enroll(false,ELFT):NECLatent1Compare(ELFT)"); + Globals->abbreviations.insert("NECTenprintELFTM", "Open+Cvt(Gray)+NECLatent1Enroll(false,ELFT_M):NECLatent1Compare(ELFT_M)"); + Globals->abbreviations.insert("NECLatentLFML", "Open+Cvt(Gray)+NECLatent1Enroll(true,LFML):NECLatent1Compare(LFML)"); + Globals->abbreviations.insert("NECLatentELFT", "Open+Cvt(Gray)+NECLatent1Enroll(true,ELFT):NECLatent1Compare(ELFT)"); + Globals->abbreviations.insert("NECLatentELFTM", "Open+NECLatent1Enroll(true,ELFT_M):NECLatent1Compare(ELFT_M)"); } }; @@ -50,23 +53,25 @@ private: void project(const Template &src, Template &dst) const { + static QMutex mutex; + QMutexLocker locker(&mutex); // It seems that most of the API is not reentrant + if (src.m().type() != CV_8UC1) qFatal("Requires 8UC1 data!"); uchar *data = src.m().data; const int rows = src.m().rows; const int columns = src.m().cols; uchar buff[MAX_TEMPLATE_SIZE]; uchar* pBuff = NULL; - int size = 0; - int error; + int size, error; if (latent) { if (algorithm == LFML) error = NEC_LFML_ExtractLatent(data, rows, columns, 500, buff, &size); - else if (algorithm == ELFT) error = NEC_ELFT_ExtractLatent(data, rows, columns, 500, 4, buff, &size); - else error = NEC_ELFT_M_ExtractLatent(data, columns, 1, &pBuff, &size); + else if (algorithm == ELFT) error = NEC_ELFT_ExtractLatent(data, rows, columns, 500, 32, buff, &size); + else error = NEC_ELFT_M_ExtractLatent(data, columns, 5, &pBuff, &size); } else { if (algorithm == LFML) error = NEC_LFML_ExtractTenprint(data, rows, columns, 500, buff, &size); - else if (algorithm == ELFT) error = NEC_ELFT_ExtractTenprint(data, rows, columns, 500, 2, buff, &size); - else qFatal("ELFT_M Tenprint not implemented."); + else if (algorithm == ELFT) error = NEC_ELFT_ExtractTenprint(data, rows, columns, 500, 8, buff, &size); + else error = NEC_ELFT_M_ExtractTenprint(data, rows, columns, 500, 5, &pBuff, &size); } if (!error) { @@ -109,10 +114,12 @@ private: uchar *aData = a.m().data; uchar *bData = b.m().data; if (!a.m().data || !b.m().data) return -std::numeric_limits::max(); - int score; - if (algorithm == LFML) NEC_LFML_Verify(bData, b.m().total(), aData, a.m().total(), &score); - else if (algorithm == ELFT) NEC_ELFT_Verify(bData, aData, &score, 1); - else NEC_ELFT_M_Verify(bData, aData, &score, 1); + int score, error; + if (algorithm == LFML) error = NEC_LFML_Verify(bData, b.m().total(), aData, a.m().total(), &score); + else if (algorithm == ELFT) error = NEC_ELFT_Verify(bData, aData, &score, 1); + else error = NEC_ELFT_M_Verify(bData, aData, &score, 1); + if (error) + qWarning("NECLatent1CompareDistance error %d", error); return score; } }; diff --git a/openbr/plugins/normalize.cpp b/openbr/plugins/normalize.cpp index a3f4942..057e016 100644 --- a/openbr/plugins/normalize.cpp +++ b/openbr/plugins/normalize.cpp @@ -137,11 +137,9 @@ private: } QFutureSynchronizer futures; - const bool parallel = (data.size() > 1000) && Globals->parallelism; for (size_t c = 0; c < mv.size(); c++) { for (int i=0; i(0, i), &bv[c].at(0, i))); - else _train (method, mv[c].col(i), labels, &av[c].at(0, i), &bv[c].at(0, i)); + futures.addFuture(QtConcurrent::run(_train, method, mv[c].col(i), labels, &av[c].at(0, i), &bv[c].at(0, i))); av[c] = av[c].reshape(1, data.first().m().rows); bv[c] = bv[c].reshape(1, data.first().m().rows); } diff --git a/openbr/plugins/openbr_internal.h b/openbr/plugins/openbr_internal.h index 8faa7d4..fb7a1b5 100644 --- a/openbr/plugins/openbr_internal.h +++ b/openbr/plugins/openbr_internal.h @@ -221,7 +221,7 @@ public: Transform * maybe_copy = t->smartCopy(); if (maybe_copy->parent() == NULL) maybe_copy->setParent(output); - output->transforms.append(t->smartCopy()); + output->transforms.append(maybe_copy); } output->file = this->file; diff --git a/openbr/plugins/quantize.cpp b/openbr/plugins/quantize.cpp index 2a37edc..decffa3 100644 --- a/openbr/plugins/quantize.cpp +++ b/openbr/plugins/quantize.cpp @@ -82,8 +82,7 @@ class HistEqQuantizationTransform : public Transform QFutureSynchronizer futures; for (int i=0; iparallelism) futures.addFuture(QtConcurrent::run(&HistEqQuantizationTransform::computeThresholds, data.col(i), &thresholds.data()[i*256])); - else computeThresholds( data.col(i), &thresholds.data()[i*256]); + futures.addFuture(QtConcurrent::run(&HistEqQuantizationTransform::computeThresholds, data.col(i), &thresholds.data()[i*256])); futures.waitForFinished(); } @@ -156,8 +155,7 @@ class BayesianQuantizationDistance : public Distance QFutureSynchronizer futures; for (int i=0; iparallelism) futures.addFuture(QtConcurrent::run(&BayesianQuantizationDistance::computeLogLikelihood, data.col(i), templateLabels, &loglikelihoods.data()[i*256])); - else computeLogLikelihood( data.col(i), templateLabels, &loglikelihoods.data()[i*256]); + futures.addFuture(QtConcurrent::run(&BayesianQuantizationDistance::computeLogLikelihood, data.col(i), templateLabels, &loglikelihoods.data()[i*256])); futures.waitForFinished(); } diff --git a/openbr/plugins/quantize2.cpp b/openbr/plugins/quantize2.cpp index d392810..f6e69f1 100644 --- a/openbr/plugins/quantize2.cpp +++ b/openbr/plugins/quantize2.cpp @@ -83,8 +83,7 @@ class BayesianQuantizationTransform : public Transform QFutureSynchronizer futures; for (int i=0; iparallelism) futures.addFuture(QtConcurrent::run(&BayesianQuantizationTransform::computeThresholds, data.col(i), labels, &thresholds.data()[i*256])); - else computeThresholds( data.col(i), labels, &thresholds.data()[i*256]); + futures.addFuture(QtConcurrent::run(&BayesianQuantizationTransform::computeThresholds, data.col(i), labels, &thresholds.data()[i*256])); futures.waitForFinished(); } diff --git a/openbr/plugins/stasm.cpp b/openbr/plugins/stasm.cpp index 483968d..f6bdc03 100644 --- a/openbr/plugins/stasm.cpp +++ b/openbr/plugins/stasm.cpp @@ -33,7 +33,8 @@ BR_REGISTER(Initializer, StasmInitializer) * \brief Wraps STASM key point detector * \author Scott Klum \cite sklum */ - +// TODO: Use a global mutex to prevent concurrent calls to AsmSearchDll +#if 0 class StasmTransform : public UntrainableTransform { Q_OBJECT @@ -67,6 +68,7 @@ class StasmTransform : public UntrainableTransform }; BR_REGISTER(Transform, StasmTransform) +#endif } // namespace br diff --git a/openbr/plugins/stream.cpp b/openbr/plugins/stream.cpp index 89a29a7..391bc79 100644 --- a/openbr/plugins/stream.cpp +++ b/openbr/plugins/stream.cpp @@ -771,11 +771,6 @@ public: (void) src; (void) dst; qFatal("nope"); } - void project(const TemplateList & src, TemplateList & dst) const - { - (void) src; (void) dst; - qFatal("nope"); - } void projectUpdate(const Template &src, Template &dst) { diff --git a/openbr/plugins/validate.cpp b/openbr/plugins/validate.cpp index ea1b6de..83efc34 100644 --- a/openbr/plugins/validate.cpp +++ b/openbr/plugins/validate.cpp @@ -46,8 +46,7 @@ class CrossValidateTransform : public MetaTransform if (partitions[j] == i) partitionedData.removeAt(j); // Train on the remaining templates - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(transforms[i], &Transform::train, partitionedData)); - else transforms[i]->train(partitionedData); + futures.addFuture(QtConcurrent::run(transforms[i], &Transform::train, partitionedData)); } futures.waitForFinished(); }