Commit 4d39cf939575e209f8512b8efb5ee42c1e3ae930

Authored by Scott Klum
2 parents 66efa942 2d37a7bc

Merge branch 'master' of https://github.com/biometrics/openbr

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 &amp;key, const QString &amp;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 &amp;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 &amp;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 &amp;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 &amp;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 &amp;src, TemplateList &amp;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 &amp;dst, TemplateList &amp;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, &copy[j], i, nextTrainableTransform));
113   - else _projectPartial( &copy[j], i, nextTrainableTransform);
  112 + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &copy[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 }
... ...