Commit 4d39cf939575e209f8512b8efb5ee42c1e3ae930
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
22 changed files
with
155 additions
and
151 deletions
app/br/br.cpp
| ... | ... | @@ -68,12 +68,13 @@ public: |
| 68 | 68 | if (argc == 0) printf("%s\nTry running 'br -help'\n", br_about()); |
| 69 | 69 | |
| 70 | 70 | bool daemon = false; |
| 71 | + const char *daemon_pipe = NULL; | |
| 71 | 72 | while (daemon || (argc > 0)) { |
| 72 | 73 | const char *fun; |
| 73 | 74 | int parc; |
| 74 | 75 | const char **parv; |
| 75 | 76 | if (argc == 0) |
| 76 | - br_read_stdin(&argc, &argv); | |
| 77 | + br_read_pipe(daemon_pipe, &argc, &argv); | |
| 77 | 78 | |
| 78 | 79 | fun = argv[0]; |
| 79 | 80 | if (fun[0] == '-') fun++; |
| ... | ... | @@ -158,8 +159,9 @@ public: |
| 158 | 159 | check(parc == 0, "No parameters expected for 'version'."); |
| 159 | 160 | printf("%s\n", br_version()); |
| 160 | 161 | } else if (!strcmp(fun, "daemon")) { |
| 161 | - check(parc == 0, "No parameters expected for 'daemon'."); | |
| 162 | + check(parc == 1, "Incorrect parameter count for 'daemon'."); | |
| 162 | 163 | daemon = true; |
| 164 | + daemon_pipe = parv[0]; | |
| 163 | 165 | } else if (!strcmp(fun, "exit")) { |
| 164 | 166 | check(parc == 0, "No parameters expected for 'exit'."); |
| 165 | 167 | daemon = false; | ... | ... |
openbr/core/core.cpp
| ... | ... | @@ -275,17 +275,14 @@ private: |
| 275 | 275 | return QFileInfo(file).exists() ? file : QString(); |
| 276 | 276 | } |
| 277 | 277 | |
| 278 | - void init(QString description) | |
| 278 | + void init(const File &description) | |
| 279 | 279 | { |
| 280 | 280 | // Check if a trained binary already exists for this algorithm |
| 281 | 281 | const QString file = getFileName(description); |
| 282 | - if (!file.isEmpty()) description = file; | |
| 282 | + if (!file.isEmpty()) return init(file); | |
| 283 | 283 | |
| 284 | - File asdf(description); | |
| 285 | - QString distribute_status = asdf.get<QString>("distribute","true"); | |
| 286 | - | |
| 287 | - if (QFileInfo(description).exists()) { | |
| 288 | - qDebug("Loading %s", qPrintable(QFileInfo(description).fileName())); | |
| 284 | + if (description.exists()) { | |
| 285 | + qDebug("Loading %s", qPrintable(description.fileName())); | |
| 289 | 286 | load(description); |
| 290 | 287 | return; |
| 291 | 288 | } |
| ... | ... | @@ -294,13 +291,11 @@ private: |
| 294 | 291 | if (Globals->abbreviations.contains(description)) |
| 295 | 292 | return init(Globals->abbreviations[description]); |
| 296 | 293 | |
| 297 | - QStringList words = QtUtils::parse(description, ':'); | |
| 298 | - if (words.size() > 2) qFatal("Invalid algorithm format."); | |
| 294 | + QStringList words = QtUtils::parse(description.flat(), ':'); | |
| 295 | + if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format."); | |
| 299 | 296 | |
| 300 | - if (distribute_status == "true") { | |
| 301 | - words[0].prepend("DistributeTemplate("); | |
| 302 | - words[0].append(")"); | |
| 303 | - } | |
| 297 | + if (description.getBool("distribute", true)) | |
| 298 | + words[0] = "DistributeTemplate(" + words[0] + ")"; | |
| 304 | 299 | |
| 305 | 300 | transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); |
| 306 | 301 | if (words.size() > 1) distance = QSharedPointer<Distance>(Distance::make(words[1], NULL)); | ... | ... |
openbr/openbr.cpp
| ... | ... | @@ -182,17 +182,23 @@ float br_progress() |
| 182 | 182 | return Globals->progress(); |
| 183 | 183 | } |
| 184 | 184 | |
| 185 | -void br_read_stdin(int *argc, char ***argv) | |
| 185 | +void br_read_pipe(const char *pipe, int *argc, char ***argv) | |
| 186 | 186 | { |
| 187 | 187 | static QList<QByteArray> byteArrayList; |
| 188 | 188 | static QVector<char*> rawCharArrayList; |
| 189 | 189 | |
| 190 | + QFile file(pipe); | |
| 191 | + file.open(QFile::ReadOnly); | |
| 192 | + QTextStream stream(&file); | |
| 193 | + | |
| 190 | 194 | QStringList args; |
| 191 | 195 | while (args.isEmpty()) { |
| 192 | - args = QtUtils::parse(QTextStream(stdin).readLine(), ' '); | |
| 193 | - QThread::yieldCurrentThread(); | |
| 196 | + args = QtUtils::parse(stream.readAll(), ' '); | |
| 197 | + if (args.isEmpty()) QThread::sleep(100); | |
| 194 | 198 | } |
| 195 | 199 | |
| 200 | + file.close(); | |
| 201 | + | |
| 196 | 202 | byteArrayList.clear(); rawCharArrayList.clear(); |
| 197 | 203 | foreach (const QString &string, args) { |
| 198 | 204 | byteArrayList.append(string.toLocal8Bit()); | ... | ... |
openbr/openbr.h
| ... | ... | @@ -297,16 +297,15 @@ BR_EXPORT bool br_plot_metadata(int num_files, const char *files[], const char * |
| 297 | 297 | BR_EXPORT float br_progress(); |
| 298 | 298 | |
| 299 | 299 | /*! |
| 300 | - * \brief Read and parse stdin. | |
| 300 | + * \brief Read and parse arguments from a named pipe. | |
| 301 | 301 | * |
| 302 | - * Used by the \ref cli to implement \c -daemon. | |
| 302 | + * Used by the \ref cli to implement \c -daemon, generally not useful otherwise. | |
| 303 | 303 | * Guaranteed to return at least one argument. |
| 304 | - * Generally not useful otherwise. | |
| 305 | 304 | * \param[out] argc argument count |
| 306 | 305 | * \param[out] argv argument list |
| 307 | 306 | * \note \ref managed_return_value |
| 308 | 307 | */ |
| 309 | -BR_EXPORT void br_read_stdin(int *argc, char ***argv); | |
| 308 | +BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv); | |
| 310 | 309 | |
| 311 | 310 | /*! |
| 312 | 311 | * \brief Converts a simmat to a new output format. | ... | ... |
openbr/openbr_plugin.cpp
| ... | ... | @@ -801,8 +801,8 @@ void br::Context::setProperty(const QString &key, const QString &value) |
| 801 | 801 | qDebug("Set %s%s", qPrintable(key), value.isEmpty() ? "" : qPrintable(" to " + value)); |
| 802 | 802 | |
| 803 | 803 | if (key == "parallelism") { |
| 804 | - const int maxThreads = std::max(1, QThread::idealThreadCount()); | |
| 805 | - QThreadPool::globalInstance()->setMaxThreadCount(parallelism ? std::min(maxThreads, abs(parallelism)) : maxThreads); | |
| 804 | + if (parallelism <= 0) parallelism = 1; | |
| 805 | + QThreadPool::globalInstance()->setMaxThreadCount(parallelism); | |
| 806 | 806 | } else if (key == "log") { |
| 807 | 807 | logFile.close(); |
| 808 | 808 | if (log.isEmpty()) return; |
| ... | ... | @@ -829,8 +829,17 @@ bool br::Context::checkSDKPath(const QString &sdkPath) |
| 829 | 829 | // We create our own when the user hasn't |
| 830 | 830 | static QCoreApplication *application = NULL; |
| 831 | 831 | |
| 832 | -void br::Context::initialize(int &argc, char *argv[], QString sdkPath) | |
| 832 | +void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool use_gui) | |
| 833 | 833 | { |
| 834 | + for (int i=0; i < argc; i ++) | |
| 835 | + { | |
| 836 | + if (strcmp("-useGui", argv[i]) == 0) { | |
| 837 | + const char * val = i+1 < argc ? argv[i+1] : ""; | |
| 838 | + if (strcmp(val, "false") ==0 || strcmp(val, "0") == 0) | |
| 839 | + use_gui = false; | |
| 840 | + break; | |
| 841 | + } | |
| 842 | + } | |
| 834 | 843 | // We take in argc as a reference due to: |
| 835 | 844 | // https://bugreports.qt-project.org/browse/QTBUG-5637 |
| 836 | 845 | // QApplication should be initialized before anything else. |
| ... | ... | @@ -861,6 +870,7 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath) |
| 861 | 870 | |
| 862 | 871 | Globals = new Context(); |
| 863 | 872 | Globals->init(File()); |
| 873 | + Globals->useGui = use_gui; | |
| 864 | 874 | |
| 865 | 875 | qInstallMessageHandler(messageHandler); |
| 866 | 876 | |
| ... | ... | @@ -885,8 +895,7 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath) |
| 885 | 895 | } |
| 886 | 896 | Globals->sdkPath = sdkPath; |
| 887 | 897 | |
| 888 | - // Empirical evidence suggests an extra thread helps achieve full CPU utilization | |
| 889 | - QThreadPool::globalInstance()->releaseThread(); | |
| 898 | + QThreadPool::globalInstance()->setMaxThreadCount(Globals->parallelism); | |
| 890 | 899 | |
| 891 | 900 | // Trigger registered initializers |
| 892 | 901 | QList< QSharedPointer<Initializer> > initializers = Factory<Initializer>::makeAll(); |
| ... | ... | @@ -896,9 +905,6 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath) |
| 896 | 905 | |
| 897 | 906 | void br::Context::finalize() |
| 898 | 907 | { |
| 899 | - // Undo the 'releaseThread()' in 'initialize()' | |
| 900 | - QThreadPool::globalInstance()->reserveThread(); | |
| 901 | - | |
| 902 | 908 | // Trigger registered finalizers |
| 903 | 909 | QList< QSharedPointer<Initializer> > initializers = Factory<Initializer>::makeAll(); |
| 904 | 910 | foreach (const QSharedPointer<Initializer> &initializer, initializers) |
| ... | ... | @@ -1192,10 +1198,8 @@ private: |
| 1192 | 1198 | templatesList[i] = Downsample(templatesList[i], transforms[i]); |
| 1193 | 1199 | |
| 1194 | 1200 | QFutureSynchronizer<void> futures; |
| 1195 | - for (int i=0; i<templatesList.size(); i++) { | |
| 1196 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | |
| 1197 | - else _train (transforms[i], &templatesList[i]); | |
| 1198 | - } | |
| 1201 | + for (int i=0; i<templatesList.size(); i++) | |
| 1202 | + futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | |
| 1199 | 1203 | futures.waitForFinished(); |
| 1200 | 1204 | } |
| 1201 | 1205 | |
| ... | ... | @@ -1308,21 +1312,12 @@ void Transform::project(const TemplateList &src, TemplateList &dst) const |
| 1308 | 1312 | { |
| 1309 | 1313 | dst.reserve(src.size()); |
| 1310 | 1314 | |
| 1311 | - // There are certain conditions where we should process the templates in serial, | |
| 1312 | - // but generally we'd prefer to process them in parallel. | |
| 1313 | - if ((src.size() < 2) || (Globals->parallelism == 0)) { | |
| 1314 | - foreach (const Template &t, src) { | |
| 1315 | - dst.append(Template()); | |
| 1316 | - _project(this, &t, &dst.last()); | |
| 1317 | - } | |
| 1318 | - } else { | |
| 1319 | - for (int i=0; i<src.size(); i++) | |
| 1320 | - dst.append(Template()); | |
| 1321 | - QFutureSynchronizer<void> futures; | |
| 1322 | - for (int i=0; i<dst.size(); i++) | |
| 1323 | - futures.addFuture(QtConcurrent::run(_project, this, &src[i], &dst[i])); | |
| 1324 | - futures.waitForFinished(); | |
| 1325 | - } | |
| 1315 | + for (int i=0; i<src.size(); i++) | |
| 1316 | + dst.append(Template()); | |
| 1317 | + QFutureSynchronizer<void> futures; | |
| 1318 | + for (int i=0; i<dst.size(); i++) | |
| 1319 | + futures.addFuture(QtConcurrent::run(_project, this, &src[i], &dst[i])); | |
| 1320 | + futures.waitForFinished(); | |
| 1326 | 1321 | } |
| 1327 | 1322 | |
| 1328 | 1323 | static void _backProject(const Transform *transform, const Template *dst, Template *src) |
| ... | ... | @@ -1343,8 +1338,7 @@ void Transform::backProject(const TemplateList &dst, TemplateList &src) const |
| 1343 | 1338 | |
| 1344 | 1339 | QFutureSynchronizer<void> futures; |
| 1345 | 1340 | for (int i=0; i<dst.size(); i++) |
| 1346 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(_backProject, this, &dst[i], &src[i])); | |
| 1347 | - else _backProject (this, &dst[i], &src[i]); | |
| 1341 | + futures.addFuture(QtConcurrent::run(_backProject, this, &dst[i], &src[i])); | |
| 1348 | 1342 | futures.waitForFinished(); |
| 1349 | 1343 | } |
| 1350 | 1344 | ... | ... |
openbr/openbr_plugin.h
| ... | ... | @@ -189,6 +189,7 @@ struct BR_EXPORT File |
| 189 | 189 | inline QString baseName() const { const QString baseName = QFileInfo(name).baseName(); |
| 190 | 190 | return baseName.isEmpty() ? QDir(name).dirName() : baseName; } /*!< \brief Returns the file's base name. */ |
| 191 | 191 | inline QString suffix() const { return QFileInfo(name).suffix(); } /*!< \brief Returns the file's extension. */ |
| 192 | + inline QString path() const { return QFileInfo(name).path(); } /*! \brief Returns the file's path excluding its name. */ | |
| 192 | 193 | QString resolved() const; /*!< \brief Returns name prepended with Globals->path if name does not exist. */ |
| 193 | 194 | |
| 194 | 195 | 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: |
| 547 | 548 | * \brief The number of threads to use. |
| 548 | 549 | */ |
| 549 | 550 | Q_PROPERTY(int parallelism READ get_parallelism WRITE set_parallelism RESET reset_parallelism) |
| 550 | - BR_PROPERTY(int, parallelism, std::max(1, QThread::idealThreadCount())) | |
| 551 | + BR_PROPERTY(int, parallelism, std::max(1, QThread::idealThreadCount()+1)) | |
| 552 | + | |
| 553 | + /*! | |
| 554 | + * \brief Whether or not to use GUI functions | |
| 555 | + */ | |
| 556 | + Q_PROPERTY(bool useGui READ get_useGui WRITE set_useGui RESET reset_useGui) | |
| 557 | + BR_PROPERTY(bool, useGui, true) | |
| 551 | 558 | |
| 552 | 559 | /*! |
| 553 | 560 | * \brief The maximum number of templates to process in parallel. |
| ... | ... | @@ -701,7 +708,7 @@ public: |
| 701 | 708 | * \note <a href="http://qt-project.org/">Qt</a> users should instead call this <i>after</i> initializing QApplication. |
| 702 | 709 | * \see finalize |
| 703 | 710 | */ |
| 704 | - static void initialize(int &argc, char *argv[], QString sdkPath = ""); | |
| 711 | + static void initialize(int &argc, char *argv[], QString sdkPath = "", bool use_gui = true); | |
| 705 | 712 | |
| 706 | 713 | /*! |
| 707 | 714 | * \brief Call \em once at the end of the application to deallocate global variables. | ... | ... |
openbr/plugins/algorithms.cpp
| ... | ... | @@ -38,11 +38,11 @@ class AlgorithmsInitializer : public Initializer |
| 38 | 38 | Globals->abbreviations.insert("MedianFace", "Open!Cascade(FrontalFace)+ASEFEyes+Affine(256,256,0.37,0.45)+Center(Median)"); |
| 39 | 39 | Globals->abbreviations.insert("BlurredFaceDetection", "Open+LimitSize(1024)+SkinMask/(Cvt(Gray)+GradientMask)+And+Morph(Erode,16)+LargestConvexArea"); |
| 40 | 40 | Globals->abbreviations.insert("DrawFaceDetection", "Open+Cascade(FrontalFace)!ASEFEyes+Draw"); |
| 41 | - Globals->abbreviations.insert("ShowFaceDetection", "DrawFaceDetection!Show"); | |
| 41 | + Globals->abbreviations.insert("ShowFaceDetection", "DrawFaceDetection!Show[distribute=false]"); | |
| 42 | 42 | Globals->abbreviations.insert("OpenBR", "FaceRecognition"); |
| 43 | 43 | Globals->abbreviations.insert("GenderEstimation", "GenderClassification"); |
| 44 | 44 | Globals->abbreviations.insert("AgeEstimation", "AgeRegression"); |
| 45 | - 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"); | |
| 45 | + 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"); | |
| 46 | 46 | |
| 47 | 47 | // Generic Image Processing |
| 48 | 48 | Globals->abbreviations.insert("SIFT", "Open+KeyPointDetector(SIFT)+KeyPointDescriptor(SIFT):KeyPointMatcher(BruteForce)"); | ... | ... |
openbr/plugins/distance.cpp
| ... | ... | @@ -158,8 +158,7 @@ class PipeDistance : public Distance |
| 158 | 158 | { |
| 159 | 159 | QFutureSynchronizer<void> futures; |
| 160 | 160 | foreach (br::Distance *distance, distances) |
| 161 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | |
| 162 | - else distance->train(data); | |
| 161 | + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | |
| 163 | 162 | futures.waitForFinished(); |
| 164 | 163 | } |
| 165 | 164 | ... | ... |
openbr/plugins/draw.cpp
| ... | ... | @@ -98,6 +98,8 @@ class DrawGridTransform : public UntrainableTransform |
| 98 | 98 | |
| 99 | 99 | BR_REGISTER(Transform, DrawGridTransform) |
| 100 | 100 | |
| 101 | +// TODO: re-implement EditTransform using Qt | |
| 102 | +#if 0 | |
| 101 | 103 | /*! |
| 102 | 104 | * \ingroup transforms |
| 103 | 105 | * \brief Remove landmarks. |
| ... | ... | @@ -162,6 +164,7 @@ Template EditTransform::currentTemplate; |
| 162 | 164 | QMutex EditTransform::currentTemplateLock; |
| 163 | 165 | |
| 164 | 166 | BR_REGISTER(Transform, EditTransform) |
| 167 | +#endif | |
| 165 | 168 | |
| 166 | 169 | } // namespace br |
| 167 | 170 | ... | ... |
openbr/plugins/format.cpp
| ... | ... | @@ -15,6 +15,7 @@ |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <QDate> |
| 18 | +#include <QSize> | |
| 18 | 19 | #ifndef BR_EMBEDDED |
| 19 | 20 | #include <QtXml> |
| 20 | 21 | #endif // BR_EMBEDDED |
| ... | ... | @@ -547,14 +548,43 @@ BR_REGISTER(Format, nullFormat) |
| 547 | 548 | class rawFormat : public Format |
| 548 | 549 | { |
| 549 | 550 | Q_OBJECT |
| 551 | + static QHash<QString, QHash<QString,QSize> > imageSizes; // QHash<Path, QHash<File,Size> > | |
| 550 | 552 | |
| 551 | 553 | Template read() const |
| 552 | 554 | { |
| 555 | + QString path = file.path(); | |
| 556 | + if (!imageSizes.contains(path)) { | |
| 557 | + static QMutex mutex; | |
| 558 | + QMutexLocker locker(&mutex); | |
| 559 | + | |
| 560 | + if (!imageSizes.contains(path)) { | |
| 561 | + const QString imageSize = path+"/ImageSize.txt"; | |
| 562 | + QStringList lines; | |
| 563 | + if (QFileInfo(imageSize).exists()) { | |
| 564 | + lines = QtUtils::readLines(imageSize); | |
| 565 | + lines.removeFirst(); // Remove header | |
| 566 | + } | |
| 567 | + | |
| 568 | + QHash<QString,QSize> sizes; | |
| 569 | + QRegExp whiteSpace("\\s+"); | |
| 570 | + foreach (const QString &line, lines) { | |
| 571 | + QStringList words = line.split(whiteSpace); | |
| 572 | + if (words.size() != 3) continue; | |
| 573 | + sizes.insert(words[0], QSize(words[2].toInt(), words[1].toInt())); | |
| 574 | + } | |
| 575 | + | |
| 576 | + imageSizes.insert(path, sizes); | |
| 577 | + } | |
| 578 | + } | |
| 579 | + | |
| 553 | 580 | QByteArray data; |
| 554 | 581 | QtUtils::readFile(file, data); |
| 555 | - if (data.size() != 768*800) | |
| 556 | - qFatal("Expected 768*800 bytes."); | |
| 557 | - return Template(file, Mat(768, 800, CV_8UC1, data.data()).clone()); | |
| 582 | + | |
| 583 | + QSize size = imageSizes[path][file.baseName()]; | |
| 584 | + if (!size.isValid()) size = QSize(800,768); | |
| 585 | + if (data.size() != size.width() * size.height()) | |
| 586 | + qFatal("Expected %d*%d bytes, got %d.", size.height(), size.width(), data.size()); | |
| 587 | + return Template(file, Mat(size.height(), size.width(), CV_8UC1, data.data()).clone()); | |
| 558 | 588 | } |
| 559 | 589 | |
| 560 | 590 | void write(const Template &t) const |
| ... | ... | @@ -563,6 +593,8 @@ class rawFormat : public Format |
| 563 | 593 | } |
| 564 | 594 | }; |
| 565 | 595 | |
| 596 | +QHash<QString, QHash<QString,QSize> > rawFormat::imageSizes; | |
| 597 | + | |
| 566 | 598 | BR_REGISTER(Format, rawFormat) |
| 567 | 599 | |
| 568 | 600 | /*! | ... | ... |
openbr/plugins/gallery.cpp
| ... | ... | @@ -107,8 +107,7 @@ class EmptyGallery : public Gallery |
| 107 | 107 | QList< QFuture<TemplateList> > futures; |
| 108 | 108 | foreach (const QString &folder, NaturalStringSort(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))) { |
| 109 | 109 | const QDir subdir = dir.absoluteFilePath(folder); |
| 110 | - if (Globals->parallelism) futures.append(QtConcurrent::run(&EmptyGallery::getTemplates, subdir)); | |
| 111 | - else templates.append(getTemplates(subdir)); | |
| 110 | + futures.append(QtConcurrent::run(&EmptyGallery::getTemplates, subdir)); | |
| 112 | 111 | } |
| 113 | 112 | foreach (const QFuture<TemplateList> &future, futures) |
| 114 | 113 | templates.append(future.result()); | ... | ... |
openbr/plugins/gui.cpp
| ... | ... | @@ -94,6 +94,8 @@ public slots: |
| 94 | 94 | void createWindow() |
| 95 | 95 | { |
| 96 | 96 | delete window; |
| 97 | + QApplication::instance()->removeEventFilter(this); | |
| 98 | + | |
| 97 | 99 | window = new QLabel(); |
| 98 | 100 | window->setVisible(true); |
| 99 | 101 | |
| ... | ... | @@ -109,21 +111,25 @@ public slots: |
| 109 | 111 | * \ingroup transforms |
| 110 | 112 | * \brief Displays templates in a GUI pop-up window using QT. |
| 111 | 113 | * \author Charles Otto \cite caotto |
| 112 | - * Unlike ShowTransform, this can be used with parallelism enabled, although it | |
| 113 | - * is considered TimeVarying. | |
| 114 | + * Can be used with parallelism enabled, although it is considered TimeVarying. | |
| 114 | 115 | */ |
| 115 | -class Show2Transform : public TimeVaryingTransform | |
| 116 | +class ShowTransform : public TimeVaryingTransform | |
| 116 | 117 | { |
| 117 | 118 | Q_OBJECT |
| 118 | 119 | public: |
| 119 | 120 | Q_PROPERTY(bool waitInput READ get_waitInput WRITE set_waitInput RESET reset_waitInput STORED false) |
| 120 | - BR_PROPERTY(bool, waitInput, false) | |
| 121 | + BR_PROPERTY(bool, waitInput, true) | |
| 121 | 122 | |
| 122 | 123 | Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) |
| 123 | 124 | BR_PROPERTY(QStringList, keys, QStringList("FrameNumber")) |
| 124 | 125 | |
| 125 | - Show2Transform() : TimeVaryingTransform(false, false) | |
| 126 | + ShowTransform() : TimeVaryingTransform(false, false) | |
| 126 | 127 | { |
| 128 | + gui = NULL; | |
| 129 | + displayBuffer = NULL; | |
| 130 | + if (!Globals->useGui) | |
| 131 | + return; | |
| 132 | + displayBuffer = new QPixmap(); | |
| 127 | 133 | // Create our GUI proxy |
| 128 | 134 | gui = new GUIProxy(); |
| 129 | 135 | // Move it to the main thread, this means signals we send to it will |
| ... | ... | @@ -134,16 +140,17 @@ public: |
| 134 | 140 | connect(this, SIGNAL(updateImage(QPixmap)), gui,SLOT(showImage(QPixmap))); |
| 135 | 141 | } |
| 136 | 142 | |
| 137 | - ~Show2Transform() | |
| 143 | + ~ShowTransform() | |
| 138 | 144 | { |
| 139 | 145 | delete gui; |
| 146 | + delete displayBuffer; | |
| 140 | 147 | } |
| 141 | 148 | |
| 142 | 149 | void train(const TemplateList &data) { (void) data; } |
| 143 | 150 | |
| 144 | 151 | void project(const TemplateList &src, TemplateList &dst) const |
| 145 | 152 | { |
| 146 | - Transform * non_const = (Show2Transform *) this; | |
| 153 | + Transform * non_const = (ShowTransform *) this; | |
| 147 | 154 | non_const->projectUpdate(src,dst); |
| 148 | 155 | } |
| 149 | 156 | |
| ... | ... | @@ -151,7 +158,7 @@ public: |
| 151 | 158 | { |
| 152 | 159 | dst = src; |
| 153 | 160 | |
| 154 | - if (src.empty()) | |
| 161 | + if (src.empty() || !Globals->useGui) | |
| 155 | 162 | return; |
| 156 | 163 | |
| 157 | 164 | foreach (const Template & t, src) { |
| ... | ... | @@ -168,12 +175,12 @@ public: |
| 168 | 175 | |
| 169 | 176 | foreach(const cv::Mat & m, t) { |
| 170 | 177 | qImageBuffer = toQImage(m); |
| 171 | - displayBuffer.convertFromImage(qImageBuffer); | |
| 178 | + displayBuffer->convertFromImage(qImageBuffer); | |
| 172 | 179 | |
| 173 | 180 | // Emit an explicit copy of our pixmap so that the pixmap used |
| 174 | 181 | // by the main thread isn't damaged when we update displayBuffer |
| 175 | 182 | // later. |
| 176 | - emit updateImage(displayBuffer.copy(displayBuffer.rect())); | |
| 183 | + emit updateImage(displayBuffer->copy(displayBuffer->rect())); | |
| 177 | 184 | |
| 178 | 185 | // Blocking wait for a key-press |
| 179 | 186 | if (this->waitInput) |
| ... | ... | @@ -191,6 +198,9 @@ public: |
| 191 | 198 | |
| 192 | 199 | void init() |
| 193 | 200 | { |
| 201 | + if (!Globals->useGui) | |
| 202 | + return; | |
| 203 | + | |
| 194 | 204 | emit needWindow(); |
| 195 | 205 | connect(this, SIGNAL(changeTitle(QString)), gui->window, SLOT(setWindowTitle(QString))); |
| 196 | 206 | connect(this, SIGNAL(hideWindow()), gui->window, SLOT(hide())); |
| ... | ... | @@ -199,7 +209,7 @@ public: |
| 199 | 209 | protected: |
| 200 | 210 | GUIProxy * gui; |
| 201 | 211 | QImage qImageBuffer; |
| 202 | - QPixmap displayBuffer; | |
| 212 | + QPixmap * displayBuffer; | |
| 203 | 213 | |
| 204 | 214 | signals: |
| 205 | 215 | void needWindow(); |
| ... | ... | @@ -208,7 +218,7 @@ signals: |
| 208 | 218 | void hideWindow(); |
| 209 | 219 | }; |
| 210 | 220 | |
| 211 | -BR_REGISTER(Transform, Show2Transform) | |
| 221 | +BR_REGISTER(Transform, ShowTransform) | |
| 212 | 222 | |
| 213 | 223 | class FPSSynch : public TimeVaryingTransform |
| 214 | 224 | { | ... | ... |
openbr/plugins/meta.cpp
| ... | ... | @@ -109,8 +109,7 @@ class PipeTransform : public CompositeTransform |
| 109 | 109 | fprintf(stderr, " projecting..."); |
| 110 | 110 | QFutureSynchronizer<void> futures; |
| 111 | 111 | for (int j=0; j<copy.size(); j++) |
| 112 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, ©[j], i, nextTrainableTransform)); | |
| 113 | - else _projectPartial( ©[j], i, nextTrainableTransform); | |
| 112 | + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, ©[j], i, nextTrainableTransform)); | |
| 114 | 113 | futures.waitForFinished(); |
| 115 | 114 | i = nextTrainableTransform; |
| 116 | 115 | } |
| ... | ... | @@ -288,10 +287,8 @@ class ForkTransform : public CompositeTransform |
| 288 | 287 | { |
| 289 | 288 | if (!trainable) return; |
| 290 | 289 | QFutureSynchronizer<void> futures; |
| 291 | - for (int i=0; i<transforms.size(); i++) { | |
| 292 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(_train, transforms[i], &data)); | |
| 293 | - else _train (transforms[i], &data); | |
| 294 | - } | |
| 290 | + for (int i=0; i<transforms.size(); i++) | |
| 291 | + futures.addFuture(QtConcurrent::run(_train, transforms[i], &data)); | |
| 295 | 292 | futures.waitForFinished(); |
| 296 | 293 | } |
| 297 | 294 | ... | ... |
openbr/plugins/misc.cpp
| ... | ... | @@ -51,46 +51,6 @@ BR_REGISTER(Transform, OpenTransform) |
| 51 | 51 | |
| 52 | 52 | /*! |
| 53 | 53 | * \ingroup transforms |
| 54 | - * \brief Displays templates in a GUI pop-up window. | |
| 55 | - * \author Josh Klontz \cite jklontz | |
| 56 | - */ | |
| 57 | -class ShowTransform : public UntrainableMetaTransform | |
| 58 | -{ | |
| 59 | - Q_OBJECT | |
| 60 | - Q_PROPERTY(bool waitKey READ get_waitKey WRITE set_waitKey RESET reset_waitKey STORED false) | |
| 61 | - BR_PROPERTY(bool, waitKey, true) | |
| 62 | - | |
| 63 | - static int counter; | |
| 64 | - int uid; | |
| 65 | - | |
| 66 | - void init() | |
| 67 | - { | |
| 68 | - uid = counter++; | |
| 69 | - Globals->setProperty("parallelism", "0"); // Can only work in single threaded mode | |
| 70 | - } | |
| 71 | - | |
| 72 | - void project(const Template &src, Template &dst) const | |
| 73 | - { | |
| 74 | - dst = src; | |
| 75 | - | |
| 76 | - if (Globals->parallelism) { | |
| 77 | - qWarning("Show::project() only works in single threaded mode."); | |
| 78 | - return; | |
| 79 | - } | |
| 80 | - | |
| 81 | - for (int i=0; i<src.size(); i++) | |
| 82 | - OpenCVUtils::showImage(src[i], "Show" + (counter*src.size() > 1 ? "-" + QString::number(uid*src.size()+i) : QString()), false); | |
| 83 | - | |
| 84 | - if (waitKey && !src.isEmpty()) cv::waitKey(-1); | |
| 85 | - } | |
| 86 | -}; | |
| 87 | - | |
| 88 | -int ShowTransform::counter = 0; | |
| 89 | - | |
| 90 | -BR_REGISTER(Transform, ShowTransform) | |
| 91 | - | |
| 92 | -/*! | |
| 93 | - * \ingroup transforms | |
| 94 | 54 | * \brief Prints the template's file to stdout or stderr. |
| 95 | 55 | * \author Josh Klontz \cite jklontz |
| 96 | 56 | */ |
| ... | ... | @@ -368,6 +328,8 @@ class AnonymizeTransform : public UntrainableMetaTransform |
| 368 | 328 | |
| 369 | 329 | BR_REGISTER(Transform, AnonymizeTransform) |
| 370 | 330 | |
| 331 | +// TODO: Use a global Mutex to prevent concurrent reads from stdin | |
| 332 | +#if 0 | |
| 371 | 333 | /*! |
| 372 | 334 | * \ingroup transforms |
| 373 | 335 | * \brief Name a point |
| ... | ... | @@ -415,6 +377,7 @@ class ElicitMetadataTransform : public UntrainableMetaTransform |
| 415 | 377 | }; |
| 416 | 378 | |
| 417 | 379 | BR_REGISTER(Transform, ElicitMetadataTransform) |
| 380 | +#endif | |
| 418 | 381 | |
| 419 | 382 | /*! |
| 420 | 383 | * \ingroup transforms | ... | ... |
openbr/plugins/neclatent1.cpp
| ... | ... | @@ -18,9 +18,12 @@ class NECLatent1Initialier : public Initializer |
| 18 | 18 | |
| 19 | 19 | void initialize() const |
| 20 | 20 | { |
| 21 | - Globals->abbreviations.insert("NECTenprint1", "Open+Cvt(Gray)+NECLatent1Enroll:NECLatent1Compare"); | |
| 22 | - Globals->abbreviations.insert("NECLatent1", "Open+Cvt(Gray)+NECLatent1Enroll(true):NECLatent1Compare"); | |
| 23 | - Globals->abbreviations.insert("NECLatentLFFS1", "Open+NECLatent1Enroll(true,ELFT_M):NECLatent1Compare(ELFT_M)"); | |
| 21 | + Globals->abbreviations.insert("NECTenprintLFML", "Open+Cvt(Gray)+NECLatent1Enroll(false,LFML):NECLatent1Compare(LFML)"); | |
| 22 | + Globals->abbreviations.insert("NECTenprintELFT", "Open+Cvt(Gray)+NECLatent1Enroll(false,ELFT):NECLatent1Compare(ELFT)"); | |
| 23 | + Globals->abbreviations.insert("NECTenprintELFTM", "Open+Cvt(Gray)+NECLatent1Enroll(false,ELFT_M):NECLatent1Compare(ELFT_M)"); | |
| 24 | + Globals->abbreviations.insert("NECLatentLFML", "Open+Cvt(Gray)+NECLatent1Enroll(true,LFML):NECLatent1Compare(LFML)"); | |
| 25 | + Globals->abbreviations.insert("NECLatentELFT", "Open+Cvt(Gray)+NECLatent1Enroll(true,ELFT):NECLatent1Compare(ELFT)"); | |
| 26 | + Globals->abbreviations.insert("NECLatentELFTM", "Open+NECLatent1Enroll(true,ELFT_M):NECLatent1Compare(ELFT_M)"); | |
| 24 | 27 | } |
| 25 | 28 | }; |
| 26 | 29 | |
| ... | ... | @@ -50,23 +53,25 @@ private: |
| 50 | 53 | |
| 51 | 54 | void project(const Template &src, Template &dst) const |
| 52 | 55 | { |
| 56 | + static QMutex mutex; | |
| 57 | + QMutexLocker locker(&mutex); // It seems that most of the API is not reentrant | |
| 58 | + | |
| 53 | 59 | if (src.m().type() != CV_8UC1) qFatal("Requires 8UC1 data!"); |
| 54 | 60 | uchar *data = src.m().data; |
| 55 | 61 | const int rows = src.m().rows; |
| 56 | 62 | const int columns = src.m().cols; |
| 57 | 63 | uchar buff[MAX_TEMPLATE_SIZE]; |
| 58 | 64 | uchar* pBuff = NULL; |
| 59 | - int size = 0; | |
| 60 | - int error; | |
| 61 | 65 | |
| 66 | + int size, error; | |
| 62 | 67 | if (latent) { |
| 63 | 68 | if (algorithm == LFML) error = NEC_LFML_ExtractLatent(data, rows, columns, 500, buff, &size); |
| 64 | - else if (algorithm == ELFT) error = NEC_ELFT_ExtractLatent(data, rows, columns, 500, 4, buff, &size); | |
| 65 | - else error = NEC_ELFT_M_ExtractLatent(data, columns, 1, &pBuff, &size); | |
| 69 | + else if (algorithm == ELFT) error = NEC_ELFT_ExtractLatent(data, rows, columns, 500, 32, buff, &size); | |
| 70 | + else error = NEC_ELFT_M_ExtractLatent(data, columns, 5, &pBuff, &size); | |
| 66 | 71 | } else { |
| 67 | 72 | if (algorithm == LFML) error = NEC_LFML_ExtractTenprint(data, rows, columns, 500, buff, &size); |
| 68 | - else if (algorithm == ELFT) error = NEC_ELFT_ExtractTenprint(data, rows, columns, 500, 2, buff, &size); | |
| 69 | - else qFatal("ELFT_M Tenprint not implemented."); | |
| 73 | + else if (algorithm == ELFT) error = NEC_ELFT_ExtractTenprint(data, rows, columns, 500, 8, buff, &size); | |
| 74 | + else error = NEC_ELFT_M_ExtractTenprint(data, rows, columns, 500, 5, &pBuff, &size); | |
| 70 | 75 | } |
| 71 | 76 | |
| 72 | 77 | if (!error) { |
| ... | ... | @@ -109,10 +114,12 @@ private: |
| 109 | 114 | uchar *aData = a.m().data; |
| 110 | 115 | uchar *bData = b.m().data; |
| 111 | 116 | if (!a.m().data || !b.m().data) return -std::numeric_limits<float>::max(); |
| 112 | - int score; | |
| 113 | - if (algorithm == LFML) NEC_LFML_Verify(bData, b.m().total(), aData, a.m().total(), &score); | |
| 114 | - else if (algorithm == ELFT) NEC_ELFT_Verify(bData, aData, &score, 1); | |
| 115 | - else NEC_ELFT_M_Verify(bData, aData, &score, 1); | |
| 117 | + int score, error; | |
| 118 | + if (algorithm == LFML) error = NEC_LFML_Verify(bData, b.m().total(), aData, a.m().total(), &score); | |
| 119 | + else if (algorithm == ELFT) error = NEC_ELFT_Verify(bData, aData, &score, 1); | |
| 120 | + else error = NEC_ELFT_M_Verify(bData, aData, &score, 1); | |
| 121 | + if (error) | |
| 122 | + qWarning("NECLatent1CompareDistance error %d", error); | |
| 116 | 123 | return score; |
| 117 | 124 | } |
| 118 | 125 | }; | ... | ... |
openbr/plugins/normalize.cpp
| ... | ... | @@ -137,11 +137,9 @@ private: |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | 139 | QFutureSynchronizer<void> futures; |
| 140 | - const bool parallel = (data.size() > 1000) && Globals->parallelism; | |
| 141 | 140 | for (size_t c = 0; c < mv.size(); c++) { |
| 142 | 141 | for (int i=0; i<dims; i++) |
| 143 | - if (parallel) futures.addFuture(QtConcurrent::run(_train, method, mv[c].col(i), labels, &av[c].at<double>(0, i), &bv[c].at<double>(0, i))); | |
| 144 | - else _train (method, mv[c].col(i), labels, &av[c].at<double>(0, i), &bv[c].at<double>(0, i)); | |
| 142 | + futures.addFuture(QtConcurrent::run(_train, method, mv[c].col(i), labels, &av[c].at<double>(0, i), &bv[c].at<double>(0, i))); | |
| 145 | 143 | av[c] = av[c].reshape(1, data.first().m().rows); |
| 146 | 144 | bv[c] = bv[c].reshape(1, data.first().m().rows); |
| 147 | 145 | } | ... | ... |
openbr/plugins/openbr_internal.h
| ... | ... | @@ -221,7 +221,7 @@ public: |
| 221 | 221 | Transform * maybe_copy = t->smartCopy(); |
| 222 | 222 | if (maybe_copy->parent() == NULL) |
| 223 | 223 | maybe_copy->setParent(output); |
| 224 | - output->transforms.append(t->smartCopy()); | |
| 224 | + output->transforms.append(maybe_copy); | |
| 225 | 225 | } |
| 226 | 226 | |
| 227 | 227 | output->file = this->file; | ... | ... |
openbr/plugins/quantize.cpp
| ... | ... | @@ -82,8 +82,7 @@ class HistEqQuantizationTransform : public Transform |
| 82 | 82 | |
| 83 | 83 | QFutureSynchronizer<void> futures; |
| 84 | 84 | for (int i=0; i<data.cols; i++) |
| 85 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(&HistEqQuantizationTransform::computeThresholds, data.col(i), &thresholds.data()[i*256])); | |
| 86 | - else computeThresholds( data.col(i), &thresholds.data()[i*256]); | |
| 85 | + futures.addFuture(QtConcurrent::run(&HistEqQuantizationTransform::computeThresholds, data.col(i), &thresholds.data()[i*256])); | |
| 87 | 86 | futures.waitForFinished(); |
| 88 | 87 | } |
| 89 | 88 | |
| ... | ... | @@ -156,8 +155,7 @@ class BayesianQuantizationDistance : public Distance |
| 156 | 155 | |
| 157 | 156 | QFutureSynchronizer<void> futures; |
| 158 | 157 | for (int i=0; i<data.cols; i++) |
| 159 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(&BayesianQuantizationDistance::computeLogLikelihood, data.col(i), templateLabels, &loglikelihoods.data()[i*256])); | |
| 160 | - else computeLogLikelihood( data.col(i), templateLabels, &loglikelihoods.data()[i*256]); | |
| 158 | + futures.addFuture(QtConcurrent::run(&BayesianQuantizationDistance::computeLogLikelihood, data.col(i), templateLabels, &loglikelihoods.data()[i*256])); | |
| 161 | 159 | futures.waitForFinished(); |
| 162 | 160 | } |
| 163 | 161 | ... | ... |
openbr/plugins/quantize2.cpp
| ... | ... | @@ -83,8 +83,7 @@ class BayesianQuantizationTransform : public Transform |
| 83 | 83 | |
| 84 | 84 | QFutureSynchronizer<void> futures; |
| 85 | 85 | for (int i=0; i<data.cols; i++) |
| 86 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(&BayesianQuantizationTransform::computeThresholds, data.col(i), labels, &thresholds.data()[i*256])); | |
| 87 | - else computeThresholds( data.col(i), labels, &thresholds.data()[i*256]); | |
| 86 | + futures.addFuture(QtConcurrent::run(&BayesianQuantizationTransform::computeThresholds, data.col(i), labels, &thresholds.data()[i*256])); | |
| 88 | 87 | futures.waitForFinished(); |
| 89 | 88 | } |
| 90 | 89 | ... | ... |
openbr/plugins/stasm.cpp
| ... | ... | @@ -33,7 +33,8 @@ BR_REGISTER(Initializer, StasmInitializer) |
| 33 | 33 | * \brief Wraps STASM key point detector |
| 34 | 34 | * \author Scott Klum \cite sklum |
| 35 | 35 | */ |
| 36 | - | |
| 36 | +// TODO: Use a global mutex to prevent concurrent calls to AsmSearchDll | |
| 37 | +#if 0 | |
| 37 | 38 | class StasmTransform : public UntrainableTransform |
| 38 | 39 | { |
| 39 | 40 | Q_OBJECT |
| ... | ... | @@ -67,6 +68,7 @@ class StasmTransform : public UntrainableTransform |
| 67 | 68 | }; |
| 68 | 69 | |
| 69 | 70 | BR_REGISTER(Transform, StasmTransform) |
| 71 | +#endif | |
| 70 | 72 | |
| 71 | 73 | } // namespace br |
| 72 | 74 | ... | ... |
openbr/plugins/stream.cpp
| ... | ... | @@ -771,11 +771,6 @@ public: |
| 771 | 771 | (void) src; (void) dst; |
| 772 | 772 | qFatal("nope"); |
| 773 | 773 | } |
| 774 | - void project(const TemplateList & src, TemplateList & dst) const | |
| 775 | - { | |
| 776 | - (void) src; (void) dst; | |
| 777 | - qFatal("nope"); | |
| 778 | - } | |
| 779 | 774 | |
| 780 | 775 | void projectUpdate(const Template &src, Template &dst) |
| 781 | 776 | { | ... | ... |
openbr/plugins/validate.cpp
| ... | ... | @@ -46,8 +46,7 @@ class CrossValidateTransform : public MetaTransform |
| 46 | 46 | if (partitions[j] == i) |
| 47 | 47 | partitionedData.removeAt(j); |
| 48 | 48 | // Train on the remaining templates |
| 49 | - if (Globals->parallelism) futures.addFuture(QtConcurrent::run(transforms[i], &Transform::train, partitionedData)); | |
| 50 | - else transforms[i]->train(partitionedData); | |
| 49 | + futures.addFuture(QtConcurrent::run(transforms[i], &Transform::train, partitionedData)); | |
| 51 | 50 | } |
| 52 | 51 | futures.waitForFinished(); |
| 53 | 52 | } | ... | ... |