Commit 81f98a0a858a060220dc40dfd7d3e1326b46ff2f

Authored by Jordan Cheney
1 parent 9355e316

Finished reorg. Comments and fixes to follow

Showing 309 changed files with 10084 additions and 9140 deletions

Too many changes.

To preserve performance only 100 of 309 files are displayed.

openbr/plugins/classification/adaboost.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/opencvutils.h>
  3 +
  4 +using namespace cv;
  5 +
  6 +namespace br
  7 +{
  8 +
  9 +/*!
  10 + * \ingroup transforms
  11 + * \brief Wraps OpenCV's Ada Boost framework
  12 + * \author Scott Klum \cite sklum
  13 + * \brief http://docs.opencv.org/modules/ml/doc/boosting.html
  14 + */
  15 +class AdaBoostTransform : public Transform
  16 +{
  17 + Q_OBJECT
  18 + Q_ENUMS(Type)
  19 + Q_ENUMS(SplitCriteria)
  20 +
  21 + Q_PROPERTY(Type type READ get_type WRITE set_type RESET reset_type STORED false)
  22 + Q_PROPERTY(SplitCriteria splitCriteria READ get_splitCriteria WRITE set_splitCriteria RESET reset_splitCriteria STORED false)
  23 + Q_PROPERTY(int weakCount READ get_weakCount WRITE set_weakCount RESET reset_weakCount STORED false)
  24 + Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false)
  25 + Q_PROPERTY(int folds READ get_folds WRITE set_folds RESET reset_folds STORED false)
  26 + Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false)
  27 + Q_PROPERTY(bool returnConfidence READ get_returnConfidence WRITE set_returnConfidence RESET reset_returnConfidence STORED false)
  28 + Q_PROPERTY(bool overwriteMat READ get_overwriteMat WRITE set_overwriteMat RESET reset_overwriteMat STORED false)
  29 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  30 + Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false)
  31 +
  32 +public:
  33 + enum Type { Discrete = CvBoost::DISCRETE,
  34 + Real = CvBoost::REAL,
  35 + Logit = CvBoost::LOGIT,
  36 + Gentle = CvBoost::GENTLE};
  37 +
  38 + enum SplitCriteria { Default = CvBoost::DEFAULT,
  39 + Gini = CvBoost::GINI,
  40 + Misclass = CvBoost::MISCLASS,
  41 + Sqerr = CvBoost::SQERR};
  42 +
  43 +private:
  44 + BR_PROPERTY(Type, type, Real)
  45 + BR_PROPERTY(SplitCriteria, splitCriteria, Default)
  46 + BR_PROPERTY(int, weakCount, 100)
  47 + BR_PROPERTY(float, trimRate, .95)
  48 + BR_PROPERTY(int, folds, 0)
  49 + BR_PROPERTY(int, maxDepth, 1)
  50 + BR_PROPERTY(bool, returnConfidence, true)
  51 + BR_PROPERTY(bool, overwriteMat, true)
  52 + BR_PROPERTY(QString, inputVariable, "Label")
  53 + BR_PROPERTY(QString, outputVariable, "")
  54 +
  55 + CvBoost boost;
  56 +
  57 + void train(const TemplateList &data)
  58 + {
  59 + Mat samples = OpenCVUtils::toMat(data.data());
  60 + Mat labels = OpenCVUtils::toMat(File::get<float>(data, inputVariable));
  61 +
  62 + Mat types = Mat(samples.cols + 1, 1, CV_8U);
  63 + types.setTo(Scalar(CV_VAR_NUMERICAL));
  64 + types.at<char>(samples.cols, 0) = CV_VAR_CATEGORICAL;
  65 +
  66 + CvBoostParams params;
  67 + params.boost_type = type;
  68 + params.split_criteria = splitCriteria;
  69 + params.weak_count = weakCount;
  70 + params.weight_trim_rate = trimRate;
  71 + params.cv_folds = folds;
  72 + params.max_depth = maxDepth;
  73 +
  74 + boost.train( samples, CV_ROW_SAMPLE, labels, Mat(), Mat(), types, Mat(),
  75 + params);
  76 + }
  77 +
  78 + void project(const Template &src, Template &dst) const
  79 + {
  80 + dst = src;
  81 + float response;
  82 + if (returnConfidence) {
  83 + response = boost.predict(src.m().reshape(1,1),Mat(),Range::all(),false,true)/weakCount;
  84 + } else {
  85 + response = boost.predict(src.m().reshape(1,1));
  86 + }
  87 +
  88 + if (overwriteMat) {
  89 + dst.m() = Mat(1, 1, CV_32F);
  90 + dst.m().at<float>(0, 0) = response;
  91 + } else {
  92 + dst.file.set(outputVariable, response);
  93 + }
  94 + }
  95 +
  96 + void load(QDataStream &stream)
  97 + {
  98 + OpenCVUtils::loadModel(boost,stream);
  99 + }
  100 +
  101 + void store(QDataStream &stream) const
  102 + {
  103 + OpenCVUtils::storeModel(boost,stream);
  104 + }
  105 +
  106 +
  107 + void init()
  108 + {
  109 + if (outputVariable.isEmpty())
  110 + outputVariable = inputVariable;
  111 + }
  112 +};
  113 +
  114 +BR_REGISTER(Transform, AdaBoostTransform)
  115 +
  116 +} // namespace br
  117 +
  118 +#include "classification/adaboost.moc"
... ...
openbr/plugins/classification/ebif.cpp
... ... @@ -128,4 +128,4 @@ BR_REGISTER(Transform, EBIFTransform)
128 128  
129 129 } // namespace br
130 130  
131   -#include "ebif.moc"
  131 +#include "classification/ebif.moc"
... ...
openbr/plugins/tree.cpp renamed to openbr/plugins/classification/forest.cpp
1   -#include "openbr_internal.h"
2   -#include "openbr/core/opencvutils.h"
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/opencvutils.h>
3 3  
4   -using namespace std;
5 4 using namespace cv;
6 5  
7 6 namespace br
... ... @@ -250,113 +249,6 @@ class ForestInductionTransform : public ForestTransform
250 249  
251 250 BR_REGISTER(Transform, ForestInductionTransform)
252 251  
253   -/*!
254   - * \ingroup transforms
255   - * \brief Wraps OpenCV's Ada Boost framework
256   - * \author Scott Klum \cite sklum
257   - * \brief http://docs.opencv.org/modules/ml/doc/boosting.html
258   - */
259   -class AdaBoostTransform : public Transform
260   -{
261   - Q_OBJECT
262   - Q_ENUMS(Type)
263   - Q_ENUMS(SplitCriteria)
264   -
265   - Q_PROPERTY(Type type READ get_type WRITE set_type RESET reset_type STORED false)
266   - Q_PROPERTY(SplitCriteria splitCriteria READ get_splitCriteria WRITE set_splitCriteria RESET reset_splitCriteria STORED false)
267   - Q_PROPERTY(int weakCount READ get_weakCount WRITE set_weakCount RESET reset_weakCount STORED false)
268   - Q_PROPERTY(float trimRate READ get_trimRate WRITE set_trimRate RESET reset_trimRate STORED false)
269   - Q_PROPERTY(int folds READ get_folds WRITE set_folds RESET reset_folds STORED false)
270   - Q_PROPERTY(int maxDepth READ get_maxDepth WRITE set_maxDepth RESET reset_maxDepth STORED false)
271   - Q_PROPERTY(bool returnConfidence READ get_returnConfidence WRITE set_returnConfidence RESET reset_returnConfidence STORED false)
272   - Q_PROPERTY(bool overwriteMat READ get_overwriteMat WRITE set_overwriteMat RESET reset_overwriteMat STORED false)
273   - Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
274   - Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false)
275   -
276   -public:
277   - enum Type { Discrete = CvBoost::DISCRETE,
278   - Real = CvBoost::REAL,
279   - Logit = CvBoost::LOGIT,
280   - Gentle = CvBoost::GENTLE};
281   -
282   - enum SplitCriteria { Default = CvBoost::DEFAULT,
283   - Gini = CvBoost::GINI,
284   - Misclass = CvBoost::MISCLASS,
285   - Sqerr = CvBoost::SQERR};
286   -
287   -private:
288   - BR_PROPERTY(Type, type, Real)
289   - BR_PROPERTY(SplitCriteria, splitCriteria, Default)
290   - BR_PROPERTY(int, weakCount, 100)
291   - BR_PROPERTY(float, trimRate, .95)
292   - BR_PROPERTY(int, folds, 0)
293   - BR_PROPERTY(int, maxDepth, 1)
294   - BR_PROPERTY(bool, returnConfidence, true)
295   - BR_PROPERTY(bool, overwriteMat, true)
296   - BR_PROPERTY(QString, inputVariable, "Label")
297   - BR_PROPERTY(QString, outputVariable, "")
298   -
299   - CvBoost boost;
300   -
301   - void train(const TemplateList &data)
302   - {
303   - Mat samples = OpenCVUtils::toMat(data.data());
304   - Mat labels = OpenCVUtils::toMat(File::get<float>(data, inputVariable));
305   -
306   - Mat types = Mat(samples.cols + 1, 1, CV_8U);
307   - types.setTo(Scalar(CV_VAR_NUMERICAL));
308   - types.at<char>(samples.cols, 0) = CV_VAR_CATEGORICAL;
309   -
310   - CvBoostParams params;
311   - params.boost_type = type;
312   - params.split_criteria = splitCriteria;
313   - params.weak_count = weakCount;
314   - params.weight_trim_rate = trimRate;
315   - params.cv_folds = folds;
316   - params.max_depth = maxDepth;
317   -
318   - boost.train( samples, CV_ROW_SAMPLE, labels, Mat(), Mat(), types, Mat(),
319   - params);
320   - }
321   -
322   - void project(const Template &src, Template &dst) const
323   - {
324   - dst = src;
325   - float response;
326   - if (returnConfidence) {
327   - response = boost.predict(src.m().reshape(1,1),Mat(),Range::all(),false,true)/weakCount;
328   - } else {
329   - response = boost.predict(src.m().reshape(1,1));
330   - }
331   -
332   - if (overwriteMat) {
333   - dst.m() = Mat(1, 1, CV_32F);
334   - dst.m().at<float>(0, 0) = response;
335   - } else {
336   - dst.file.set(outputVariable, response);
337   - }
338   - }
339   -
340   - void load(QDataStream &stream)
341   - {
342   - OpenCVUtils::loadModel(boost,stream);
343   - }
344   -
345   - void store(QDataStream &stream) const
346   - {
347   - OpenCVUtils::storeModel(boost,stream);
348   - }
349   -
350   -
351   - void init()
352   - {
353   - if (outputVariable.isEmpty())
354   - outputVariable = inputVariable;
355   - }
356   -};
357   -
358   -BR_REGISTER(Transform, AdaBoostTransform)
359   -
360 252 } // namespace br
361 253  
362   -#include "tree.moc"
  254 +#include "classification/forest.moc"
... ...
openbr/plugins/ipc2013.cpp renamed to openbr/plugins/classification/ipc2013.cpp
1   -#include "openbr_internal.h"
2 1 #include <pxcaccelerator.h>
3 2 #include <pxcface.h>
4 3 #include <pxcimage.h>
5 4 #include <pxcsession.h>
6 5  
  6 +#include <openbr/plugins/openbr_internal.h>
  7 +
7 8 using namespace br;
8 9  
9 10 static PXCSession *pxcSession = NULL;
... ...
openbr/plugins/eigen3.cpp renamed to openbr/plugins/classification/lda.cpp
... ... @@ -16,11 +16,11 @@
16 16  
17 17 #include <Eigen/Dense>
18 18  
19   -#include "openbr_internal.h"
  19 +#include <openbr/plugins/openbr_internal.h>
20 20  
21   -#include "openbr/core/common.h"
22   -#include "openbr/core/eigenutils.h"
23   -#include "openbr/core/opencvutils.h"
  21 +#include <openbr/core/common.h>
  22 +#include <openbr/core/eigenutils.h>
  23 +#include <openbr/core/opencvutils.h>
24 24  
25 25 namespace br
26 26 {
... ... @@ -654,4 +654,4 @@ BR_REGISTER(Transform, SparseLDATransform)
654 654  
655 655 } // namespace br
656 656  
657   -#include "eigen3.moc"
  657 +#include "classification/lda.moc"
... ...
openbr/plugins/liblinear.cpp renamed to openbr/plugins/classification/liblinear.cpp
... ... @@ -2,8 +2,8 @@
2 2 #include <opencv2/core/core.hpp>
3 3 #include <opencv2/ml/ml.hpp>
4 4  
5   -#include "openbr_internal.h"
6   -#include "openbr/core/opencvutils.h"
  5 +#include <openbr/plugins/openbr_internal.h>
  6 +#include <openbr/core/opencvutils.h>
7 7  
8 8 #include <linear.h>
9 9  
... ...
openbr/plugins/nn.cpp renamed to openbr/plugins/classification/mlp.cpp
1 1 #include <opencv2/ml/ml.hpp>
2 2  
3   -#include "openbr_internal.h"
4   -#include "openbr/core/qtutils.h"
5   -#include "openbr/core/opencvutils.h"
6   -#include "openbr/core/eigenutils.h"
7   -#include <QString>
8   -#include <QTemporaryFile>
9   -
10   -using namespace std;
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +#include <openbr/core/opencvutils.h>
  5 +
11 6 using namespace cv;
12 7  
13 8 namespace br
14 9 {
15 10  
16   -static void storeMLP(const CvANN_MLP &mlp, QDataStream &stream)
17   -{
18   - // Create local file
19   - QTemporaryFile tempFile;
20   - tempFile.open();
21   - tempFile.close();
22   -
23   - // Save MLP to local file
24   - mlp.save(qPrintable(tempFile.fileName()));
25   -
26   - // Copy local file contents to stream
27   - tempFile.open();
28   - QByteArray data = tempFile.readAll();
29   - tempFile.close();
30   - stream << data;
31   -}
32   -
33   -static void loadMLP(CvANN_MLP &mlp, QDataStream &stream)
34   -{
35   - // Copy local file contents from stream
36   - QByteArray data;
37   - stream >> data;
38   -
39   - // Create local file
40   - QTemporaryFile tempFile(QDir::tempPath()+"/MLP");
41   - tempFile.open();
42   - tempFile.write(data);
43   - tempFile.close();
44   -
45   - // Load MLP from local file
46   - mlp.load(qPrintable(tempFile.fileName()));
47   -}
48   -
49 11 /*!
50 12 * \ingroup transforms
51 13 * \brief Wraps OpenCV's multi-layer perceptron framework
... ... @@ -124,12 +86,12 @@ private:
124 86  
125 87 void load(QDataStream &stream)
126 88 {
127   - loadMLP(mlp,stream);
  89 + OpenCVUtils::loadModel(mlp, stream);
128 90 }
129 91  
130 92 void store(QDataStream &stream) const
131 93 {
132   - storeMLP(mlp,stream);
  94 + OpenCVUtils::storeModel(mlp, stream);
133 95 }
134 96 };
135 97  
... ... @@ -137,4 +99,4 @@ BR_REGISTER(Transform, MLPTransform)
137 99  
138 100 } // namespace br
139 101  
140   -#include "nn.moc"
  102 +#include "classification/mlp.moc"
... ...
openbr/plugins/nt4.cpp renamed to openbr/plugins/classification/nt4.cpp
... ... @@ -457,4 +457,4 @@ class NT4Compare : public Distance
457 457  
458 458 BR_REGISTER(Distance, NT4Compare)
459 459  
460   -#include "nt4.moc"
  460 +#include "classification/nt4.moc"
... ...
openbr/plugins/pp4.cpp renamed to openbr/plugins/classification/pp4.cpp
openbr/plugins/pp5.cpp renamed to openbr/plugins/classification/pp5.cpp
... ... @@ -593,4 +593,4 @@ class PP5GalleryTransform: public UntrainableMetaTransform
593 593  
594 594 BR_REGISTER(Transform, PP5GalleryTransform)
595 595  
596   -#include "plugins/pp5.moc"
  596 +#include "classification/pp5.moc"
... ...
openbr/plugins/svm.cpp renamed to openbr/plugins/classification/svm.cpp
... ... @@ -18,8 +18,8 @@
18 18 #include <opencv2/core/core.hpp>
19 19 #include <opencv2/ml/ml.hpp>
20 20  
21   -#include "openbr_internal.h"
22   -#include "openbr/core/opencvutils.h"
  21 +#include <openbr/plugins/openbr_internal.h>
  22 +#include <openbr/core/opencvutils.h>
23 23  
24 24 using namespace cv;
25 25  
... ... @@ -261,4 +261,4 @@ BR_REGISTER(Distance, SVMDistance)
261 261  
262 262 } // namespace br
263 263  
264   -#include "svm.moc"
  264 +#include "classification/svm.moc"
... ...
openbr/plugins/classification/turk.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Convenience class for training turk attribute regressors
  9 + * \author Josh Klontz \cite jklontz
  10 + */
  11 +class TurkClassifierTransform : public Transform
  12 +{
  13 + Q_OBJECT
  14 + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false)
  15 + Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false)
  16 + Q_PROPERTY(bool isMeta READ get_isMeta WRITE set_isMeta RESET reset_isMeta STORED false)
  17 + BR_PROPERTY(QString, key, QString())
  18 + BR_PROPERTY(QStringList, values, QStringList())
  19 + BR_PROPERTY(bool, isMeta, false)
  20 +
  21 + Transform *child;
  22 +
  23 + void init()
  24 + {
  25 + QStringList classifiers;
  26 + foreach (const QString &value, values)
  27 + classifiers.append(QString("(SVM(RBF,EPS_SVR,returnDFVal=true,inputVariable=%1,outputVariable=predicted_%1)%2)").arg(key + "_" + value, isMeta ? QString("+Average+SaveMat(predicted_%1)").arg(value) : QString()));
  28 + child = Transform::make(classifiers.join("/") + (classifiers.size() > 1 ? "+Cat" : ""));
  29 + }
  30 +
  31 + void train(const QList<TemplateList> &data)
  32 + {
  33 + child->train(data);
  34 + }
  35 +
  36 + void project(const Template &src, Template &dst) const
  37 + {
  38 + child->project(src, dst);
  39 + }
  40 +
  41 + void store(QDataStream &stream) const
  42 + {
  43 + child->store(stream);
  44 + }
  45 +
  46 + void load(QDataStream &stream)
  47 + {
  48 + child->load(stream);
  49 + }
  50 +};
  51 +
  52 +BR_REGISTER(Transform, TurkClassifierTransform)
  53 +
  54 +} // namespace br
  55 +
  56 +#include "classification/turk.moc"
... ...
openbr/plugins/cluster/collectnn.cpp
... ... @@ -39,4 +39,4 @@ BR_REGISTER(Transform, CollectNNTransform)
39 39  
40 40 } // namespace br
41 41  
42   -#include "collectnn.moc"
  42 +#include "cluster/collectnn.moc"
... ...
openbr/plugins/cluster/kmeans.cpp
... ... @@ -62,4 +62,4 @@ BR_REGISTER(Transform, KMeansTransform)
62 62  
63 63 } // namespace br
64 64  
65   -#include "kmeans.moc"
  65 +#include "cluster/kmeans.moc"
... ...
openbr/plugins/cluster/knn.cpp
... ... @@ -81,4 +81,4 @@ BR_REGISTER(Transform, KNNTransform)
81 81  
82 82 } // namespace br
83 83  
84   -#include "knn.moc"
  84 +#include "cluster/knn.moc"
... ...
openbr/plugins/cluster/lognn.cpp
... ... @@ -62,4 +62,4 @@ BR_REGISTER(Transform, LogNNTransform)
62 62  
63 63 } // namespace br
64 64  
65   -#include "lognn.moc"
  65 +#include "cluster/lognn.moc"
... ...
openbr/plugins/cluster/randomcentroids.cpp
... ... @@ -65,4 +65,4 @@ BR_REGISTER(Transform, RandomCentroidsTransform)
65 65  
66 66 } //namespace br
67 67  
68   -#include "randomcentroids.moc"
  68 +#include "cluster/randomcentroids.moc"
... ...
openbr/plugins/eigen3.cmake renamed to openbr/plugins/cmake/eigen3.cmake
... ... @@ -2,6 +2,8 @@ set(BR_WITH_EIGEN3 ON CACHE BOOL &quot;Build Eigen3 plugins&quot;)
2 2  
3 3 if(${BR_WITH_EIGEN3})
4 4 find_package(Eigen3 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/eigen3.cpp)
6 5 install(FILES ${EIGEN3_LICENSE} RENAME Eigen3 DESTINATION share/openbr/licenses)
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/lda.cpp)
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/revertaffine.cpp)
7 9 endif()
... ...
openbr/plugins/ipc2013.cmake renamed to openbr/plugins/cmake/ipc2013.cmake
... ... @@ -2,7 +2,8 @@ set(BR_WITH_IPC2013 OFF CACHE BOOL &quot;Build with Intel Perceptual Computing SDK 20
2 2  
3 3 if(${BR_WITH_IPC2013})
4 4 find_package(IPC2013 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/ipc2013.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${IPC2013_LIBS})
7 6 install(DIRECTORY ${IPC2013_DIR}/bin/x64/ DESTINATION bin)
  7 +else()
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/ipc2013.cpp)
8 9 endif()
... ...
openbr/plugins/jni.cmake renamed to openbr/plugins/cmake/jni.cmake
... ... @@ -3,10 +3,10 @@ set(BR_WITH_JAVA OFF CACHE BOOL &quot;Use Java Code&quot;)
3 3 if (${BR_WITH_JAVA})
4 4 find_package(JNI REQUIRED)
5 5 find_package(JAVA REQUIRED)
6   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/jni.cpp)
7 6 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${JNI_LIBRARIES})
8 7  
9 8 include_directories(${JAVA_INCLUDE_PATH})
10 9 include_directories(${JAVA_INCLUDE_PATH2})
11   -
  10 +else()
  11 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/jni.cpp)
12 12 endif()
... ...
openbr/plugins/liblinear.cmake renamed to openbr/plugins/cmake/liblinear.cmake
... ... @@ -3,5 +3,6 @@ set(BR_WITH_LIBLINEAR OFF CACHE BOOL &quot;Build with LibLinear&quot;)
3 3 if(${BR_WITH_LIBLINEAR})
4 4 find_package(LibLinear REQUIRED)
5 5 set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${LibLinear_SRC})
6   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/liblinear.cpp)
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/liblinear.cpp)
7 8 endif()
... ...
openbr/plugins/likely.cmake renamed to openbr/plugins/cmake/likely.cmake
... ... @@ -2,6 +2,9 @@ set(BR_WITH_LIKELY OFF CACHE BOOL &quot;Build with Likely&quot;)
2 2  
3 3 if(${BR_WITH_LIKELY})
4 4 find_package(Likely REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/likely.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Likely_LIBS})
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/core/likely.cpp)
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/lmat.cpp)
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/lmat.cpp)
7 10 endif()
... ...
openbr/plugins/mongoose.cmake renamed to openbr/plugins/cmake/mongoose.cmake
1 1 set(BR_WITH_MONGOOSE OFF CACHE BOOL "Build with Mongoose")
2 2 if(${BR_WITH_MONGOOSE})
3 3 find_package(Mongoose)
4   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/mongoose.cpp ${MONGOOSE_SRC})
  4 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${MONGOOSE_SRC})
5 5 install(FILES ${MONGOOSE_LICENSE} RENAME mongoose DESTINATION share/openbr/licenses)
  6 +else()
  7 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/mongoose.cpp)
6 8 endif()
... ...
openbr/plugins/qtnetwork.cmake renamed to openbr/plugins/cmake/network.cmake
... ... @@ -3,6 +3,10 @@ if(${BR_WITH_QTNETWORK})
3 3 find_package(Qt5Network)
4 4 find_package(HttpParser)
5 5 set(QT_DEPENDENCIES ${QT_DEPENDENCIES} Network)
6   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/qtnetwork.cpp ${HTTPPARSER_SRC})
  6 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${HTTPPARSER_SRC})
7 7 install(FILES ${HTTPPARSER_LICENSE} RENAME http-parser DESTINATION share/openbr/licenses)
  8 +else()
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/urlformat.cpp)
  10 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/format/postformat.cpp)
  11 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gallery/postgallery.cpp)
8 12 endif()
... ...
openbr/plugins/nt4.cmake renamed to openbr/plugins/cmake/nt4.cmake
... ... @@ -2,7 +2,8 @@ set(BR_WITH_NT4 OFF CACHE BOOL &quot;Build with Neurotec Biometric 4&quot;)
2 2  
3 3 if(${BR_WITH_NT4})
4 4 find_package(NT4 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/nt4.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${NT4_LIBS})
7 6 install(DIRECTORY ${NT4_DIR_LIB}/ DESTINATION lib)
  7 +else()
  8 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/nt4.cpp)
8 9 endif()
... ...
openbr/plugins/pp4.cmake renamed to openbr/plugins/cmake/pp4.cmake
... ... @@ -2,8 +2,9 @@ set(BR_WITH_PP4 OFF CACHE BOOL &quot;Build with PittPatt 4&quot;)
2 2  
3 3 if(${BR_WITH_PP4})
4 4 find_package(PP4 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp4.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP4_LIBS})
7 6 install(DIRECTORY ${PP4_DIR}/lib/ DESTINATION lib)
8 7 install(DIRECTORY ${PP4_DIR}/models/ DESTINATION models/pp4)
  8 +else()
  9 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/pp4.cpp)
9 10 endif()
... ...
openbr/plugins/pp5.cmake renamed to openbr/plugins/cmake/pp5.cmake
... ... @@ -2,7 +2,6 @@ set(BR_WITH_PP5 OFF CACHE BOOL &quot;Build with PittPatt 5&quot;)
2 2  
3 3 if(${BR_WITH_PP5})
4 4 find_package(PP5 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/pp5.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${PP5_LIBS})
7 6  
8 7 if(WIN32)
... ... @@ -12,4 +11,6 @@ if(${BR_WITH_PP5})
12 11 endif()
13 12  
14 13 install(DIRECTORY ${PP5_DIR}/models/ DESTINATION share/openbr/models/pp5)
  14 +else()
  15 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/classification/pp5.cpp)
15 16 endif()
... ...
openbr/plugins/cmake/show.cmake 0 → 100644
  1 +if(${BR_EMBEDDED})
  2 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/gui/show.cpp)
  3 +endif()
... ...
openbr/plugins/stasm4.cmake renamed to openbr/plugins/cmake/stasm4.cmake
... ... @@ -2,7 +2,6 @@ set(BR_WITH_STASM4 OFF CACHE BOOL &quot;Build with Stasm&quot;)
2 2  
3 3 if(${BR_WITH_STASM4})
4 4 find_package(Stasm4 REQUIRED)
5   - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/stasm4.cpp)
6 5 set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${Stasm4_LIBS})
7 6  
8 7 if(WIN32)
... ... @@ -12,4 +11,7 @@ if(${BR_WITH_STASM4})
12 11 endif()
13 12  
14 13 install(DIRECTORY ${Stasm_DIR}/data/ DESTINATION share/openbr/models/stasm)
  14 +else()
  15 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/metadata/stasm4.cpp)
  16 + set(BR_EXCLUDED_PLUGINS ${BR_EXCLUDED_PLUGINS} plugins/imgproc/revertaffine.cpp)
15 17 endif()
... ...
openbr/plugins/core/algorithms.cpp
... ... @@ -108,4 +108,4 @@ BR_REGISTER(Initializer, AlgorithmsInitializer)
108 108  
109 109 } // namespace br
110 110  
111   -#include "algorithms.moc"
  111 +#include "core/algorithms.moc"
... ...
openbr/plugins/core/attributealgorithms.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup initializers
  8 + * \brief Initializes global abbreviations with implemented algorithms for attributes
  9 + * \author Babatunde Ogunfemi \cite baba1472
  10 + */
  11 +class AttributeAlgorithmsInitializer : public Initializer
  12 +{
  13 + Q_OBJECT
  14 +
  15 + void initialize() const
  16 + {
  17 + // Constants
  18 + QString BASE="Open+PP5Register+Rename(PP5_Landmark0_Right_Eye,Affine_0)+Rename(PP5_Landmark1_Left_Eye,Affine_1)+Affine(192,240,.345,.475)+Cvt(Gray)+Stasm(false,true,[(66.24,114),(125.76,114)])";
  19 + QString SUBSPACE ="Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,4,4)+Hist(59)+Cat+PCA(0.95)";
  20 +
  21 + QString NOSE="RectFromStasmNoseWithBridge+ROI+Resize(36,24)+" + SUBSPACE;
  22 + QString MOUTH="RectFromStasmMouth+ROI+Resize(24,36)+" + SUBSPACE;
  23 + QString EYES="RectFromStasmEyes+ROI+Resize(24,36)+" + SUBSPACE;
  24 + QString HAIR="RectFromStasmHair+ROI+Resize(24,36)+" + SUBSPACE;
  25 + QString BROW="RectFromStasmBrow+ROI+Resize(24,36)+" + SUBSPACE;
  26 + QString JAW="RectFromStasmJaw+ROI+Resize(36,36)+" + SUBSPACE;
  27 + QString FACE = "Crop(24,30,144,190)+Resize(36,36)+" + SUBSPACE;
  28 +
  29 + // All Attributes
  30 + Globals->abbreviations.insert("AllAttributes", "AttributeBrow/AttributeMouth/AttributeEyes/AttributeFace/AttributeHair/AttributeNose/AttributeJaw");
  31 + Globals->abbreviations.insert("AllAttributesMatching", "(AttributeBrow)/(AttributeMouth)/(AttributeEyes)/(AttributeFace)/(AttributeHair)/(AttributeNose)/(AttributeJaw):AttributeMatch");
  32 +
  33 + //Individual Attributes
  34 + Globals->abbreviations.insert("AttributeBrow", "(" + BASE+ "+" + BROW + "+"
  35 + "TurkClassifier(eyebrowposition,[closebrows,highbrows],3)/"
  36 + "TurkClassifier(unibrow,[unibrow],3)/"
  37 + "TurkClassifier(eyebroworientation,[eyebrowsdown,eyebrowsuptodown],3)/"
  38 + "TurkClassifier(thickeyebrows,[thickeyebrows,lighteyebrows],3))");
  39 + Globals->abbreviations.insert("AttributeMouth", "(" + BASE + "+" + MOUTH + "+"
  40 + "TurkClassifier(smiling,[smiling],3)/"
  41 + "TurkClassifier(lipthickness,[cherry,big,small],3)/"
  42 + "TurkClassifier(mouthbite,[underbite,overbite],3)/"
  43 + "TurkClassifier(mouthopen,[closed,noteeth,halfteeth,allteeth],3)/"
  44 + "TurkClassifier(mouthwidth,[small,wide],3)/"
  45 + "TurkClassifier(mustache,[nomustache,linemustache,lightmustache,normalmustache,down],3)/"
  46 + "TurkClassifier(mouthasymmetry,[asymmetrical],3))");
  47 + Globals->abbreviations.insert("AttributeEyes", "(" + BASE + "+" + EYES + "+ "
  48 + "TurkClassifier(eyeseparation,[close,wide],3)/"
  49 + "TurkClassifier(eyeslant,[slant2,slant1,wild],3)/"
  50 + "TurkClassifier(benteyes,[bent])/"
  51 + "TurkClassifier(eyecolor,[darkeyes,lighteyes],3)/"
  52 + "TurkClassifier(baggyeyes,[baggy],3)/"
  53 + "TurkClassifier(almondeyes,[almond],3)/"
  54 + "TurkClassifier(buriedeyes,[buriedeyes],3)/"
  55 + "TurkClassifier(sleepyeyes,[sleepy],3)/"
  56 + "TurkClassifier(lineeyes,[line],3)/"
  57 + "TurkClassifier(roundeyes,[round],3)/"
  58 + "TurkClassifier(sharpeyes,[sharp],3)/"
  59 + "TurkClassifier(smalleyes,[smalleyes],3)/"
  60 + "TurkClassifier(glasses,[glasses],3)/"
  61 + "TurkClassifier(eyelashvisibility,[feweyelashes],3))");
  62 + Globals->abbreviations.insert("AttributeFace", "(" + BASE + "+" + FACE + "+"
  63 + "TurkClassifier(gender,[male],3)/"
  64 + "TurkClassifier(faceshape,[round,triangular,rectangular],3)/"
  65 + "TurkClassifier(cheekdensity,[puffy,in,normal],3)/"
  66 + "TurkClassifier(facemarks,[scars,moles,normal],3)/"
  67 + "TurkClassifier(facelength,[long],3)/"
  68 + "TurkClassifier(nosetoeyedist,[short,long],3)/"
  69 + "TurkClassifier(nosetomouthdist,[long,small],3))");
  70 + Globals->abbreviations.insert("AttributeHair", "(" + BASE + "+" + HAIR + "+"
  71 + "TurkClassifier(foreheadwrinkles,[wrinkled],3)/"
  72 + "TurkClassifier(foreheadsize,[smallforehead,largeforehead],3)/"
  73 + "TurkClassifier(haircolor,[darkhair,lighthair,greyhair],3)/"
  74 + "TurkClassifier(hairdensity,[thick,bald,thin,halfbald],3)/"
  75 + "TurkClassifier(widowspeak,[widowspeak],3)/"
  76 + "TurkClassifier(hairstyle,[curlyhair],3))");
  77 + Globals->abbreviations.insert("AttributeNose", "(" + BASE + "+" + NOSE + "+"
  78 + "TurkClassifier(noseorientation,[upnose,downnose],3)/"
  79 + "TurkClassifier(nosewidth,[small,thick],3)/"
  80 + "TurkClassifier(nosesize,[smallnose,bignose],3)/"
  81 + "TurkClassifier(brokennose,[broken],3))");
  82 + Globals->abbreviations.insert("AttributeJaw", "(" + BASE + "+" + JAW + "+"
  83 + "TurkClassifier(beard,[nobeard,bigbeard,lightbeard,goatee,linebeard,normalbeard,lincolnbeard],3)/"
  84 + "TurkClassifier(chinsize,[shortchin,longchin],3))");
  85 + Globals->abbreviations.insert("AttributeMatch", "Fuse(["
  86 + "Turk(eyebrowposition,[closebrows,highbrows],3),"
  87 + "Turk(unibrow,[unibrow],3),"
  88 + "Turk(eyebroworientation,[eyebrowsdown,eyebrowsuptodown],3),"
  89 + "Turk(thickeyebrows,[thickeyebrows,lighteyebrows],3),"
  90 + "Turk(smiling,[smiling],3),"
  91 + "Turk(lipthickness,[cherry,big,small],3),"
  92 + "Turk(mouthbite,[underbite,overbite],3),"
  93 + "Turk(mouthopen,[closed,noteeth,halfteeth,allteeth],3),"
  94 + "Turk(mouthwidth,[small,wide],3),"
  95 + "Turk(mustache,[nomustache,linemustache,lightmustache,normalmustache,down],3),"
  96 + "Turk(mouthasymmetry,[asymmetrical],3),"
  97 + "Turk(eyeseparation,[close,wide],3),"
  98 + "Turk(eyeslant,[slant2,slant1,wild],3),"
  99 + "Turk(benteyes,[bent],3),"
  100 + "Turk(eyecolor,[darkeyes,lighteyes],3),"
  101 + "Turk(baggyeyes,[baggy],3),"
  102 + "Turk(almondeyes,[almond],3),"
  103 + "Turk(buriedeyes,[buriedeyes],3),"
  104 + "Turk(sleepyeyes,[sleepy],3),"
  105 + "Turk(lineeyes,[line],3),"
  106 + "Turk(roundeyes,[round],3),"
  107 + "Turk(sharpeyes,[sharp],3),"
  108 + "Turk(smalleyes,[smalleyes],3),"
  109 + "Turk(glasses,[glasses],3),"
  110 + "Turk(eyelashvisibility,[feweyelashes],3),"
  111 + "Turk(gender,[male],3),"
  112 + "Turk(faceshape,[round,triangular,rectangular],3),"
  113 + "Turk(cheekdensity,[puffy,in,normal],3),"
  114 + "Turk(facemarks,[scars,moles,normal],3),"
  115 + "Turk(facelength,[long],3),"
  116 + "Turk(nosetoeyedist,[short,long],3),"
  117 + "Turk(nosetomouthdist,[long,small],3),"
  118 + "Turk(foreheadwrinkles,[wrinkled],3),"
  119 + "Turk(foreheadsize,[smallforehead,largeforehead],3),"
  120 + "Turk(haircolor,[darkhair,lighthair,greyhair],3),"
  121 + "Turk(hairdensity,[thick,bald,thin,halfbald],3),"
  122 + "Turk(widowspeak,[widowspeak],3),"
  123 + "Turk(hairstyle,[curlyhair],3),"
  124 + "Turk(noseorientation,[upnose,downnose],3),"
  125 + "Turk(nosewidth,[small,thick],3),"
  126 + "Turk(nosesize,[smallnose,bignose],3),"
  127 + "Turk(brokennose,[broken],3),"
  128 + "Turk(beard,[nobeard,bigbeard,lightbeard,goatee,linebeard,normalbeard,lincolnbeard],3),"
  129 + "Turk(chinsize,[shortchin,longchin],3)])");
  130 + }
  131 +};
  132 +
  133 +BR_REGISTER(Initializer, AttributeAlgorithmsInitializer)
  134 +
  135 +} // namespace br
  136 +
  137 +#include "core/attributealgorithms.moc"
... ...
openbr/plugins/core/cache.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Caches br::Transform::project() results.
  9 + * \author Josh Klontz \cite jklontz
  10 + */
  11 +class CacheTransform : public MetaTransform
  12 +{
  13 + Q_OBJECT
  14 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  15 + BR_PROPERTY(br::Transform*, transform, NULL)
  16 +
  17 + static QHash<QString, Template> cache;
  18 + static QMutex cacheLock;
  19 +
  20 +public:
  21 + ~CacheTransform()
  22 + {
  23 + if (cache.isEmpty()) return;
  24 +
  25 + // Write to cache
  26 + QFile file("Cache");
  27 + if (!file.open(QFile::WriteOnly))
  28 + qFatal("Unable to open %s for writing.", qPrintable(file.fileName()));
  29 + QDataStream stream(&file);
  30 + stream << cache;
  31 + file.close();
  32 + }
  33 +
  34 +private:
  35 + void init()
  36 + {
  37 + if (!transform) return;
  38 +
  39 + trainable = transform->trainable;
  40 + if (!cache.isEmpty()) return;
  41 +
  42 + // Read from cache
  43 + QFile file("Cache");
  44 + if (file.exists()) {
  45 + if (!file.open(QFile::ReadOnly))
  46 + qFatal("Unable to open %s for reading.", qPrintable(file.fileName()));
  47 + QDataStream stream(&file);
  48 + stream >> cache;
  49 + file.close();
  50 + }
  51 + }
  52 +
  53 + void train(const QList<TemplateList> &data)
  54 + {
  55 + transform->train(data);
  56 + }
  57 +
  58 + void project(const Template &src, Template &dst) const
  59 + {
  60 + const QString &file = src.file;
  61 + if (cache.contains(file)) {
  62 + dst = cache[file];
  63 + } else {
  64 + transform->project(src, dst);
  65 + cacheLock.lock();
  66 + cache[file] = dst;
  67 + cacheLock.unlock();
  68 + }
  69 + }
  70 +};
  71 +
  72 +QHash<QString, Template> CacheTransform::cache;
  73 +QMutex CacheTransform::cacheLock;
  74 +
  75 +BR_REGISTER(Transform, CacheTransform)
  76 +
  77 +} // namespace br
  78 +
  79 +#include "core/cache.moc"
... ...
openbr/plugins/core/contract.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief It's like the opposite of ExpandTransform, but not really
  9 + * \author Charles Otto \cite caotto
  10 + *
  11 + * Given a set of templatelists as input, concatenate them onto a single Template
  12 + */
  13 +class ContractTransform : public UntrainableMetaTransform
  14 +{
  15 + Q_OBJECT
  16 +
  17 + virtual void project(const TemplateList &src, TemplateList &dst) const
  18 + {
  19 + if (src.empty()) return;
  20 + Template out;
  21 +
  22 + foreach (const Template &t, src) {
  23 + out.merge(t);
  24 + }
  25 + out.file.clearRects();
  26 + foreach (const Template &t, src) {
  27 + if (!t.file.rects().empty())
  28 + out.file.appendRects(t.file.rects());
  29 + }
  30 + dst.clear();
  31 + dst.append(out);
  32 + }
  33 +
  34 + virtual void project(const Template &src, Template &dst) const
  35 + {
  36 + qFatal("this has gone bad");
  37 + (void) src; (void) dst;
  38 + }
  39 +};
  40 +
  41 +BR_REGISTER(Transform, ContractTransform)
  42 +
  43 +} // namespace br
  44 +
  45 +#include "core/contract.moc"
... ...
openbr/plugins/validate.cpp renamed to openbr/plugins/core/crossvalidate.cpp
1   -#include <QFutureSynchronizer>
2   -#include <QtConcurrentRun>
3   -#include "openbr_internal.h"
4   -#include "openbr/core/common.h"
5   -#include <openbr/core/qtutils.h>
  1 +#include <QtConcurrent>
  2 +
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +#include <openbr/core/common.h>
6 5  
7 6 namespace br
8 7 {
... ... @@ -134,138 +133,6 @@ class CrossValidateTransform : public MetaTransform
134 133  
135 134 BR_REGISTER(Transform, CrossValidateTransform)
136 135  
137   -/*!
138   - * \ingroup distances
139   - * \brief Cross validate a distance metric.
140   - * \author Josh Klontz \cite jklontz
141   - */
142   -class CrossValidateDistance : public UntrainableDistance
143   -{
144   - Q_OBJECT
145   -
146   - float compare(const Template &a, const Template &b) const
147   - {
148   - static const QString key("Partition"); // More efficient to preallocate this
149   - const int partitionA = a.file.get<int>(key, 0);
150   - const int partitionB = b.file.get<int>(key, 0);
151   - return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0;
152   - }
153   -};
154   -
155   -BR_REGISTER(Distance, CrossValidateDistance)
156   -
157   -/*!
158   - * \ingroup distances
159   - * \brief Checks target metadata against filters.
160   - * \author Josh Klontz \cite jklontz
161   - */
162   -class FilterDistance : public UntrainableDistance
163   -{
164   - Q_OBJECT
165   -
166   - float compare(const Template &a, const Template &b) const
167   - {
168   - (void) b; // Query template isn't checked
169   - foreach (const QString &key, Globals->filters.keys()) {
170   - bool keep = false;
171   - const QString metadata = a.file.get<QString>(key, "");
172   - if (Globals->filters[key].isEmpty()) continue;
173   - if (metadata.isEmpty()) return -std::numeric_limits<float>::max();
174   - foreach (const QString &value, Globals->filters[key]) {
175   - if (metadata == value) {
176   - keep = true;
177   - break;
178   - }
179   - }
180   - if (!keep) return -std::numeric_limits<float>::max();
181   - }
182   - return 0;
183   - }
184   -};
185   -
186   -BR_REGISTER(Distance, FilterDistance)
187   -
188   -/*!
189   - * \ingroup distances
190   - * \brief Checks target metadata against query metadata.
191   - * \author Scott Klum \cite sklum
192   - */
193   -class MetadataDistance : public UntrainableDistance
194   -{
195   - Q_OBJECT
196   -
197   - Q_PROPERTY(QStringList filters READ get_filters WRITE set_filters RESET reset_filters STORED false)
198   - BR_PROPERTY(QStringList, filters, QStringList())
199   -
200   - float compare(const Template &a, const Template &b) const
201   - {
202   - foreach (const QString &key, filters) {
203   - QString aValue = a.file.get<QString>(key, QString());
204   - QString bValue = b.file.get<QString>(key, QString());
205   -
206   - // The query value may be a range. Let's check.
207   - if (bValue.isEmpty()) bValue = QtUtils::toString(b.file.get<QPointF>(key, QPointF()));
208   -
209   - if (aValue.isEmpty() || bValue.isEmpty()) continue;
210   -
211   - bool keep = false;
212   - bool ok;
213   -
214   - QPointF range = QtUtils::toPoint(bValue,&ok);
215   -
216   - if (ok) /* Range */ {
217   - int value = range.x();
218   - int upperBound = range.y();
219   -
220   - while (value <= upperBound) {
221   - if (aValue == QString::number(value)) {
222   - keep = true;
223   - break;
224   - }
225   - value++;
226   - }
227   - }
228   - else if (aValue == bValue) keep = true;
229   -
230   - if (!keep) return -std::numeric_limits<float>::max();
231   - }
232   - return 0;
233   - }
234   -};
235   -
236   -
237   -BR_REGISTER(Distance, MetadataDistance)
238   -
239   -/*!
240   - * \ingroup distances
241   - * \brief Sets distance to -FLOAT_MAX if a target template has/doesn't have a key.
242   - * \author Scott Klum \cite sklum
243   - */
244   -class RejectDistance : public UntrainableDistance
245   -{
246   - Q_OBJECT
247   -
248   - Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
249   - BR_PROPERTY(QStringList, keys, QStringList())
250   - Q_PROPERTY(bool rejectIfContains READ get_rejectIfContains WRITE set_rejectIfContains RESET reset_rejectIfContains STORED false)
251   - BR_PROPERTY(bool, rejectIfContains, false)
252   -
253   - float compare(const Template &a, const Template &b) const
254   - {
255   - // We don't look at the query
256   - (void) b;
257   -
258   - foreach (const QString &key, keys)
259   - if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key)))
260   - return -std::numeric_limits<float>::max();
261   -
262   - return 0;
263   - }
264   -};
265   -
266   -
267   -BR_REGISTER(Distance, RejectDistance)
268   -
269 136 } // namespace br
270 137  
271   -#include "validate.moc"
  138 +#include "core/crossvalidate.moc"
... ...
openbr/plugins/core/discard.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Removes all template's matrices.
  9 + * \see IdentityTransform FirstTransform RestTransform RemoveTransform
  10 + * \author Josh Klontz \cite jklontz
  11 + */
  12 +class DiscardTransform : public UntrainableMetaTransform
  13 +{
  14 + Q_OBJECT
  15 +
  16 + void project(const Template &src, Template &dst) const
  17 + {
  18 + dst.file = src.file;
  19 + }
  20 +};
  21 +
  22 +BR_REGISTER(Transform, DiscardTransform)
  23 +
  24 +} // namespace br
  25 +
  26 +#include "core/discard.moc"
... ...
openbr/plugins/core/discardtemplates.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +class DiscardTemplatesTransform : public UntrainableMetaTransform
  7 +{
  8 + Q_OBJECT
  9 +
  10 + void project(const Template &src, Template &dst) const
  11 + {
  12 + (void) src; (void) dst;
  13 + qFatal("Incorrect project called on DiscardTemplatesTransform");
  14 + }
  15 + void project(const TemplateList &src, TemplateList &dst) const
  16 + {
  17 + (void) src;
  18 + dst.clear();
  19 + }
  20 +};
  21 +
  22 +BR_REGISTER(Transform, DiscardTemplatesTransform)
  23 +
  24 +} // namespace br
  25 +
  26 +#include "core/discardtemplates.moc"
... ...
openbr/plugins/core/distributetemplate.cpp 0 → 100644
  1 +#include <QtConcurrent>
  2 +
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +
  5 +namespace br
  6 +{
  7 +
  8 +static void _projectList(const Transform *transform, const TemplateList *src, TemplateList *dst)
  9 +{
  10 + transform->project(*src, *dst);
  11 +}
  12 +
  13 +class DistributeTemplateTransform : public MetaTransform
  14 +{
  15 + Q_OBJECT
  16 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  17 + BR_PROPERTY(br::Transform*, transform, NULL)
  18 +
  19 +public:
  20 +
  21 + Transform *smartCopy(bool &newTransform)
  22 + {
  23 + if (!transform->timeVarying()) {
  24 + newTransform = false;
  25 + return this;
  26 + }
  27 + newTransform = true;
  28 +
  29 + DistributeTemplateTransform *output = new DistributeTemplateTransform;
  30 + bool newChild = false;
  31 + output->transform = transform->smartCopy(newChild);
  32 + if (newChild)
  33 + output->transform->setParent(output);
  34 +
  35 + return output;
  36 + }
  37 +
  38 + void train(const QList<TemplateList> &data)
  39 + {
  40 + if (!transform->trainable) {
  41 + qWarning("Attempted to train untrainable transform, nothing will happen.");
  42 + return;
  43 + }
  44 +
  45 + QList<TemplateList> separated;
  46 + foreach (const TemplateList &list, data) {
  47 + foreach (const Template &t, list) {
  48 + separated.append(TemplateList());
  49 + separated.last().append(t);
  50 + }
  51 + }
  52 +
  53 + transform->train(separated);
  54 + }
  55 +
  56 + void project(const Template &src, Template &dst) const
  57 + {
  58 + TemplateList input;
  59 + input.append(src);
  60 + TemplateList output;
  61 + project(input, output);
  62 +
  63 + if (output.size() != 1) qFatal("output contains more than 1 template");
  64 + else dst = output[0];
  65 + }
  66 +
  67 + // For each input template, form a single element TemplateList, push all those
  68 + // lists through transform, and form dst by concatenating the results.
  69 + // Process the single elemnt templates in parallel if parallelism is enabled.
  70 + void project(const TemplateList &src, TemplateList &dst) const
  71 + {
  72 + // Pre-allocate output for each template
  73 + QList<TemplateList> output_buffer;
  74 + output_buffer.reserve(src.size());
  75 +
  76 + // Can't declare this local to the loop because it would go out of scope
  77 + QList<TemplateList> input_buffer;
  78 + input_buffer.reserve(src.size());
  79 +
  80 + QFutureSynchronizer<void> futures;
  81 +
  82 + for (int i =0; i < src.size();i++) {
  83 + input_buffer.append(TemplateList());
  84 + output_buffer.append(TemplateList());
  85 + }
  86 + QList<QFuture<void> > temp;
  87 + temp.reserve(src.size());
  88 + for (int i=0; i<src.size(); i++) {
  89 + input_buffer[i].append(src[i]);
  90 +
  91 + if (Globals->parallelism > 1) temp.append(QtConcurrent::run(_projectList, transform, &input_buffer[i], &output_buffer[i]));
  92 + else _projectList(transform, &input_buffer[i], &output_buffer[i]);
  93 + }
  94 + // We add the futures in reverse order, since in Qt 5.1 at least the
  95 + // waiting thread will wait on them in the order added (which for uniform priority
  96 + // threads is the order of execution), and we want the waiting thread to go in the opposite order
  97 + // so that it can steal runnables and do something besides wait.
  98 + for (int i = temp.size() - 1; i >= 0; i--) {
  99 + futures.addFuture(temp[i]);
  100 + }
  101 +
  102 + futures.waitForFinished();
  103 +
  104 + for (int i=0; i<src.size(); i++) dst.append(output_buffer[i]);
  105 + }
  106 +
  107 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  108 + {
  109 + this->project(src, dst);
  110 + return;
  111 + }
  112 +
  113 + void init()
  114 + {
  115 + if (!transform)
  116 + return;
  117 +
  118 + trainable = transform->trainable;
  119 + }
  120 +
  121 +};
  122 +BR_REGISTER(Transform, DistributeTemplateTransform)
  123 +
  124 +} // namespace br
  125 +
  126 +#include "core/distributetemplate.moc"
... ...
openbr/plugins/core/downsample.cpp renamed to openbr/plugins/core/downsampletraining.cpp
... ... @@ -116,4 +116,4 @@ BR_REGISTER(Transform, DownsampleTrainingTransform)
116 116  
117 117 } // namespace br
118 118  
119   -#include "downsample.moc"
  119 +#include "core/downsampletraining.moc"
... ...
openbr/plugins/core/event.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +class EventTransform : public UntrainableMetaTransform
  7 +{
  8 + Q_OBJECT
  9 + Q_PROPERTY(QString eventName READ get_eventName WRITE set_eventName RESET reset_eventName STORED false)
  10 + BR_PROPERTY(QString, eventName, "")
  11 +
  12 + TemplateEvent event;
  13 +
  14 + void project(const Template &src, Template &dst) const
  15 + {
  16 + dst = src;
  17 + event.pulseSignal(dst);
  18 + }
  19 +
  20 + TemplateEvent *getEvent(const QString &name)
  21 + {
  22 + return name == eventName ? &event : NULL;
  23 + }
  24 +};
  25 +
  26 +BR_REGISTER(Transform, EventTransform)
  27 +
  28 +} // namespace br
  29 +
  30 +#include "core/event.moc"
... ...
openbr/plugins/core/expand.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +static TemplateList Expanded(const TemplateList &templates)
  7 +{
  8 + TemplateList expanded;
  9 + foreach (const Template &t, templates) {
  10 + const bool enrollAll = t.file.get<bool>("enrollAll");
  11 + if (t.isEmpty()) {
  12 + if (!enrollAll)
  13 + expanded.append(t);
  14 + continue;
  15 + }
  16 +
  17 + const QList<QPointF> points = t.file.points();
  18 + const QList<QRectF> rects = t.file.rects();
  19 + if (points.size() % t.size() != 0) qFatal("Uneven point count.");
  20 + if (rects.size() % t.size() != 0) qFatal("Uneven rect count.");
  21 + const int pointStep = points.size() / t.size();
  22 + const int rectStep = rects.size() / t.size();
  23 +
  24 + for (int i=0; i<t.size(); i++) {
  25 + expanded.append(Template(t.file, t[i]));
  26 + expanded.last().file.setRects(rects.mid(i*rectStep, rectStep));
  27 + expanded.last().file.setPoints(points.mid(i*pointStep, pointStep));
  28 + }
  29 + }
  30 + return expanded;
  31 +}
  32 +
  33 +/*!
  34 + * \ingroup transforms
  35 + * \brief Performs an expansion step on input templatelists
  36 + * \author Josh Klontz \cite jklontz
  37 + *
  38 + * Each matrix in an input Template is expanded into its own template.
  39 + *
  40 + * \see PipeTransform
  41 + */
  42 +class ExpandTransform : public UntrainableMetaTransform
  43 +{
  44 + Q_OBJECT
  45 +
  46 + virtual void project(const TemplateList &src, TemplateList &dst) const
  47 + {
  48 + dst = Expanded(src);
  49 + }
  50 +
  51 + virtual void project(const Template &src, Template &dst) const
  52 + {
  53 + dst = src;
  54 + qDebug("Called Expand project(Template,Template), nothing will happen");
  55 + }
  56 +};
  57 +
  58 +BR_REGISTER(Transform, ExpandTransform)
  59 +
  60 +} // namespace br
  61 +
  62 +#include "core/expand.moc"
... ...
openbr/plugins/core/first.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Removes all but the first matrix from the template.
  9 + * \see IdentityTransform DiscardTransform RestTransform RemoveTransform
  10 + * \author Josh Klontz \cite jklontz
  11 + */
  12 +class FirstTransform : public UntrainableMetaTransform
  13 +{
  14 + Q_OBJECT
  15 +
  16 + void project(const Template &src, Template &dst) const
  17 + {
  18 + // AggregateFrames will leave the Template empty
  19 + // if it hasn't filled up the buffer
  20 + // so we gotta anticipate an empty Template
  21 + if (src.empty()) return;
  22 + dst.file = src.file;
  23 + dst = src.m();
  24 + }
  25 +};
  26 +
  27 +BR_REGISTER(Transform, FirstTransform)
  28 +
  29 +} // namespace br
  30 +
  31 +#include "core/first.moc"
... ...
openbr/plugins/core/fork.cpp 0 → 100644
  1 +#include <QtConcurrent>
  2 +
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +
  5 +namespace br
  6 +{
  7 +
  8 +static void _train(Transform *transform, const QList<TemplateList> *data)
  9 +{
  10 + transform->train(*data);
  11 +}
  12 +
  13 +/*!
  14 + * \ingroup transforms
  15 + * \brief Transforms in parallel.
  16 + * \author Josh Klontz \cite jklontz
  17 + *
  18 + * The source br::Template is seperately given to each transform and the results are appended together.
  19 + *
  20 + * \see PipeTransform
  21 + */
  22 +class ForkTransform : public CompositeTransform
  23 +{
  24 + Q_OBJECT
  25 +
  26 + void train(const QList<TemplateList> &data)
  27 + {
  28 + if (!trainable) return;
  29 + QFutureSynchronizer<void> futures;
  30 + for (int i=0; i<transforms.size(); i++)
  31 + futures.addFuture(QtConcurrent::run(_train, transforms[i], &data));
  32 + futures.waitForFinished();
  33 + }
  34 +
  35 + // same as _project, but calls projectUpdate on sub-transforms
  36 + void projectupdate(const Template &src, Template &dst)
  37 + {
  38 + foreach (Transform *f, transforms) {
  39 + try {
  40 + Template res;
  41 + f->projectUpdate(src, res);
  42 + dst.merge(res);
  43 + } catch (...) {
  44 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  45 + dst = Template(src.file);
  46 + dst.file.fte = true;
  47 + break;
  48 + }
  49 + }
  50 + }
  51 +
  52 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  53 + {
  54 + dst.reserve(src.size());
  55 + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file));
  56 + foreach (Transform *f, transforms) {
  57 + TemplateList m;
  58 + f->projectUpdate(src, m);
  59 + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size.");
  60 + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]);
  61 + }
  62 + }
  63 +
  64 + // this is probably going to go bad, fork transform probably won't work well in a variable
  65 + // input/output scenario
  66 + virtual void finalize(TemplateList &output)
  67 + {
  68 + output.clear();
  69 + // For each transform,
  70 + for (int i = 0; i < transforms.size(); i++)
  71 + {
  72 + // Collect any final templates
  73 + TemplateList last_set;
  74 + transforms[i]->finalize(last_set);
  75 + if (last_set.empty())
  76 + continue;
  77 +
  78 + if (output.empty()) output = last_set;
  79 + else
  80 + {
  81 + // is the number of templates received from this transform consistent with the number
  82 + // received previously? If not we can't do anything coherent here.
  83 + if (last_set.size() != output.size())
  84 + qFatal("mismatched template list sizes in ForkTransform");
  85 + for (int j = 0; j < output.size(); j++) {
  86 + output[j].append(last_set[j]);
  87 + }
  88 + }
  89 + }
  90 + }
  91 +
  92 +protected:
  93 +
  94 + // Apply each transform to src, concatenate the results
  95 + void _project(const Template &src, Template &dst) const
  96 + {
  97 + foreach (const Transform *f, transforms) {
  98 + try {
  99 + dst.merge((*f)(src));
  100 + } catch (...) {
  101 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  102 + dst = Template(src.file);
  103 + dst.file.fte = true;
  104 + break;
  105 + }
  106 + }
  107 + }
  108 +
  109 + void _project(const TemplateList &src, TemplateList &dst) const
  110 + {
  111 + dst.reserve(src.size());
  112 + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file));
  113 + foreach (const Transform *f, transforms) {
  114 + TemplateList m;
  115 + f->project(src, m);
  116 + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size.");
  117 + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]);
  118 + }
  119 + }
  120 +
  121 +};
  122 +
  123 +BR_REGISTER(Transform, ForkTransform)
  124 +
  125 +} // namespace br
  126 +
  127 +#include "core/fork.moc"
... ...
openbr/plugins/core/fte.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/common.h>
  3 +
  4 +namespace br
  5 +{
  6 +
  7 +/*!
  8 + * \ingroup transforms
  9 + * \brief Flags images that failed to enroll based on the specified transform.
  10 + * \author Josh Klontz \cite jklontz
  11 + */
  12 +class FTETransform : public Transform
  13 +{
  14 + Q_OBJECT
  15 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  16 + Q_PROPERTY(float min READ get_min WRITE set_min RESET reset_min)
  17 + Q_PROPERTY(float max READ get_max WRITE set_max RESET reset_max)
  18 + BR_PROPERTY(br::Transform*, transform, NULL)
  19 + BR_PROPERTY(float, min, -std::numeric_limits<float>::max())
  20 + BR_PROPERTY(float, max, std::numeric_limits<float>::max())
  21 +
  22 + void train(const TemplateList &data)
  23 + {
  24 + transform->train(data);
  25 +
  26 + TemplateList projectedData;
  27 + transform->project(data, projectedData);
  28 +
  29 + QList<float> vals;
  30 + foreach (const Template &t, projectedData) {
  31 + if (!t.file.contains(transform->objectName()))
  32 + qFatal("Matrix metadata missing key %s.", qPrintable(transform->objectName()));
  33 + vals.append(t.file.get<float>(transform->objectName()));
  34 + }
  35 + float q1, q3;
  36 + Common::Median(vals, &q1, &q3);
  37 + min = q1 - 1.5 * (q3 - q1);
  38 + max = q3 + 1.5 * (q3 - q1);
  39 + }
  40 +
  41 + void project(const Template &src, Template &dst) const
  42 + {
  43 + Template projectedSrc;
  44 + transform->project(src, projectedSrc);
  45 + const float val = projectedSrc.file.get<float>(transform->objectName());
  46 +
  47 + dst = src;
  48 + dst.file.set(transform->objectName(), val);
  49 + dst.file.set("PossibleFTE", (val < min) || (val > max));
  50 + }
  51 +};
  52 +
  53 +BR_REGISTER(Transform, FTETransform)
  54 +
  55 +} // namespace br
  56 +
  57 +#include "core/fte.moc"
... ...
openbr/plugins/distance/gallerycompare.cpp renamed to openbr/plugins/core/gallerycompare.cpp
... ... @@ -61,4 +61,4 @@ BR_REGISTER(Transform, GalleryCompareTransform)
61 61  
62 62 } // namespace br
63 63  
64   -#include "gallerycompare.moc"
  64 +#include "core/gallerycompare.moc"
... ...
openbr/plugins/core/identity.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief A no-op transform.
  9 + * \see DiscardTransform FirstTransform RestTransform RemoveTransform
  10 + * \author Josh Klontz \cite jklontz
  11 + */
  12 +class IdentityTransform : public UntrainableMetaTransform
  13 +{
  14 + Q_OBJECT
  15 +
  16 + void project(const Template &src, Template &dst) const
  17 + {
  18 + dst = src;
  19 + }
  20 +};
  21 +
  22 +BR_REGISTER(Transform, IdentityTransform)
  23 +
  24 +} // namespace br
  25 +
  26 +#include "core/identity.moc"
... ...
openbr/plugins/core/independent.cpp
... ... @@ -210,4 +210,4 @@ BR_REGISTER(Transform, IndependentTransform)
210 210  
211 211 } // namespace br
212 212  
213   -#include "independent.moc"
  213 +#include "core/independent.moc"
... ...
openbr/plugins/jni.cpp renamed to openbr/plugins/core/jni.cpp
1 1 //Need to include location of jvm.dll (jdk version) and its parent directory in the environment variables
2 2  
3 3 #include <limits>
4   -#include "openbr_internal.h"
5   -#include "openbr/core/resource.h"
  4 +#include <openbr/plugins/openbr_internal.h>
  5 +#include <openbr/core/resource.h>
6 6 #include <jni.h>
7 7  
8 8 namespace br
... ...
openbr/plugins/likely.cpp renamed to openbr/plugins/core/likely.cpp
1   -#include <likely.h>
2   -#include <likely/opencv.hpp>
3   -
4   -#include "openbr/core/opencvutils.h"
5   -#include "openbr_internal.h"
  1 +#include <openbr/plugins/openbr_internal.h>
6 2  
7 3 namespace br
8 4 {
... ... @@ -57,68 +53,6 @@ public:
57 53  
58 54 BR_REGISTER(Transform, LikelyTransform)
59 55  
60   -/*!
61   - * \ingroup formats
62   - * \brief Likely matrix format
63   - *
64   - * www.liblikely.org
65   - * \author Josh Klontz \cite jklontz
66   - */
67   -class lmatFormat : public Format
68   -{
69   - Q_OBJECT
70   -
71   - Template read() const
72   - {
73   - const likely_const_mat m = likely_read(qPrintable(file.name), likely_file_guess);
74   - const Template result(likelyToOpenCVMat(m));
75   - likely_release_mat(m);
76   - return result;
77   - }
78   -
79   - void write(const Template &t) const
80   - {
81   - const likely_const_mat m = likelyFromOpenCVMat(t);
82   - likely_write(m, qPrintable(file.name));
83   - likely_release_mat(m);
84   - }
85   -};
86   -
87   -BR_REGISTER(Format, lmatFormat)
88   -
89   -/*!
90   - * \ingroup formats
91   - * \brief Likely matrix format
92   - *
93   - * www.liblikely.org
94   - * \author Josh Klontz \cite jklontz
95   - */
96   -class lmatGallery : public Gallery
97   -{
98   - Q_OBJECT
99   - QList<cv::Mat> mats;
100   -
101   - ~lmatGallery()
102   - {
103   - const likely_const_mat m = likelyFromOpenCVMat(OpenCVUtils::toMatByRow(mats));
104   - likely_write(m, qPrintable(file.name));
105   - likely_release_mat(m);
106   - }
107   -
108   - TemplateList readBlock(bool *done)
109   - {
110   - *done = true;
111   - qFatal("Not supported.");
112   - }
113   -
114   - void write(const Template &t)
115   - {
116   - mats.append(t);
117   - }
118   -};
119   -
120   -BR_REGISTER(Gallery, lmatGallery)
121   -
122 56 } // namespace br
123 57  
124   -#include "likely.moc"
  58 +#include "core/likely.moc"
... ...
openbr/plugins/core/loadstore.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/qtutils.h>
  3 +
  4 +namespace br
  5 +{
  6 +
  7 +/*!
  8 + * \ingroup transforms
  9 + * \brief Caches transform training.
  10 + * \author Josh Klontz \cite jklontz
  11 + */
  12 +class LoadStoreTransform : public MetaTransform
  13 +{
  14 + Q_OBJECT
  15 + Q_PROPERTY(QString transformString READ get_transformString WRITE set_transformString RESET reset_transformString STORED false)
  16 + Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false)
  17 + BR_PROPERTY(QString, transformString, "Identity")
  18 + BR_PROPERTY(QString, fileName, QString())
  19 +
  20 +public:
  21 + Transform *transform;
  22 +
  23 + LoadStoreTransform() : transform(NULL) {}
  24 +
  25 + QString description(bool expanded = false) const
  26 + {
  27 + if (expanded) {
  28 + QString res = transform->description(expanded);
  29 + return res;
  30 + }
  31 + return br::Object::description(expanded);
  32 + }
  33 +
  34 + Transform *simplify(bool &newTForm)
  35 + {
  36 + Transform *res = transform->simplify(newTForm);
  37 + return res;
  38 + }
  39 +
  40 + QList<Object *> getChildren() const
  41 + {
  42 + QList<Object *> rval;
  43 + rval.append(transform);
  44 + return rval;
  45 + }
  46 +private:
  47 +
  48 + void init()
  49 + {
  50 + if (transform != NULL) return;
  51 + if (fileName.isEmpty()) fileName = QRegExp("^[_a-zA-Z0-9]+$").exactMatch(transformString) ? transformString : QtUtils::shortTextHash(transformString);
  52 +
  53 + if (!tryLoad())
  54 + transform = make(transformString);
  55 + else
  56 + trainable = false;
  57 + }
  58 +
  59 + bool timeVarying() const
  60 + {
  61 + return transform->timeVarying();
  62 + }
  63 +
  64 + void train(const QList<TemplateList> &data)
  65 + {
  66 + if (QFileInfo(getFileName()).exists())
  67 + return;
  68 +
  69 + transform->train(data);
  70 +
  71 + qDebug("Storing %s", qPrintable(fileName));
  72 + QtUtils::BlockCompression compressedOut;
  73 + QFile fout(fileName);
  74 + QtUtils::touchDir(fout);
  75 + compressedOut.setBasis(&fout);
  76 +
  77 + QDataStream stream(&compressedOut);
  78 + QString desc = transform->description();
  79 +
  80 + if (!compressedOut.open(QFile::WriteOnly))
  81 + qFatal("Failed to open %s for writing.", qPrintable(file));
  82 +
  83 + stream << desc;
  84 + transform->store(stream);
  85 + compressedOut.close();
  86 + }
  87 +
  88 + void project(const Template &src, Template &dst) const
  89 + {
  90 + transform->project(src, dst);
  91 + }
  92 +
  93 + void project(const TemplateList &src, TemplateList &dst) const
  94 + {
  95 + transform->project(src, dst);
  96 + }
  97 +
  98 + void projectUpdate(const Template &src, Template &dst)
  99 + {
  100 + transform->projectUpdate(src, dst);
  101 + }
  102 +
  103 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  104 + {
  105 + transform->projectUpdate(src, dst);
  106 + }
  107 +
  108 + void finalize(TemplateList &output)
  109 + {
  110 + transform->finalize(output);
  111 + }
  112 +
  113 + QString getFileName() const
  114 + {
  115 + if (QFileInfo(fileName).exists()) return fileName;
  116 + const QString file = Globals->sdkPath + "/share/openbr/models/transforms/" + fileName;
  117 + return QFileInfo(file).exists() ? file : QString();
  118 + }
  119 +
  120 + bool tryLoad()
  121 + {
  122 + const QString file = getFileName();
  123 + if (file.isEmpty()) return false;
  124 +
  125 + qDebug("Loading %s", qPrintable(file));
  126 + QFile fin(file);
  127 + QtUtils::BlockCompression reader(&fin);
  128 + if (!reader.open(QIODevice::ReadOnly)) {
  129 + if (QFileInfo(file).exists()) qFatal("Unable to open %s for reading. Check file permissions.", qPrintable(file));
  130 + else qFatal("Unable to open %s for reading. File does not exist.", qPrintable(file));
  131 + }
  132 +
  133 + QDataStream stream(&reader);
  134 + stream >> transformString;
  135 +
  136 + transform = Transform::make(transformString);
  137 + transform->load(stream);
  138 +
  139 + return true;
  140 + }
  141 +};
  142 +
  143 +BR_REGISTER(Transform, LoadStoreTransform)
  144 +
  145 +} // namespace br
  146 +
  147 +#include "core/loadstore.moc"
... ...
openbr/plugins/core/pipe.cpp 0 → 100644
  1 +#include <QtConcurrent>
  2 +
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +
  5 +namespace br
  6 +{
  7 +
  8 +/*!
  9 + * \ingroup Transforms
  10 + * \brief Transforms in series.
  11 + * \author Josh Klontz \cite jklontz
  12 + *
  13 + * The source br::Template is given to the first transform and the resulting br::Template is passed to the next transform, etc.
  14 + *
  15 + * \see ExpandTransform
  16 + * \see ForkTransform
  17 + */
  18 +class PipeTransform : public CompositeTransform
  19 +{
  20 + Q_OBJECT
  21 +
  22 + void _projectPartial(TemplateList *srcdst, int startIndex, int stopIndex)
  23 + {
  24 + TemplateList ftes;
  25 + for (int i=startIndex; i<stopIndex; i++) {
  26 + TemplateList res;
  27 + transforms[i]->project(*srcdst, res);
  28 +
  29 + splitFTEs(res, ftes);
  30 + *srcdst = res;
  31 + }
  32 + }
  33 +
  34 + void train(const QList<TemplateList> &data)
  35 + {
  36 + if (!trainable) return;
  37 +
  38 + QList<TemplateList> dataLines(data);
  39 +
  40 + int i = 0;
  41 + while (i < transforms.size()) {
  42 + // Conditional statement covers likely case that first transform is untrainable
  43 + if (transforms[i]->trainable) {
  44 + qDebug() << "Training " << transforms[i]->description() << "\n...";
  45 + transforms[i]->train(dataLines);
  46 + }
  47 +
  48 + // if the transform is time varying, we can't project it in parallel
  49 + if (transforms[i]->timeVarying()) {
  50 + qDebug() << "Projecting " << transforms[i]->description() << "\n...";
  51 + for (int j=0; j < dataLines.size();j++) {
  52 + TemplateList junk;
  53 + splitFTEs(dataLines[j], junk);
  54 +
  55 + transforms[i]->projectUpdate(dataLines[j], dataLines[j]);
  56 + }
  57 +
  58 + // advance i since we already projected for this stage.
  59 + i++;
  60 +
  61 + // the next stage might be trainable, so continue to evaluate it.
  62 + continue;
  63 + }
  64 +
  65 + // We project through any subsequent untrainable transforms at once
  66 + // as a memory optimization in case any of these intermediate
  67 + // transforms allocate a lot of memory (like OpenTransform)
  68 + // then we don't want all the training templates to be processed
  69 + // by that transform at once if we can avoid it.
  70 + int nextTrainableTransform = i+1;
  71 + while ((nextTrainableTransform < transforms.size()) &&
  72 + !transforms[nextTrainableTransform]->trainable &&
  73 + !transforms[nextTrainableTransform]->timeVarying())
  74 + nextTrainableTransform++;
  75 +
  76 + // No more trainable transforms? Don't need any more projects then
  77 + if (nextTrainableTransform == transforms.size())
  78 + break;
  79 +
  80 + fprintf(stderr, "Projecting %s", qPrintable(transforms[i]->description()));
  81 + for (int j=i+1; j < nextTrainableTransform; j++)
  82 + fprintf(stderr,"+%s", qPrintable(transforms[j]->description()));
  83 + fprintf(stderr, "\n...\n");
  84 + fflush(stderr);
  85 +
  86 + QFutureSynchronizer<void> futures;
  87 + for (int j=0; j < dataLines.size(); j++)
  88 + futures.addFuture(QtConcurrent::run(this, &PipeTransform::_projectPartial, &dataLines[j], i, nextTrainableTransform));
  89 + futures.waitForFinished();
  90 +
  91 + i = nextTrainableTransform;
  92 + }
  93 + }
  94 +
  95 + void projectUpdate(const Template &src, Template &dst)
  96 + {
  97 + dst = src;
  98 + foreach (Transform *f, transforms) {
  99 + try {
  100 + f->projectUpdate(dst);
  101 + if (dst.file.fte)
  102 + break;
  103 + } catch (...) {
  104 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  105 + dst = Template(src.file);
  106 + dst.file.fte = true;
  107 + break;
  108 + }
  109 + }
  110 + }
  111 +
  112 + // For time varying transforms, parallel execution over individual templates
  113 + // won't work.
  114 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  115 + {
  116 + TemplateList ftes;
  117 + dst = src;
  118 + foreach (Transform *f, transforms) {
  119 + TemplateList res;
  120 + f->projectUpdate(dst, res);
  121 + splitFTEs(res, ftes);
  122 + dst = res;
  123 + }
  124 + dst.append(ftes);
  125 + }
  126 +
  127 + virtual void finalize(TemplateList &output)
  128 + {
  129 + output.clear();
  130 + // For each transform,
  131 + for (int i = 0; i < transforms.size(); i++)
  132 + {
  133 +
  134 + // Collect any final templates
  135 + TemplateList last_set;
  136 + transforms[i]->finalize(last_set);
  137 + if (last_set.empty())
  138 + continue;
  139 + // Push any templates received through the remaining transforms in the sequence
  140 + for (int j = (i+1); j < transforms.size();j++)
  141 + {
  142 + transforms[j]->projectUpdate(last_set);
  143 + }
  144 + // append the result to the output set
  145 + output.append(last_set);
  146 + }
  147 + }
  148 +
  149 + void init()
  150 + {
  151 + QList<Transform *> flattened;
  152 + for (int i=0;i < transforms.size(); i++)
  153 + {
  154 + PipeTransform *probe = dynamic_cast<PipeTransform *> (transforms[i]);
  155 + if (!probe) {
  156 + flattened.append(transforms[i]);
  157 + continue;
  158 + }
  159 + for (int j=0; j < probe->transforms.size(); j++)
  160 + flattened.append(probe->transforms[j]);
  161 + }
  162 + transforms = flattened;
  163 +
  164 + CompositeTransform::init();
  165 + }
  166 +
  167 +protected:
  168 + // Template list project -- process templates in parallel through Transform::project
  169 + // or if parallelism is disabled, handle them sequentially
  170 + void _project(const TemplateList &src, TemplateList &dst) const
  171 + {
  172 + TemplateList ftes;
  173 + dst = src;
  174 + foreach (const Transform *f, transforms) {
  175 + TemplateList res;
  176 + f->project(dst, res);
  177 + splitFTEs(res, ftes);
  178 + dst = res;
  179 + }
  180 + dst.append(ftes);
  181 + }
  182 +
  183 + // Single template const project, pass the template through each sub-transform, one after the other
  184 + virtual void _project(const Template &src, Template &dst) const
  185 + {
  186 + dst = src;
  187 + foreach (const Transform *f, transforms) {
  188 + try {
  189 + dst >> *f;
  190 + if (dst.file.fte)
  191 + break;
  192 + } catch (...) {
  193 + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
  194 + dst = Template(src.file);
  195 + dst.file.fte = true;
  196 + }
  197 + }
  198 + }
  199 +};
  200 +
  201 +BR_REGISTER(Transform, PipeTransform)
  202 +
  203 +} // namespace br
  204 +
  205 +#include "core/pipe.moc"
... ...
openbr/plugins/process.cpp renamed to openbr/plugins/core/processwrapper.cpp
... ... @@ -9,8 +9,8 @@
9 9 #include <QUuid>
10 10 #include <QWaitCondition>
11 11  
12   -#include "openbr_internal.h"
13   -#include "openbr/core/opencvutils.h"
  12 +#include <openbr/plugins/openbr_internal.h>
  13 +#include <openbr/core/opencvutils.h>
14 14  
15 15 using namespace cv;
16 16  
... ... @@ -658,4 +658,4 @@ BR_REGISTER(Transform, ProcessWrapperTransform)
658 658  
659 659 }
660 660  
661   -#include "process.moc"
  661 +#include "core/processwrapper.moc"
... ...
openbr/plugins/core/progresscounter.cpp 0 → 100644
  1 +#include <QElapsedTimer>
  2 +
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +#include <openbr/core/qtutils.h>
  5 +
  6 +namespace br
  7 +{
  8 +
  9 +class ProgressCounterTransform : public TimeVaryingTransform
  10 +{
  11 + Q_OBJECT
  12 +
  13 + Q_PROPERTY(qint64 totalProgress READ get_totalProgress WRITE set_totalProgress RESET reset_totalProgress STORED false)
  14 + BR_PROPERTY(qint64, totalProgress, 1)
  15 +
  16 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  17 + {
  18 + dst = src;
  19 +
  20 + qint64 elapsed = timer.elapsed();
  21 + int last_frame = -2;
  22 + if (!dst.empty()) {
  23 + for (int i=0;i < dst.size();i++) {
  24 + int frame = dst[i].file.get<int>("FrameNumber", -1);
  25 + if (frame == last_frame && frame != -1)
  26 + continue;
  27 +
  28 + // Use 1 as the starting index for progress output
  29 + Globals->currentProgress = dst[i].file.get<qint64>("progress",0)+1;
  30 + dst[i].file.remove("progress");
  31 + last_frame = frame;
  32 +
  33 + Globals->currentStep++;
  34 + }
  35 + }
  36 +
  37 + // updated every second
  38 + if (elapsed > 1000) {
  39 + Globals->printStatus();
  40 + timer.start();
  41 + }
  42 +
  43 + return;
  44 + }
  45 +
  46 + void train(const TemplateList& data)
  47 + {
  48 + (void) data;
  49 + }
  50 +
  51 + void finalize(TemplateList &data)
  52 + {
  53 + (void) data;
  54 + float p = br_progress();
  55 + qDebug("\r%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep);
  56 + timer.start();
  57 + Globals->startTime.start();
  58 + Globals->currentStep = 0;
  59 + Globals->currentProgress = 0;
  60 + Globals->totalSteps = totalProgress;
  61 + }
  62 +
  63 + void init()
  64 + {
  65 + timer.start();
  66 + Globals->startTime.start();
  67 + Globals->currentProgress = 0;
  68 + Globals->currentStep = 0;
  69 + Globals->totalSteps = totalProgress;
  70 + }
  71 +
  72 +public:
  73 + ProgressCounterTransform() : TimeVaryingTransform(false,false) {}
  74 + QElapsedTimer timer;
  75 +};
  76 +
  77 +BR_REGISTER(Transform, ProgressCounterTransform)
  78 +
  79 +} // namespace br
  80 +
  81 +#include "core/progresscounter.moc"
... ...
openbr/plugins/core/registrar.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup initializers
  8 + * \brief Register custom objects with Qt meta object system.
  9 + * \author Charles Otto \cite caotto
  10 + */
  11 +class Registrar : public Initializer
  12 +{
  13 + Q_OBJECT
  14 +
  15 + void initialize() const
  16 + {
  17 + qRegisterMetaType<br::Neighbors>();
  18 + }
  19 +};
  20 +
  21 +BR_REGISTER(Initializer, Registrar)
  22 +
  23 +} // namespace br
  24 +
  25 +#include "core/registrar.moc"
... ...
openbr/plugins/core/remove.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Removes the matrix from the template at the specified index.
  9 + * \author Josh Klontz \cite jklontz
  10 + * \see IdentityTransform DiscardTransform FirstTransform RestTransform
  11 + */
  12 +//! [example_transform]
  13 +class RemoveTransform : public UntrainableMetaTransform
  14 +{
  15 + Q_OBJECT
  16 + Q_PROPERTY(int index READ get_index WRITE set_index RESET reset_index STORED false)
  17 + BR_PROPERTY(int, index, 0)
  18 +
  19 + void project(const Template &src, Template &dst) const
  20 + {
  21 + dst = src;
  22 + dst.removeAt(index);
  23 + }
  24 +};
  25 +
  26 +BR_REGISTER(Transform, RemoveTransform)
  27 +//! [example_transform]
  28 +
  29 +} // namespace br
  30 +
  31 +#include "core/remove.moc"
... ...
openbr/plugins/core/rest.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Removes the first matrix from the template.
  9 + * \see IdentityTransform DiscardTransform FirstTransform RemoveTransform
  10 + * \author Josh Klontz \cite jklontz
  11 + */
  12 +class RestTransform : public UntrainableMetaTransform
  13 +{
  14 + Q_OBJECT
  15 +
  16 + void project(const Template &src, Template &dst) const
  17 + {
  18 + dst = src;
  19 + dst.removeFirst();
  20 + }
  21 +};
  22 +
  23 +BR_REGISTER(Transform, RestTransform)
  24 +
  25 +} // namespace br
  26 +
  27 +#include "core/rest.moc"
... ...
openbr/plugins/core/schrodinger.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup transforms
  8 + * \brief Generates two templates, one of which is passed through a transform and the other
  9 + * is not. No cats were harmed in the making of this transform.
  10 + * \author Scott Klum \cite sklum
  11 + */
  12 +class SchrodingerTransform : public MetaTransform
  13 +{
  14 + Q_OBJECT
  15 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform)
  16 + BR_PROPERTY(br::Transform*, transform, NULL)
  17 +
  18 +public:
  19 + void train(const TemplateList &data)
  20 + {
  21 + transform->train(data);
  22 + }
  23 +
  24 + void project(const TemplateList &src, TemplateList &dst) const
  25 + {
  26 + foreach(const Template &t, src) {
  27 + dst.append(t);
  28 + Template u;
  29 + transform->project(t,u);
  30 + dst.append(u);
  31 + }
  32 + }
  33 +
  34 + void project(const Template &src, Template &dst) const {
  35 + TemplateList temp;
  36 + project(TemplateList() << src, temp);
  37 + if (!temp.isEmpty()) dst = temp.first();
  38 + }
  39 +
  40 +};
  41 +BR_REGISTER(Transform, SchrodingerTransform)
  42 +
  43 +} // namespace br
  44 +
  45 +#include "core/schrodinger.moc"
... ...
openbr/plugins/core/singleton.cpp
... ... @@ -70,4 +70,4 @@ BR_REGISTER(Transform, SingletonTransform)
70 70  
71 71 } // namespace br
72 72  
73   -#include "singleton.moc"
  73 +#include "core/singleton.moc"
... ...
openbr/plugins/stream.cpp renamed to openbr/plugins/core/stream.cpp
... ... @@ -8,10 +8,11 @@
8 8 #include <QtConcurrent>
9 9 #include <opencv/highgui.h>
10 10 #include <opencv2/highgui/highgui.hpp>
11   -#include "openbr_internal.h"
12   -#include "openbr/core/common.h"
13   -#include "openbr/core/opencvutils.h"
14   -#include "openbr/core/qtutils.h"
  11 +
  12 +#include <openbr/plugins/openbr_internal.h>
  13 +#include <openbr/core/common.h>
  14 +#include <openbr/core/opencvutils.h>
  15 +#include <openbr/core/qtutils.h>
15 16  
16 17 using namespace cv;
17 18 using namespace std;
... ... @@ -1360,5 +1361,5 @@ BR_REGISTER(Transform, StreamTransform)
1360 1361  
1361 1362 } // namespace br
1362 1363  
1363   -#include "stream.moc"
  1364 +#include "core/stream.moc"
1364 1365  
... ...
openbr/plugins/distance/L2.cpp
... ... @@ -27,4 +27,4 @@ BR_REGISTER(Distance, L2Distance)
27 27  
28 28 } // namespace br
29 29  
30   -#include "L2.moc"
  30 +#include "distance/L2.moc"
... ...
openbr/plugins/distance/attribute.cpp
... ... @@ -31,4 +31,4 @@ BR_REGISTER(Distance, AttributeDistance)
31 31  
32 32 } // namespace br
33 33  
34   -#include "attribute.moc"
  34 +#include "distance/attribute.moc"
... ...
openbr/plugins/distance/bayesianquantization.cpp 0 → 100644
  1 +#include <QtConcurrent>
  2 +
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +#include <openbr/core/opencvutils.h>
  5 +
  6 +using namespace cv;
  7 +
  8 +namespace br
  9 +{
  10 +
  11 +/*!
  12 + * \ingroup distances
  13 + * \brief Bayesian quantization distance
  14 + * \author Josh Klontz \cite jklontz
  15 + */
  16 +class BayesianQuantizationDistance : public Distance
  17 +{
  18 + Q_OBJECT
  19 +
  20 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  21 + BR_PROPERTY(QString, inputVariable, "Label")
  22 +
  23 + QVector<float> loglikelihoods;
  24 +
  25 + static void computeLogLikelihood(const Mat &data, const QList<int> &labels, float *loglikelihood)
  26 + {
  27 + const QList<uchar> vals = OpenCVUtils::matrixToVector<uchar>(data);
  28 + if (vals.size() != labels.size())
  29 + qFatal("Logic error.");
  30 +
  31 + QVector<quint64> genuines(256, 0), impostors(256,0);
  32 + for (int i=0; i<vals.size(); i++)
  33 + for (int j=i+1; j<vals.size(); j++)
  34 + if (labels[i] == labels[j]) genuines[abs(vals[i]-vals[j])]++;
  35 + else impostors[abs(vals[i]-vals[j])]++;
  36 +
  37 + quint64 totalGenuines(0), totalImpostors(0);
  38 + for (int i=0; i<256; i++) {
  39 + totalGenuines += genuines[i];
  40 + totalImpostors += impostors[i];
  41 + }
  42 +
  43 + for (int i=0; i<256; i++)
  44 + loglikelihood[i] = log((float(genuines[i]+1)/totalGenuines)/(float(impostors[i]+1)/totalImpostors));
  45 + }
  46 +
  47 + void train(const TemplateList &src)
  48 + {
  49 + if ((src.first().size() > 1) || (src.first().m().type() != CV_8UC1))
  50 + qFatal("Expected sigle matrix templates of type CV_8UC1!");
  51 +
  52 + const Mat data = OpenCVUtils::toMat(src.data());
  53 + const QList<int> templateLabels = src.indexProperty(inputVariable);
  54 + loglikelihoods = QVector<float>(data.cols*256, 0);
  55 +
  56 + QFutureSynchronizer<void> futures;
  57 + for (int i=0; i<data.cols; i++)
  58 + futures.addFuture(QtConcurrent::run(&BayesianQuantizationDistance::computeLogLikelihood, data.col(i), templateLabels, &loglikelihoods.data()[i*256]));
  59 + futures.waitForFinished();
  60 + }
  61 +
  62 + float compare(const cv::Mat &a, const cv::Mat &b) const
  63 + {
  64 + const uchar *aData = a.data;
  65 + const uchar *bData = b.data;
  66 + const int size = a.rows * a.cols;
  67 + float likelihood = 0;
  68 + for (int i=0; i<size; i++)
  69 + likelihood += loglikelihoods[i*256+abs(aData[i]-bData[i])];
  70 + return likelihood;
  71 + }
  72 +
  73 + void store(QDataStream &stream) const
  74 + {
  75 + stream << loglikelihoods;
  76 + }
  77 +
  78 + void load(QDataStream &stream)
  79 + {
  80 + stream >> loglikelihoods;
  81 + }
  82 +};
  83 +
  84 +BR_REGISTER(Distance, BayesianQuantizationDistance)
  85 +
  86 +} // namespace br
  87 +
  88 +#include "distance/bayesianquantization.moc"
... ...
openbr/plugins/distance/byteL1.cpp
... ... @@ -23,4 +23,4 @@ BR_REGISTER(Distance, ByteL1Distance)
23 23  
24 24 } // namespace br
25 25  
26   -#include "byteL1.moc"
  26 +#include "distance/byteL1.moc"
... ...
openbr/plugins/distance/crossvalidate.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup distances
  8 + * \brief Cross validate a distance metric.
  9 + * \author Josh Klontz \cite jklontz
  10 + */
  11 +class CrossValidateDistance : public UntrainableDistance
  12 +{
  13 + Q_OBJECT
  14 +
  15 + float compare(const Template &a, const Template &b) const
  16 + {
  17 + static const QString key("Partition"); // More efficient to preallocate this
  18 + const int partitionA = a.file.get<int>(key, 0);
  19 + const int partitionB = b.file.get<int>(key, 0);
  20 + return (partitionA != partitionB) ? -std::numeric_limits<float>::max() : 0;
  21 + }
  22 +};
  23 +
  24 +BR_REGISTER(Distance, CrossValidateDistance)
  25 +
  26 +} // namespace br
  27 +
  28 +#include "distance/crossvalidate.moc"
... ...
openbr/plugins/distance/default.cpp
... ... @@ -28,4 +28,4 @@ BR_REGISTER(Distance, DefaultDistance)
28 28  
29 29 } // namespace br
30 30  
31   -#include "default.moc"
  31 +#include "distance/default.moc"
... ...
openbr/plugins/distance/dist.cpp
... ... @@ -101,4 +101,4 @@ BR_REGISTER(Distance, DistDistance)
101 101  
102 102 } // namespace br
103 103  
104   -#include "dist.moc"
  104 +#include "distance/dist.moc"
... ...
openbr/plugins/distance/filter.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup distances
  8 + * \brief Checks target metadata against filters.
  9 + * \author Josh Klontz \cite jklontz
  10 + */
  11 +class FilterDistance : public UntrainableDistance
  12 +{
  13 + Q_OBJECT
  14 +
  15 + float compare(const Template &a, const Template &b) const
  16 + {
  17 + (void) b; // Query template isn't checked
  18 + foreach (const QString &key, Globals->filters.keys()) {
  19 + bool keep = false;
  20 + const QString metadata = a.file.get<QString>(key, "");
  21 + if (Globals->filters[key].isEmpty()) continue;
  22 + if (metadata.isEmpty()) return -std::numeric_limits<float>::max();
  23 + foreach (const QString &value, Globals->filters[key]) {
  24 + if (metadata == value) {
  25 + keep = true;
  26 + break;
  27 + }
  28 + }
  29 + if (!keep) return -std::numeric_limits<float>::max();
  30 + }
  31 + return 0;
  32 + }
  33 +};
  34 +
  35 +BR_REGISTER(Distance, FilterDistance)
  36 +
  37 +} // namespace br
  38 +
  39 +#include "distance/filter.moc"
... ...
openbr/plugins/distance/fuse.cpp
... ... @@ -98,4 +98,4 @@ BR_REGISTER(Distance, FuseDistance)
98 98  
99 99 } // namespace br
100 100  
101   -#include "fuse.moc"
  101 +#include "distance/fuse.moc"
... ...
openbr/plugins/distance/halfbyteL1.cpp
... ... @@ -26,4 +26,4 @@ BR_REGISTER(Distance, HalfByteL1Distance)
26 26  
27 27 } // namespace br
28 28  
29   -#include "halfbyteL1.moc"
  29 +#include "distance/halfbyteL1.moc"
... ...
openbr/plugins/distance/heatmap.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup distances
  8 + * \brief 1v1 heat map comparison
  9 + * \author Scott Klum \cite sklum
  10 + */
  11 +class HeatMapDistance : public Distance
  12 +{
  13 + Q_OBJECT
  14 + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
  15 + Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false)
  16 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  17 + BR_PROPERTY(QString, description, "IdenticalDistance")
  18 + BR_PROPERTY(int, step, 1)
  19 + BR_PROPERTY(QString, inputVariable, "Label")
  20 +
  21 + QList<br::Distance*> distances;
  22 +
  23 + void train(const TemplateList &src)
  24 + {
  25 + QList<TemplateList> patches;
  26 +
  27 + // Split src into list of TemplateLists of corresponding patches across all Templates
  28 + for (int i=0; i<step; i++) {
  29 + TemplateList patchBuffer;
  30 + for (int j=0; j<src.size(); j++)
  31 + patchBuffer.append(Template(src[j].file, src[j][i]));
  32 + patches.append(patchBuffer);
  33 + patchBuffer.clear();
  34 + }
  35 +
  36 + while (distances.size() < patches.size())
  37 + distances.append(make(description));
  38 +
  39 + // Train on a distance for each patch
  40 + for (int i=0; i<distances.size(); i++)
  41 + distances[i]->train(patches[i]);
  42 + }
  43 +
  44 + float compare(const cv::Mat &target, const cv::Mat &query) const
  45 + {
  46 + (void) target;
  47 + (void) query;
  48 + qFatal("Heatmap Distance not compatible with Template to Template comparison.");
  49 +
  50 + return 0;
  51 + }
  52 +
  53 + void compare(const TemplateList &target, const TemplateList &query, Output *output) const
  54 + {
  55 + for (int i=0; i<target.size(); i++) {
  56 + if (target[i].size() != step || query[i].size() != step) qFatal("Heatmap step not equal to the number of patches.");
  57 + for (int j=0; j<step; j++)
  58 + output->setRelative(distances[j]->compare(target[i][j],query[i][j]), j, 0);
  59 + }
  60 + }
  61 +
  62 + void store(QDataStream &stream) const
  63 + {
  64 + stream << distances.size();
  65 + foreach (Distance *distance, distances)
  66 + distance->store(stream);
  67 + }
  68 +
  69 + void load(QDataStream &stream)
  70 + {
  71 + int numDistances;
  72 + stream >> numDistances;
  73 + while (distances.size() < numDistances)
  74 + distances.append(make(description));
  75 + foreach (Distance *distance, distances)
  76 + distance->load(stream);
  77 + }
  78 +};
  79 +
  80 +BR_REGISTER(Distance, HeatMapDistance)
  81 +
  82 +} // namespace br
  83 +
  84 +#include "distance/heatmap.moc"
... ...
openbr/plugins/distance/identical.cpp
... ... @@ -28,4 +28,4 @@ BR_REGISTER(Distance, IdenticalDistance)
28 28  
29 29 } // namespace br
30 30  
31   -#include "identical.moc"
  31 +#include "distance/identical.moc"
... ...
openbr/plugins/distance/keypointmatcher.cpp
... ... @@ -55,4 +55,4 @@ BR_REGISTER(Distance, KeyPointMatcherDistance)
55 55  
56 56 } // namespace br
57 57  
58   -#include "keypointmatcher.moc"
  58 +#include "distance/keypointmatcher.moc"
... ...
openbr/plugins/distance/l1.cpp
... ... @@ -27,4 +27,4 @@ BR_REGISTER(Distance, L1Distance)
27 27  
28 28 } // namespace br
29 29  
30   -#include "L1.moc"
  30 +#include "distance/L1.moc"
... ...
openbr/plugins/quality.cpp renamed to openbr/plugins/distance/matchprobability.cpp
1   -#include <QFutureSynchronizer>
2 1 #include <QtConcurrent>
3   -#include "openbr_internal.h"
4 2  
5   -#include "openbr/core/common.h"
6   -#include "openbr/core/opencvutils.h"
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +#include <openbr/core/common.h>
7 5  
8 6 namespace br
9 7 {
10 8  
11   -/*!
12   - * \ingroup transforms
13   - * \brief Impostor Uniqueness Measure \cite klare12
14   - * \author Josh Klontz \cite jklontz
15   - */
16   -class ImpostorUniquenessMeasureTransform : public Transform
17   -{
18   - Q_OBJECT
19   - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
20   - Q_PROPERTY(double mean READ get_mean WRITE set_mean RESET reset_mean)
21   - Q_PROPERTY(double stddev READ get_stddev WRITE set_stddev RESET reset_stddev)
22   - Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
23   - BR_PROPERTY(br::Distance*, distance, Distance::make("Dist(L2)", this))
24   - BR_PROPERTY(double, mean, 0)
25   - BR_PROPERTY(double, stddev, 1)
26   - BR_PROPERTY(QString, inputVariable, "Label")
27   -
28   - TemplateList impostors;
29   -
30   - float calculateIUM(const Template &probe, const TemplateList &gallery) const
31   - {
32   - const QString probeLabel = probe.file.get<QString>(inputVariable);
33   - TemplateList subset = gallery;
34   - for (int j=subset.size()-1; j>=0; j--)
35   - if (subset[j].file.get<QString>(inputVariable) == probeLabel)
36   - subset.removeAt(j);
37   -
38   - QList<float> scores = distance->compare(subset, probe);
39   - float min, max;
40   - Common::MinMax(scores, &min, &max);
41   - double mean = Common::Mean(scores);
42   - return (max-mean)/(max-min);
43   - }
44   -
45   - void train(const TemplateList &data)
46   - {
47   - distance->train(data);
48   - impostors = data;
49   -
50   - QList<float> iums; iums.reserve(impostors.size());
51   - for (int i=0; i<data.size(); i++)
52   - iums.append(calculateIUM(impostors[i], impostors));
53   -
54   - Common::MeanStdDev(iums, &mean, &stddev);
55   - }
56   -
57   - void project(const Template &src, Template &dst) const
58   - {
59   - dst = src;
60   - float ium = calculateIUM(src, impostors);
61   - dst.file.set("Impostor_Uniqueness_Measure", ium);
62   - dst.file.set("Impostor_Uniqueness_Measure_Bin", ium < mean-stddev ? 0 : (ium < mean+stddev ? 1 : 2));
63   - }
64   -
65   - void store(QDataStream &stream) const
66   - {
67   - distance->store(stream);
68   - stream << mean << stddev << impostors;
69   - }
70   -
71   - void load(QDataStream &stream)
72   - {
73   - distance->load(stream);
74   - stream >> mean >> stddev >> impostors;
75   - }
76   -};
77   -
78   -BR_REGISTER(Transform, ImpostorUniquenessMeasureTransform)
79   -
80   -
81 9 float KDEPointer(const QList<float> *scores, double x, double h)
82 10 {
83 11 return Common::KernelDensityEstimation(*scores, x, h);
... ... @@ -119,7 +47,7 @@ struct KDE
119 47 if (gaussian) return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((score-mean)/stddev, 2));
120 48 if (bins.empty())
121 49 return -std::numeric_limits<float>::max();
122   -
  50 +
123 51 if (score <= min) return bins.first();
124 52 if (score >= max) return bins.last();
125 53 const float x = (score-min)/(max-min)*bins.size();
... ... @@ -186,7 +114,7 @@ class MatchProbabilityDistance : public Distance
186 114 const QList<int> labels = src.indexProperty(inputVariable);
187 115 QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size())));
188 116 distance->compare(src, src, matrixOutput.data());
189   -
  117 +
190 118 QList<float> genuineScores, impostorScores;
191 119 genuineScores.reserve(labels.size());
192 120 impostorScores.reserve(labels.size()*labels.size());
... ... @@ -199,7 +127,7 @@ class MatchProbabilityDistance : public Distance
199 127 else impostorScores.append(score);
200 128 }
201 129 }
202   -
  130 +
203 131 mp = MP(genuineScores, impostorScores, !gaussian);
204 132 }
205 133  
... ... @@ -246,204 +174,6 @@ protected:
246 174  
247 175 BR_REGISTER(Distance, MatchProbabilityDistance)
248 176  
249   -class ZScoreDistance : public Distance
250   -{
251   - Q_OBJECT
252   - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
253   - Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false)
254   - BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
255   - BR_PROPERTY(bool, crossModality, false)
256   -
257   - float min, max;
258   - double mean, stddev;
259   -
260   - void train(const TemplateList &src)
261   - {
262   - distance->train(src);
263   -
264   - QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size())));
265   - distance->compare(src, src, matrixOutput.data());
266   -
267   - QList<float> scores;
268   - scores.reserve(src.size()*src.size());
269   - for (int i=0; i<src.size(); i++) {
270   - for (int j=0; j<i; j++) {
271   - const float score = matrixOutput.data()->data.at<float>(i, j);
272   - if (score == -std::numeric_limits<float>::max()) continue;
273   - if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue;
274   - scores.append(score);
275   - }
276   - }
277   -
278   - Common::MinMax(scores, &min, &max);
279   - Common::MeanStdDev(scores, &mean, &stddev);
280   -
281   - if (stddev == 0) qFatal("Stddev is 0.");
282   - }
283   -
284   - float compare(const Template &target, const Template &query) const
285   - {
286   - float score = distance->compare(target,query);
287   - if (score == -std::numeric_limits<float>::max()) score = (min - mean) / stddev;
288   - else if (score == std::numeric_limits<float>::max()) score = (max - mean) / stddev;
289   - else score = (score - mean) / stddev;
290   - return score;
291   - }
292   -
293   - void store(QDataStream &stream) const
294   - {
295   - distance->store(stream);
296   - stream << min << max << mean << stddev;
297   - }
298   -
299   - void load(QDataStream &stream)
300   - {
301   - distance->load(stream);
302   - stream >> min >> max >> mean >> stddev;
303   - }
304   -};
305   -
306   -BR_REGISTER(Distance, ZScoreDistance)
307   -
308   -/*!
309   - * \ingroup distances
310   - * \brief 1v1 heat map comparison
311   - * \author Scott Klum \cite sklum
312   - */
313   -class HeatMapDistance : public Distance
314   -{
315   - Q_OBJECT
316   - Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false)
317   - Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false)
318   - Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
319   - BR_PROPERTY(QString, description, "IdenticalDistance")
320   - BR_PROPERTY(int, step, 1)
321   - BR_PROPERTY(QString, inputVariable, "Label")
322   -
323   - QList<br::Distance*> distances;
324   -
325   - void train(const TemplateList &src)
326   - {
327   - QList<TemplateList> patches;
328   -
329   - // Split src into list of TemplateLists of corresponding patches across all Templates
330   - for (int i=0; i<step; i++) {
331   - TemplateList patchBuffer;
332   - for (int j=0; j<src.size(); j++)
333   - patchBuffer.append(Template(src[j].file, src[j][i]));
334   - patches.append(patchBuffer);
335   - patchBuffer.clear();
336   - }
337   -
338   - while (distances.size() < patches.size())
339   - distances.append(make(description));
340   -
341   - // Train on a distance for each patch
342   - for (int i=0; i<distances.size(); i++)
343   - distances[i]->train(patches[i]);
344   - }
345   -
346   - float compare(const cv::Mat &target, const cv::Mat &query) const
347   - {
348   - (void) target;
349   - (void) query;
350   - qFatal("Heatmap Distance not compatible with Template to Template comparison.");
351   -
352   - return 0;
353   - }
354   -
355   - void compare(const TemplateList &target, const TemplateList &query, Output *output) const
356   - {
357   - for (int i=0; i<target.size(); i++) {
358   - if (target[i].size() != step || query[i].size() != step) qFatal("Heatmap step not equal to the number of patches.");
359   - for (int j=0; j<step; j++)
360   - output->setRelative(distances[j]->compare(target[i][j],query[i][j]), j, 0);
361   - }
362   - }
363   -
364   - void store(QDataStream &stream) const
365   - {
366   - stream << distances.size();
367   - foreach (Distance *distance, distances)
368   - distance->store(stream);
369   - }
370   -
371   - void load(QDataStream &stream)
372   - {
373   - int numDistances;
374   - stream >> numDistances;
375   - while (distances.size() < numDistances)
376   - distances.append(make(description));
377   - foreach (Distance *distance, distances)
378   - distance->load(stream);
379   - }
380   -};
381   -
382   -BR_REGISTER(Distance, HeatMapDistance)
383   -
384   -/*!
385   - * \ingroup distances
386   - * \brief Linear normalizes of a distance so the mean impostor score is 0 and the mean genuine score is 1.
387   - * \author Josh Klontz \cite jklontz
388   - */
389   -class UnitDistance : public Distance
390   -{
391   - Q_OBJECT
392   - Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance)
393   - Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a)
394   - Q_PROPERTY(float b READ get_b WRITE set_b RESET reset_b)
395   - Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
396   - BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
397   - BR_PROPERTY(float, a, 1)
398   - BR_PROPERTY(float, b, 0)
399   - BR_PROPERTY(QString, inputVariable, "Label")
400   -
401   - void train(const TemplateList &templates)
402   - {
403   - const TemplateList samples = templates.mid(0, 2000);
404   - const QList<int> sampleLabels = samples.indexProperty(inputVariable);
405   - QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(samples.size()), FileList(samples.size())));
406   - Distance::compare(samples, samples, matrixOutput.data());
407   -
408   - double genuineAccumulator, impostorAccumulator;
409   - int genuineCount, impostorCount;
410   - genuineAccumulator = impostorAccumulator = genuineCount = impostorCount = 0;
411   -
412   - for (int i=0; i<samples.size(); i++) {
413   - for (int j=0; j<i; j++) {
414   - const float val = matrixOutput.data()->data.at<float>(i, j);
415   - if (sampleLabels[i] == sampleLabels[j]) {
416   - genuineAccumulator += val;
417   - genuineCount++;
418   - } else {
419   - impostorAccumulator += val;
420   - impostorCount++;
421   - }
422   - }
423   - }
424   -
425   - if (genuineCount == 0) { qWarning("No genuine matches."); return; }
426   - if (impostorCount == 0) { qWarning("No impostor matches."); return; }
427   -
428   - double genuineMean = genuineAccumulator / genuineCount;
429   - double impostorMean = impostorAccumulator / impostorCount;
430   -
431   - if (genuineMean == impostorMean) { qWarning("Genuines and impostors are indistinguishable."); return; }
432   -
433   - a = 1.0/(genuineMean-impostorMean);
434   - b = impostorMean;
435   -
436   - qDebug("a = %f, b = %f", a, b);
437   - }
438   -
439   - float compare(const Template &target, const Template &query) const
440   - {
441   - return a * (distance->compare(target, query) - b);
442   - }
443   -};
444   -
445   -BR_REGISTER(Distance, UnitDistance)
446   -
447 177 } // namespace br
448 178  
449   -#include "quality.moc"
  179 +#include "distance/matchprobability.moc"
... ...
openbr/plugins/distance/metadata.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/qtutils.h>
  3 +
  4 +namespace br
  5 +{
  6 +
  7 +/*!
  8 + * \ingroup distances
  9 + * \brief Checks target metadata against query metadata.
  10 + * \author Scott Klum \cite sklum
  11 + */
  12 +class MetadataDistance : public UntrainableDistance
  13 +{
  14 + Q_OBJECT
  15 +
  16 + Q_PROPERTY(QStringList filters READ get_filters WRITE set_filters RESET reset_filters STORED false)
  17 + BR_PROPERTY(QStringList, filters, QStringList())
  18 +
  19 + float compare(const Template &a, const Template &b) const
  20 + {
  21 + foreach (const QString &key, filters) {
  22 + QString aValue = a.file.get<QString>(key, QString());
  23 + QString bValue = b.file.get<QString>(key, QString());
  24 +
  25 + // The query value may be a range. Let's check.
  26 + if (bValue.isEmpty()) bValue = QtUtils::toString(b.file.get<QPointF>(key, QPointF()));
  27 +
  28 + if (aValue.isEmpty() || bValue.isEmpty()) continue;
  29 +
  30 + bool keep = false;
  31 + bool ok;
  32 +
  33 + QPointF range = QtUtils::toPoint(bValue,&ok);
  34 +
  35 + if (ok) /* Range */ {
  36 + int value = range.x();
  37 + int upperBound = range.y();
  38 +
  39 + while (value <= upperBound) {
  40 + if (aValue == QString::number(value)) {
  41 + keep = true;
  42 + break;
  43 + }
  44 + value++;
  45 + }
  46 + }
  47 + else if (aValue == bValue) keep = true;
  48 +
  49 + if (!keep) return -std::numeric_limits<float>::max();
  50 + }
  51 + return 0;
  52 + }
  53 +};
  54 +
  55 +
  56 +BR_REGISTER(Distance, MetadataDistance)
  57 +
  58 +} // namespace br
  59 +
  60 +#include "distance/metadata.moc"
... ...
openbr/plugins/distance/neglogplusone.cpp
... ... @@ -39,4 +39,4 @@ BR_REGISTER(Distance, NegativeLogPlusOneDistance)
39 39  
40 40 } // namespace br
41 41  
42   -#include "neglogplusone.moc"
  42 +#include "distance/neglogplusone.moc"
... ...
openbr/plugins/distance/online.cpp
... ... @@ -32,4 +32,4 @@ BR_REGISTER(Distance, OnlineDistance)
32 32  
33 33 } // namespace br
34 34  
35   -#include "online.moc"
  35 +#include "distance/online.moc"
... ...
openbr/plugins/distance/pipe.cpp
... ... @@ -44,4 +44,4 @@ BR_REGISTER(Distance, PipeDistance)
44 44  
45 45 } // namespace br
46 46  
47   -#include "pipe.moc"
  47 +#include "distance/pipe.moc"
... ...
openbr/plugins/distance/reject.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup distances
  8 + * \brief Sets distance to -FLOAT_MAX if a target template has/doesn't have a key.
  9 + * \author Scott Klum \cite sklum
  10 + */
  11 +class RejectDistance : public UntrainableDistance
  12 +{
  13 + Q_OBJECT
  14 +
  15 + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
  16 + BR_PROPERTY(QStringList, keys, QStringList())
  17 + Q_PROPERTY(bool rejectIfContains READ get_rejectIfContains WRITE set_rejectIfContains RESET reset_rejectIfContains STORED false)
  18 + BR_PROPERTY(bool, rejectIfContains, false)
  19 +
  20 + float compare(const Template &a, const Template &b) const
  21 + {
  22 + // We don't look at the query
  23 + (void) b;
  24 +
  25 + foreach (const QString &key, keys)
  26 + if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key)))
  27 + return -std::numeric_limits<float>::max();
  28 +
  29 + return 0;
  30 + }
  31 +};
  32 +
  33 +
  34 +BR_REGISTER(Distance, RejectDistance)
  35 +
  36 +} // namespace br
  37 +
  38 +#include "distance/reject.moc"
... ...
openbr/plugins/distance/sum.cpp
... ... @@ -43,4 +43,4 @@ BR_REGISTER(Distance, SumDistance)
43 43  
44 44 } // namespace br
45 45  
46   -#include "sum.moc"
  46 +#include "distance/sum.moc"
... ...
openbr/plugins/distance/turk.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/opencvutils.h>
  3 +
  4 +namespace br
  5 +{
  6 +
  7 +/*!
  8 + * \ingroup distances
  9 + * \brief Unmaps Turk HITs to be compared against query mats
  10 + * \author Scott Klum \cite sklum
  11 + */
  12 +class TurkDistance : public UntrainableDistance
  13 +{
  14 + Q_OBJECT
  15 + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key)
  16 + Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false)
  17 + BR_PROPERTY(QString, key, QString())
  18 + BR_PROPERTY(QStringList, values, QStringList())
  19 +
  20 + bool targetHuman;
  21 + bool queryMachine;
  22 +
  23 + void init()
  24 + {
  25 + targetHuman = Globals->property("TurkTargetHuman").toBool();
  26 + queryMachine = Globals->property("TurkQueryMachine").toBool();
  27 + }
  28 +
  29 + cv::Mat getValues(const Template &t) const
  30 + {
  31 + QList<float> result;
  32 + foreach (const QString &value, values)
  33 + result.append(t.file.get<float>(key + "_" + value));
  34 + return OpenCVUtils::toMat(result, 1);
  35 + }
  36 +
  37 + float compare(const Template &target, const Template &query) const
  38 + {
  39 + const cv::Mat a = targetHuman ? getValues(target) : target.m();
  40 + const cv::Mat b = queryMachine ? query.m() : getValues(query);
  41 + return -norm(a, b, cv::NORM_L1);
  42 + }
  43 +};
  44 +
  45 +BR_REGISTER(Distance, TurkDistance)
  46 +
  47 +} // namespace br
  48 +
  49 +#include "distance/turk.moc"
... ...
openbr/plugins/distance/unit.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup distances
  8 + * \brief Linear normalizes of a distance so the mean impostor score is 0 and the mean genuine score is 1.
  9 + * \author Josh Klontz \cite jklontz
  10 + */
  11 +class UnitDistance : public Distance
  12 +{
  13 + Q_OBJECT
  14 + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance)
  15 + Q_PROPERTY(float a READ get_a WRITE set_a RESET reset_a)
  16 + Q_PROPERTY(float b READ get_b WRITE set_b RESET reset_b)
  17 + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false)
  18 + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
  19 + BR_PROPERTY(float, a, 1)
  20 + BR_PROPERTY(float, b, 0)
  21 + BR_PROPERTY(QString, inputVariable, "Label")
  22 +
  23 + void train(const TemplateList &templates)
  24 + {
  25 + const TemplateList samples = templates.mid(0, 2000);
  26 + const QList<int> sampleLabels = samples.indexProperty(inputVariable);
  27 + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(samples.size()), FileList(samples.size())));
  28 + Distance::compare(samples, samples, matrixOutput.data());
  29 +
  30 + double genuineAccumulator, impostorAccumulator;
  31 + int genuineCount, impostorCount;
  32 + genuineAccumulator = impostorAccumulator = genuineCount = impostorCount = 0;
  33 +
  34 + for (int i=0; i<samples.size(); i++) {
  35 + for (int j=0; j<i; j++) {
  36 + const float val = matrixOutput.data()->data.at<float>(i, j);
  37 + if (sampleLabels[i] == sampleLabels[j]) {
  38 + genuineAccumulator += val;
  39 + genuineCount++;
  40 + } else {
  41 + impostorAccumulator += val;
  42 + impostorCount++;
  43 + }
  44 + }
  45 + }
  46 +
  47 + if (genuineCount == 0) { qWarning("No genuine matches."); return; }
  48 + if (impostorCount == 0) { qWarning("No impostor matches."); return; }
  49 +
  50 + double genuineMean = genuineAccumulator / genuineCount;
  51 + double impostorMean = impostorAccumulator / impostorCount;
  52 +
  53 + if (genuineMean == impostorMean) { qWarning("Genuines and impostors are indistinguishable."); return; }
  54 +
  55 + a = 1.0/(genuineMean-impostorMean);
  56 + b = impostorMean;
  57 +
  58 + qDebug("a = %f, b = %f", a, b);
  59 + }
  60 +
  61 + float compare(const Template &target, const Template &query) const
  62 + {
  63 + return a * (distance->compare(target, query) - b);
  64 + }
  65 +};
  66 +
  67 +BR_REGISTER(Distance, UnitDistance)
  68 +
  69 +} // namespace br
  70 +
  71 +#include "distance/unit.moc"
... ...
openbr/plugins/distance/zscore.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/common.h>
  3 +
  4 +namespace br
  5 +{
  6 +
  7 +class ZScoreDistance : public Distance
  8 +{
  9 + Q_OBJECT
  10 + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  11 + Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false)
  12 + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
  13 + BR_PROPERTY(bool, crossModality, false)
  14 +
  15 + float min, max;
  16 + double mean, stddev;
  17 +
  18 + void train(const TemplateList &src)
  19 + {
  20 + distance->train(src);
  21 +
  22 + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size())));
  23 + distance->compare(src, src, matrixOutput.data());
  24 +
  25 + QList<float> scores;
  26 + scores.reserve(src.size()*src.size());
  27 + for (int i=0; i<src.size(); i++) {
  28 + for (int j=0; j<i; j++) {
  29 + const float score = matrixOutput.data()->data.at<float>(i, j);
  30 + if (score == -std::numeric_limits<float>::max()) continue;
  31 + if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue;
  32 + scores.append(score);
  33 + }
  34 + }
  35 +
  36 + Common::MinMax(scores, &min, &max);
  37 + Common::MeanStdDev(scores, &mean, &stddev);
  38 +
  39 + if (stddev == 0) qFatal("Stddev is 0.");
  40 + }
  41 +
  42 + float compare(const Template &target, const Template &query) const
  43 + {
  44 + float score = distance->compare(target,query);
  45 + if (score == -std::numeric_limits<float>::max()) score = (min - mean) / stddev;
  46 + else if (score == std::numeric_limits<float>::max()) score = (max - mean) / stddev;
  47 + else score = (score - mean) / stddev;
  48 + return score;
  49 + }
  50 +
  51 + void store(QDataStream &stream) const
  52 + {
  53 + distance->store(stream);
  54 + stream << min << max << mean << stddev;
  55 + }
  56 +
  57 + void load(QDataStream &stream)
  58 + {
  59 + distance->load(stream);
  60 + stream >> min >> max >> mean >> stddev;
  61 + }
  62 +};
  63 +
  64 +BR_REGISTER(Distance, ZScoreDistance)
  65 +
  66 +} // namespace br
  67 +
  68 +#include "distance/zscore.moc"
... ...
openbr/plugins/format/binary.cpp
... ... @@ -67,4 +67,4 @@ BR_REGISTER(Format, binaryFormat)
67 67  
68 68 } // namespace br
69 69  
70   -#include "binary.moc"
  70 +#include "format/binary.moc"
... ...
openbr/plugins/format/csv.cpp
... ... @@ -70,4 +70,4 @@ BR_REGISTER(Format, csvFormat)
70 70  
71 71 } // namespace br
72 72  
73   -#include "csv.moc"
  73 +#include "format/csv.moc"
... ...
openbr/plugins/format/ebts.cpp
... ... @@ -196,4 +196,4 @@ BR_REGISTER(Format, ebtsFormat)
196 196  
197 197 } // namespace br
198 198  
199   -#include "ebts.moc"
  199 +#include "format/ebts.moc"
... ...
openbr/plugins/format/lffs.cpp
... ... @@ -33,4 +33,4 @@ BR_REGISTER(Format, lffsFormat)
33 33  
34 34 } // namespace br
35 35  
36   -#include "lffs.moc"
  36 +#include "format/lffs.moc"
... ...
openbr/plugins/format/lmat.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +
  3 +namespace br
  4 +{
  5 +
  6 +/*!
  7 + * \ingroup formats
  8 + * \brief Likely matrix format
  9 + *
  10 + * www.liblikely.org
  11 + * \author Josh Klontz \cite jklontz
  12 + */
  13 +class lmatFormat : public Format
  14 +{
  15 + Q_OBJECT
  16 +
  17 + Template read() const
  18 + {
  19 + const likely_const_mat m = likely_read(qPrintable(file.name), likely_file_guess);
  20 + const Template result(likelyToOpenCVMat(m));
  21 + likely_release_mat(m);
  22 + return result;
  23 + }
  24 +
  25 + void write(const Template &t) const
  26 + {
  27 + const likely_const_mat m = likelyFromOpenCVMat(t);
  28 + likely_write(m, qPrintable(file.name));
  29 + likely_release_mat(m);
  30 + }
  31 +};
  32 +
  33 +BR_REGISTER(Format, lmatFormat)
  34 +
  35 +} // namespace br
  36 +
  37 +#include "format/lmat.moc"
... ...
openbr/plugins/format/mat.cpp
... ... @@ -224,4 +224,4 @@ BR_REGISTER(Format, matFormat)
224 224  
225 225 } // namespace br
226 226  
227   -#include "mat.moc"
  227 +#include "format/mat.moc"
... ...
openbr/plugins/format/mtx.cpp
... ... @@ -44,4 +44,4 @@ BR_REGISTER(Format, maskFormat)
44 44  
45 45 } // namespace br
46 46  
47   -#include "mtx.moc"
  47 +#include "format/mtx.moc"
... ...
openbr/plugins/format/null.cpp
... ... @@ -27,4 +27,4 @@ BR_REGISTER(Format, nullFormat)
27 27  
28 28 } // namespace br
29 29  
30   -#include "null.moc"
  30 +#include "format/null.moc"
... ...
openbr/plugins/format/post.cpp 0 → 100644
  1 +#include <QTcpSocket>
  2 +#include <opencv2/highgui/highgui.hpp>
  3 +
  4 +#include <openbr/plugins/openbr_internal.h>
  5 +#include <http_parser.h>
  6 +
  7 +using namespace cv;
  8 +
  9 +namespace br
  10 +{
  11 +
  12 +/*!
  13 + * \ingroup formats
  14 + * \brief Handle POST requests
  15 + * \author Josh Klontz \cite jklontz
  16 + */
  17 +class postFormat : public Format
  18 +{
  19 + Q_OBJECT
  20 +
  21 + Template read() const
  22 + {
  23 + Template t(file);
  24 +
  25 + // Read from socket
  26 + QTcpSocket *socket = new QTcpSocket();
  27 + socket->setSocketDescriptor(file.get<qintptr>("socketDescriptor"));
  28 + socket->write("HTTP/1.1 200 OK\r\n"
  29 + "Content-Type: text/html; charset=UTF-8\r\n\r\n"
  30 + "Hello World!\r\n");
  31 + socket->waitForBytesWritten();
  32 + socket->waitForReadyRead();
  33 + QByteArray data = socket->readAll();
  34 + socket->close();
  35 + delete socket;
  36 +
  37 + qDebug() << data;
  38 +
  39 + // Parse data
  40 + http_parser_settings settings;
  41 + settings.on_body = bodyCallback;
  42 + settings.on_headers_complete = NULL;
  43 + settings.on_header_field = NULL;
  44 + settings.on_header_value = NULL;
  45 + settings.on_message_begin = NULL;
  46 + settings.on_message_complete = NULL;
  47 + settings.on_status_complete = NULL;
  48 + settings.on_url = NULL;
  49 +
  50 + {
  51 + QByteArray body;
  52 + http_parser parser;
  53 + http_parser_init(&parser, HTTP_REQUEST);
  54 + parser.data = &body;
  55 + http_parser_execute(&parser, &settings, data.data(), data.size());
  56 + data = body;
  57 + }
  58 +
  59 + data.prepend("HTTP/1.1 200 OK");
  60 + QByteArray body;
  61 + { // Image data is two layers deep
  62 + http_parser parser;
  63 + http_parser_init(&parser, HTTP_BOTH);
  64 + parser.data = &body;
  65 + http_parser_execute(&parser, &settings, data.data(), data.size());
  66 + }
  67 +
  68 + t.append(imdecode(Mat(1, body.size(), CV_8UC1, body.data()), 1));
  69 + return t;
  70 + }
  71 +
  72 + void write(const Template &t) const
  73 + {
  74 + (void) t;
  75 + qFatal("Not supported!");
  76 + }
  77 +
  78 + static int bodyCallback(http_parser *parser, const char *at, size_t length)
  79 + {
  80 + QByteArray *byteArray = (QByteArray*)parser->data;
  81 + *byteArray = QByteArray(at, length);
  82 + return 0;
  83 + }
  84 +};
  85 +
  86 +BR_REGISTER(Format, postFormat)
  87 +
  88 +} // namespace br
  89 +
  90 +#include "format/post.moc"
... ...
openbr/plugins/format/raw.cpp
... ... @@ -67,4 +67,4 @@ BR_REGISTER(Format, rawFormat)
67 67  
68 68 } // namespace br
69 69  
70   -#include "raw.moc"
  70 +#include "format/raw.moc"
... ...
openbr/plugins/format/scores.cpp
... ... @@ -62,4 +62,4 @@ BR_REGISTER(Format, scoresFormat)
62 62  
63 63 } // namespace br
64 64  
65   -#include "scores.moc"
  65 +#include "format/scores.moc"
... ...
openbr/plugins/format/url.cpp 0 → 100644
  1 +#include <QtNetwork>
  2 +#include <opencv2/highgui/highgui.hpp>
  3 +
  4 +#include <openbr/plugins/openbr_internal.h>
  5 +
  6 +using namespace cv;
  7 +
  8 +namespace br
  9 +{
  10 +
  11 +/*!
  12 + * \ingroup formats
  13 + * \brief Reads image files from the web.
  14 + * \author Josh Klontz \cite jklontz
  15 + */
  16 +class urlFormat : public Format
  17 +{
  18 + Q_OBJECT
  19 +
  20 + Template read() const
  21 + {
  22 + Template t;
  23 +
  24 + QNetworkAccessManager networkAccessManager;
  25 + QNetworkRequest request(QString(file.name).remove(".url"));
  26 + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
  27 + QNetworkReply *reply = networkAccessManager.get(request);
  28 +
  29 + while (!reply->isFinished()) QCoreApplication::processEvents();
  30 + if (reply->error()) qWarning("%s (%s)", qPrintable(reply->errorString()), qPrintable(QString::number(reply->error())));
  31 +
  32 + QByteArray data = reply->readAll();
  33 + delete reply;
  34 +
  35 + Mat m = imdecode(Mat(1, data.size(), CV_8UC1, data.data()), 1);
  36 + if (m.data) t.append(m);
  37 +
  38 + return t;
  39 + }
  40 +
  41 + void write(const Template &t) const
  42 + {
  43 + (void) t;
  44 + qFatal("Not supported.");
  45 + }
  46 +};
  47 +
  48 +BR_REGISTER(Format, urlFormat)
  49 +
  50 +} // namespace br
  51 +
  52 +#include "format/url.moc"
... ...
openbr/plugins/format/video.cpp
... ... @@ -144,4 +144,4 @@ BR_REGISTER(Format, DefaultFormat)
144 144  
145 145 } // namespace br
146 146  
147   -#include "video.moc"
  147 +#include "format/video.moc"
... ...
openbr/plugins/format/xml.cpp
... ... @@ -99,4 +99,4 @@ BR_REGISTER(Format, xmlFormat)
99 99  
100 100 } // namespace br
101 101  
102   -#include "xml.moc"
  102 +#include "format/xml.moc"
... ...
openbr/plugins/gallery.cpp deleted
1   -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2   - * Copyright 2012 The MITRE Corporation *
3   - * *
4   - * Licensed under the Apache License, Version 2.0 (the "License"); *
5   - * you may not use this file except in compliance with the License. *
6   - * You may obtain a copy of the License at *
7   - * *
8   - * http://www.apache.org/licenses/LICENSE-2.0 *
9   - * *
10   - * Unless required by applicable law or agreed to in writing, software *
11   - * distributed under the License is distributed on an "AS IS" BASIS, *
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13   - * See the License for the specific language governing permissions and *
14   - * limitations under the License. *
15   - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16   -
17   -#include <QtCore>
18   -#include <QtConcurrentRun>
19   -#ifndef BR_EMBEDDED
20   -#include <QNetworkAccessManager>
21   -#include <QNetworkReply>
22   -#include <QSqlDatabase>
23   -#include <QSqlError>
24   -#include <QSqlQuery>
25   -#include <QSqlRecord>
26   -#include <QXmlStreamReader>
27   -#endif // BR_EMBEDDED
28   -#include <opencv2/highgui/highgui.hpp>
29   -#include "openbr_internal.h"
30   -
31   -#include "openbr/universal_template.h"
32   -#include "openbr/core/bee.h"
33   -#include "openbr/core/common.h"
34   -#include "openbr/core/opencvutils.h"
35   -#include "openbr/core/qtutils.h"
36   -
37   -#include <fstream>
38   -
39   -#ifdef CVMATIO
40   -#include "MatlabIO.hpp"
41   -#include "MatlabIOContainer.hpp"
42   -#endif
43   -
44   -#ifdef _WIN32
45   -#include <io.h>
46   -#include <fcntl.h>
47   -#endif // _WIN32
48   -
49   -namespace br
50   -{
51   -
52   -/*!
53   - * \ingroup galleries
54   - * \brief Weka ARFF file format.
55   - * \author Josh Klontz \cite jklontz
56   - * http://weka.wikispaces.com/ARFF+%28stable+version%29
57   - */
58   -class arffGallery : public Gallery
59   -{
60   - Q_OBJECT
61   - QFile arffFile;
62   -
63   - TemplateList readBlock(bool *done)
64   - {
65   - (void) done;
66   - qFatal("Not implemented.");
67   - return TemplateList();
68   - }
69   -
70   - void write(const Template &t)
71   - {
72   - if (!arffFile.isOpen()) {
73   - arffFile.setFileName(file.name);
74   - arffFile.open(QFile::WriteOnly);
75   - arffFile.write("% OpenBR templates\n"
76   - "@RELATION OpenBR\n"
77   - "\n");
78   -
79   - const int dimensions = t.m().rows * t.m().cols;
80   - for (int i=0; i<dimensions; i++)
81   - arffFile.write(qPrintable("@ATTRIBUTE v" + QString::number(i) + " REAL\n"));
82   - arffFile.write(qPrintable("@ATTRIBUTE class string\n"));
83   -
84   - arffFile.write("\n@DATA\n");
85   - }
86   -
87   - arffFile.write(qPrintable(OpenCVUtils::matrixToStringList(t).join(',')));
88   - arffFile.write(qPrintable(",'" + t.file.get<QString>("Label") + "'\n"));
89   - }
90   -
91   - void init()
92   - {
93   - //
94   - }
95   -};
96   -
97   -BR_REGISTER(Gallery, arffGallery)
98   -
99   -class BinaryGallery : public Gallery
100   -{
101   - Q_OBJECT
102   -
103   - void init()
104   - {
105   - const QString baseName = file.baseName();
106   -
107   - if (baseName == "stdin") {
108   -#ifdef _WIN32
109   - if(_setmode(_fileno(stdin), _O_BINARY) == -1)
110   - qFatal("Failed to set stdin to binary mode!");
111   -#endif // _WIN32
112   -
113   - gallery.open(stdin, QFile::ReadOnly);
114   - } else if (baseName == "stdout") {
115   -#ifdef _WIN32
116   - if(_setmode(_fileno(stdout), _O_BINARY) == -1)
117   - qFatal("Failed to set stdout to binary mode!");
118   -#endif // _WIN32
119   -
120   - gallery.open(stdout, QFile::WriteOnly);
121   - } else if (baseName == "stderr") {
122   -#ifdef _WIN32
123   - if(_setmode(_fileno(stderr), _O_BINARY) == -1)
124   - qFatal("Failed to set stderr to binary mode!");
125   -#endif // _WIN32
126   -
127   - gallery.open(stderr, QFile::WriteOnly);
128   - } else {
129   - // Defer opening the file, in the general case we don't know if we
130   - // need read or write mode yet
131   - return;
132   - }
133   - stream.setDevice(&gallery);
134   - }
135   -
136   - void readOpen()
137   - {
138   - if (!gallery.isOpen()) {
139   - gallery.setFileName(file);
140   - if (!gallery.exists())
141   - qFatal("File %s does not exist", qPrintable(gallery.fileName()));
142   -
143   - QFile::OpenMode mode = QFile::ReadOnly;
144   - if (!gallery.open(mode))
145   - qFatal("Can't open gallery: %s for reading", qPrintable(gallery.fileName()));
146   - stream.setDevice(&gallery);
147   - }
148   - }
149   -
150   - void writeOpen()
151   - {
152   - if (!gallery.isOpen()) {
153   - gallery.setFileName(file);
154   -
155   - // Do we remove the pre-existing gallery?
156   - if (file.get<bool>("remove"))
157   - gallery.remove();
158   - QtUtils::touchDir(gallery);
159   - QFile::OpenMode mode = QFile::WriteOnly;
160   -
161   - // Do we append?
162   - if (file.get<bool>("append"))
163   - mode |= QFile::Append;
164   -
165   - if (!gallery.open(mode))
166   - qFatal("Can't open gallery: %s for writing", qPrintable(gallery.fileName()));
167   - stream.setDevice(&gallery);
168   - }
169   - }
170   -
171   - TemplateList readBlock(bool *done)
172   - {
173   - readOpen();
174   - if (gallery.atEnd())
175   - gallery.seek(0);
176   -
177   - TemplateList templates;
178   - while ((templates.size() < readBlockSize) && !gallery.atEnd()) {
179   - const Template t = readTemplate();
180   - if (!t.isEmpty() || !t.file.isNull()) {
181   - templates.append(t);
182   - templates.last().file.set("progress", position());
183   - }
184   -
185   - // Special case for pipes where we want to process data as soon as it is available
186   - if (gallery.isSequential())
187   - break;
188   - }
189   -
190   - *done = gallery.atEnd();
191   - return templates;
192   - }
193   -
194   - void write(const Template &t)
195   - {
196   - writeOpen();
197   - writeTemplate(t);
198   - if (gallery.isSequential())
199   - gallery.flush();
200   - }
201   -
202   -protected:
203   - QFile gallery;
204   - QDataStream stream;
205   -
206   - qint64 totalSize()
207   - {
208   - readOpen();
209   - return gallery.size();
210   - }
211   -
212   - qint64 position()
213   - {
214   - return gallery.pos();
215   - }
216   -
217   - virtual Template readTemplate() = 0;
218   - virtual void writeTemplate(const Template &t) = 0;
219   -};
220   -
221   -/*!
222   - * \ingroup galleries
223   - * \brief A binary gallery.
224   - *
225   - * Designed to be a literal translation of templates to disk.
226   - * Compatible with TemplateList::fromBuffer.
227   - * \author Josh Klontz \cite jklontz
228   - */
229   -class galGallery : public BinaryGallery
230   -{
231   - Q_OBJECT
232   -
233   - Template readTemplate()
234   - {
235   - Template t;
236   - stream >> t;
237   - return t;
238   - }
239   -
240   - void writeTemplate(const Template &t)
241   - {
242   - if (t.isEmpty() && t.file.isNull())
243   - return;
244   - else if (t.file.fte)
245   - stream << Template(t.file); // only write metadata for failure to enroll
246   - else
247   - stream << t;
248   - }
249   -};
250   -
251   -BR_REGISTER(Gallery, galGallery)
252   -
253   -/*!
254   - * \ingroup galleries
255   - * \brief A contiguous array of br_universal_template.
256   - * \author Josh Klontz \cite jklontz
257   - */
258   -class utGallery : public BinaryGallery
259   -{
260   - Q_OBJECT
261   -
262   - Template readTemplate()
263   - {
264   - Template t;
265   - br_universal_template ut;
266   - if (gallery.read((char*)&ut, sizeof(br_universal_template)) == sizeof(br_universal_template)) {
267   - QByteArray data(ut.urlSize + ut.fvSize, Qt::Uninitialized);
268   - char *dst = data.data();
269   - qint64 bytesNeeded = ut.urlSize + ut.fvSize;
270   - while (bytesNeeded > 0) {
271   - qint64 bytesRead = gallery.read(dst, bytesNeeded);
272   - if (bytesRead <= 0) {
273   - qDebug() << gallery.errorString();
274   - qFatal("Unexepected EOF while reading universal template data, needed: %d more of: %d bytes.", int(bytesNeeded), int(ut.urlSize + ut.fvSize));
275   - }
276   - bytesNeeded -= bytesRead;
277   - dst += bytesRead;
278   - }
279   -
280   - t.file.set("ImageID", QVariant(QByteArray((const char*)ut.imageID, 16).toHex()));
281   - t.file.set("AlgorithmID", ut.algorithmID);
282   - t.file.set("URL", QString(data.data()));
283   - char *dataStart = data.data() + ut.urlSize;
284   - uint32_t dataSize = ut.fvSize;
285   - if ((ut.algorithmID <= -1) && (ut.algorithmID >= -3)) {
286   - t.file.set("FrontalFace", QRectF(ut.x, ut.y, ut.width, ut.height));
287   - uint32_t *rightEyeX = reinterpret_cast<uint32_t*>(dataStart);
288   - dataStart += sizeof(uint32_t);
289   - uint32_t *rightEyeY = reinterpret_cast<uint32_t*>(dataStart);
290   - dataStart += sizeof(uint32_t);
291   - uint32_t *leftEyeX = reinterpret_cast<uint32_t*>(dataStart);
292   - dataStart += sizeof(uint32_t);
293   - uint32_t *leftEyeY = reinterpret_cast<uint32_t*>(dataStart);
294   - dataStart += sizeof(uint32_t);
295   - dataSize -= sizeof(uint32_t)*4;
296   - t.file.set("First_Eye", QPointF(*rightEyeX, *rightEyeY));
297   - t.file.set("Second_Eye", QPointF(*leftEyeX, *leftEyeY));
298   - } else {
299   - t.file.set("X", ut.x);
300   - t.file.set("Y", ut.y);
301   - t.file.set("Width", ut.width);
302   - t.file.set("Height", ut.height);
303   - }
304   - t.file.set("Label", ut.label);
305   - t.append(cv::Mat(1, dataSize, CV_8UC1, dataStart).clone() /* We don't want a shallow copy! */);
306   - } else {
307   - if (!gallery.atEnd())
308   - qFatal("Failed to read universal template header!");
309   - }
310   - return t;
311   - }
312   -
313   - void writeTemplate(const Template &t)
314   - {
315   - const QByteArray imageID = QByteArray::fromHex(t.file.get<QByteArray>("ImageID", QByteArray(32, '0')));
316   - if (imageID.size() != 16)
317   - qFatal("Expected 16-byte ImageID, got: %d bytes.", imageID.size());
318   -
319   - const int32_t algorithmID = (t.isEmpty() || t.file.fte) ? 0 : t.file.get<int32_t>("AlgorithmID");
320   - const QByteArray url = t.file.get<QString>("URL", t.file.name).toLatin1();
321   -
322   - uint32_t x = 0, y = 0, width = 0, height = 0;
323   - QByteArray header;
324   - if ((algorithmID <= -1) && (algorithmID >= -3)) {
325   - const QRectF frontalFace = t.file.get<QRectF>("FrontalFace");
326   - x = frontalFace.x();
327   - y = frontalFace.y();
328   - width = frontalFace.width();
329   - height = frontalFace.height();
330   -
331   - const QPointF firstEye = t.file.get<QPointF>("First_Eye");
332   - const QPointF secondEye = t.file.get<QPointF>("Second_Eye");
333   - const uint32_t rightEyeX = firstEye.x();
334   - const uint32_t rightEyeY = firstEye.y();
335   - const uint32_t leftEyeX = secondEye.x();
336   - const uint32_t leftEyeY = secondEye.y();
337   -
338   - header.append((const char*)&rightEyeX, sizeof(uint32_t));
339   - header.append((const char*)&rightEyeY, sizeof(uint32_t));
340   - header.append((const char*)&leftEyeX , sizeof(uint32_t));
341   - header.append((const char*)&leftEyeY , sizeof(uint32_t));
342   - } else {
343   - x = t.file.get<uint32_t>("X", 0);
344   - y = t.file.get<uint32_t>("Y", 0);
345   - width = t.file.get<uint32_t>("Width", 0);
346   - height = t.file.get<uint32_t>("Height", 0);
347   - }
348   - const uint32_t label = t.file.get<uint32_t>("Label", 0);
349   -
350   - gallery.write(imageID);
351   - gallery.write((const char*) &algorithmID, sizeof(int32_t));
352   - gallery.write((const char*) &x , sizeof(uint32_t));
353   - gallery.write((const char*) &y , sizeof(uint32_t));
354   - gallery.write((const char*) &width , sizeof(uint32_t));
355   - gallery.write((const char*) &height , sizeof(uint32_t));
356   - gallery.write((const char*) &label , sizeof(uint32_t));
357   -
358   - const uint32_t urlSize = url.size() + 1;
359   - gallery.write((const char*) &urlSize, sizeof(uint32_t));
360   -
361   - const uint32_t signatureSize = (algorithmID == 0) ? 0 : t.m().rows * t.m().cols * t.m().elemSize();
362   - const uint32_t fvSize = header.size() + signatureSize;
363   - gallery.write((const char*) &fvSize, sizeof(uint32_t));
364   -
365   - gallery.write((const char*) url.data(), urlSize);
366   - if (algorithmID != 0) {
367   - gallery.write(header);
368   - gallery.write((const char*) t.m().data, signatureSize);
369   - }
370   - }
371   -};
372   -
373   -BR_REGISTER(Gallery, utGallery)
374   -
375   -/*!
376   - * \ingroup galleries
377   - * \brief Newline-separated URLs.
378   - * \author Josh Klontz \cite jklontz
379   - */
380   -class urlGallery : public BinaryGallery
381   -{
382   - Q_OBJECT
383   -
384   - Template readTemplate()
385   - {
386   - Template t;
387   - const QString url = QString::fromLocal8Bit(gallery.readLine()).simplified();
388   - if (!url.isEmpty())
389   - t.file.set("URL", url);
390   - return t;
391   - }
392   -
393   - void writeTemplate(const Template &t)
394   - {
395   - const QString url = t.file.get<QString>("URL", t.file.name);
396   - if (!url.isEmpty()) {
397   - gallery.write(qPrintable(url));
398   - gallery.write("\n");
399   - }
400   - }
401   -};
402   -
403   -BR_REGISTER(Gallery, urlGallery)
404   -
405   -/*!
406   - * \ingroup galleries
407   - * \brief Newline-separated JSON objects.
408   - * \author Josh Klontz \cite jklontz
409   - */
410   -class jsonGallery : public BinaryGallery
411   -{
412   - Q_OBJECT
413   -
414   - Template readTemplate()
415   - {
416   - QJsonParseError error;
417   - const QByteArray line = gallery.readLine().simplified();
418   - if (line.isEmpty())
419   - return Template();
420   - File file = QJsonDocument::fromJson(line, &error).object().toVariantMap();
421   - if (error.error != QJsonParseError::NoError) {
422   - qWarning("Couldn't parse: %s\n", line.data());
423   - qFatal("%s\n", qPrintable(error.errorString()));
424   - }
425   - return file;
426   - }
427   -
428   - void writeTemplate(const Template &t)
429   - {
430   - const QByteArray json = QJsonDocument(QJsonObject::fromVariantMap(t.file.localMetadata())).toJson().replace('\n', "");
431   - if (!json.isEmpty()) {
432   - gallery.write(json);
433   - gallery.write("\n");
434   - }
435   - }
436   -};
437   -
438   -BR_REGISTER(Gallery, jsonGallery)
439   -
440   -/*!
441   - * \ingroup galleries
442   - * \brief Reads/writes templates to/from folders.
443   - * \author Josh Klontz \cite jklontz
444   - * \param regexp An optional regular expression to match against the files extension.
445   - */
446   -class EmptyGallery : public Gallery
447   -{
448   - Q_OBJECT
449   - Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false)
450   - BR_PROPERTY(QString, regexp, QString())
451   -
452   - qint64 gallerySize;
453   -
454   - void init()
455   - {
456   - QDir dir(file.name);
457   - QtUtils::touchDir(dir);
458   - gallerySize = dir.count();
459   - }
460   -
461   - TemplateList readBlock(bool *done)
462   - {
463   - TemplateList templates;
464   - *done = true;
465   -
466   - // Enrolling a null file is used as an idiom to initialize an algorithm
467   - if (file.isNull()) return templates;
468   -
469   - // Add immediate subfolders
470   - QDir dir(file);
471   - QList< QFuture<TemplateList> > futures;
472   - foreach (const QString &folder, QtUtils::naturalSort(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))) {
473   - const QDir subdir = dir.absoluteFilePath(folder);
474   - futures.append(QtConcurrent::run(&EmptyGallery::getTemplates, subdir));
475   - }
476   - foreach (const QFuture<TemplateList> &future, futures)
477   - templates.append(future.result());
478   -
479   - // Add root folder
480   - foreach (const QString &fileName, QtUtils::getFiles(file.name, false))
481   - templates.append(File(fileName, dir.dirName()));
482   -
483   - if (!regexp.isEmpty()) {
484   - QRegExp re(regexp);
485   - re.setPatternSyntax(QRegExp::Wildcard);
486   - for (int i=templates.size()-1; i>=0; i--) {
487   - if (!re.exactMatch(templates[i].file.fileName())) {
488   - templates.removeAt(i);
489   - }
490   - }
491   - }
492   -
493   - for (int i = 0; i < templates.size(); i++) templates[i].file.set("progress", i);
494   -
495   - return templates;
496   - }
497   -
498   - void write(const Template &t)
499   - {
500   - static QMutex diskLock;
501   -
502   - // Enrolling a null file is used as an idiom to initialize an algorithm
503   - if (file.name.isEmpty()) return;
504   -
505   - const QString newFormat = file.get<QString>("newFormat",QString());
506   - QString destination = file.name + "/" + (file.getBool("preservePath") ? t.file.path()+"/" : QString());
507   - destination += (newFormat.isEmpty() ? t.file.fileName() : t.file.baseName()+newFormat);
508   -
509   - QMutexLocker diskLocker(&diskLock); // Windows prefers to crash when writing to disk in parallel
510   - if (t.isNull()) {
511   - QtUtils::copyFile(t.file.resolved(), destination);
512   - } else {
513   - QScopedPointer<Format> format(Factory<Format>::make(destination));
514   - format->write(t);
515   - }
516   - }
517   -
518   - qint64 totalSize()
519   - {
520   - return gallerySize;
521   - }
522   -
523   - static TemplateList getTemplates(const QDir &dir)
524   - {
525   - const QStringList files = QtUtils::getFiles(dir, true);
526   - TemplateList templates; templates.reserve(files.size());
527   - foreach (const QString &file, files)
528   - templates.append(File(file, dir.dirName()));
529   - return templates;
530   - }
531   -};
532   -
533   -BR_REGISTER(Gallery, EmptyGallery)
534   -
535   -/*!
536   - * \ingroup galleries
537   - * \brief Crawl a root location for image files.
538   - * \author Josh Klontz \cite jklontz
539   - */
540   -class crawlGallery : public Gallery
541   -{
542   - Q_OBJECT
543   - Q_PROPERTY(bool autoRoot READ get_autoRoot WRITE set_autoRoot RESET reset_autoRoot STORED false)
544   - Q_PROPERTY(int depth READ get_depth WRITE set_depth RESET reset_depth STORED false)
545   - Q_PROPERTY(bool depthFirst READ get_depthFirst WRITE set_depthFirst RESET reset_depthFirst STORED false)
546   - Q_PROPERTY(int images READ get_images WRITE set_images RESET reset_images STORED false)
547   - Q_PROPERTY(bool json READ get_json WRITE set_json RESET reset_json STORED false)
548   - Q_PROPERTY(int timeLimit READ get_timeLimit WRITE set_timeLimit RESET reset_timeLimit STORED false)
549   - BR_PROPERTY(bool, autoRoot, false)
550   - BR_PROPERTY(int, depth, INT_MAX)
551   - BR_PROPERTY(bool, depthFirst, false)
552   - BR_PROPERTY(int, images, INT_MAX)
553   - BR_PROPERTY(bool, json, false)
554   - BR_PROPERTY(int, timeLimit, INT_MAX)
555   -
556   - QTime elapsed;
557   - TemplateList templates;
558   -
559   - void crawl(QFileInfo url, int currentDepth = 0)
560   - {
561   - if ((templates.size() >= images) || (currentDepth >= depth) || (elapsed.elapsed()/1000 >= timeLimit))
562   - return;
563   -
564   - if (url.filePath().startsWith("file://"))
565   - url = QFileInfo(url.filePath().mid(7));
566   -
567   - if (url.isDir()) {
568   - const QDir dir(url.absoluteFilePath());
569   - const QFileInfoList files = dir.entryInfoList(QDir::Files);
570   - const QFileInfoList subdirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
571   - foreach (const QFileInfo &first, depthFirst ? subdirs : files)
572   - crawl(first, currentDepth + 1);
573   - foreach (const QFileInfo &second, depthFirst ? files : subdirs)
574   - crawl(second, currentDepth + 1);
575   - } else if (url.isFile()) {
576   - const QString suffix = url.suffix();
577   - if ((suffix == "bmp") || (suffix == "jpg") || (suffix == "jpeg") || (suffix == "png") || (suffix == "tiff")) {
578   - File f;
579   - if (json) f.set("URL", "file://"+url.canonicalFilePath());
580   - else f.name = "file://"+url.canonicalFilePath();
581   - templates.append(f);
582   - }
583   - }
584   - }
585   -
586   - void init()
587   - {
588   - elapsed.start();
589   - const QString root = file.name.mid(0, file.name.size()-6); // Remove .crawl suffix";
590   - if (!root.isEmpty()) {
591   - crawl(root);
592   - } else {
593   - if (autoRoot) {
594   - foreach (const QString &path, QStandardPaths::standardLocations(QStandardPaths::HomeLocation))
595   - crawl(path);
596   - } else {
597   - QFile file;
598   - file.open(stdin, QFile::ReadOnly);
599   - while (!file.atEnd()) {
600   - const QString url = QString::fromLocal8Bit(file.readLine()).simplified();
601   - if (!url.isEmpty())
602   - crawl(url);
603   - }
604   - }
605   - }
606   - }
607   -
608   - TemplateList readBlock(bool *done)
609   - {
610   - *done = true;
611   - return templates;
612   - }
613   -
614   - void write(const Template &)
615   - {
616   - qFatal("Not supported");
617   - }
618   -};
619   -
620   -BR_REGISTER(Gallery, crawlGallery)
621   -
622   -/*!
623   - * \ingroup galleries
624   - * \brief Treats the gallery as a br::Format.
625   - * \author Josh Klontz \cite jklontz
626   - */
627   -class DefaultGallery : public Gallery
628   -{
629   - Q_OBJECT
630   -
631   - TemplateList readBlock(bool *done)
632   - {
633   - *done = true;
634   - return TemplateList() << file;
635   - }
636   -
637   - void write(const Template &t)
638   - {
639   - QScopedPointer<Format> format(Factory<Format>::make(file));
640   - format->write(t);
641   - }
642   -
643   - qint64 totalSize()
644   - {
645   - return 1;
646   - }
647   -};
648   -
649   -BR_REGISTER(Gallery, DefaultGallery)
650   -
651   -/*!
652   - * \ingroup galleries
653   - * \brief Combine all templates into one large matrix and process it as a br::Format
654   - * \author Josh Klontz \cite jklontz
655   - */
656   -class matrixGallery : public Gallery
657   -{
658   - Q_OBJECT
659   - Q_PROPERTY(const QString extension READ get_extension WRITE set_extension RESET reset_extension STORED false)
660   - BR_PROPERTY(QString, extension, "mtx")
661   -
662   - TemplateList templates;
663   -
664   - ~matrixGallery()
665   - {
666   - if (templates.isEmpty())
667   - return;
668   -
669   - QScopedPointer<Format> format(Factory<Format>::make(getFormat()));
670   - format->write(Template(file, OpenCVUtils::toMat(templates.data())));
671   - }
672   -
673   - File getFormat() const
674   - {
675   - return file.name.left(file.name.size() - file.suffix().size()) + extension;
676   - }
677   -
678   - TemplateList readBlock(bool *done)
679   - {
680   - *done = true;
681   - return TemplateList() << getFormat();
682   - }
683   -
684   - void write(const Template &t)
685   - {
686   - templates.append(t);
687   - }
688   -};
689   -
690   -BR_REGISTER(Gallery, matrixGallery)
691   -
692   -/*!
693   - * \ingroup initializers
694   - * \brief Initialization support for memGallery.
695   - * \author Josh Klontz \cite jklontz
696   - */
697   -class MemoryGalleries : public Initializer
698   -{
699   - Q_OBJECT
700   -
701   - void initialize() const {}
702   -
703   - void finalize() const
704   - {
705   - galleries.clear();
706   - }
707   -
708   -public:
709   - static QHash<File, TemplateList> galleries; /*!< TODO */
710   -};
711   -
712   -QHash<File, TemplateList> MemoryGalleries::galleries;
713   -
714   -BR_REGISTER(Initializer, MemoryGalleries)
715   -
716   -/*!
717   - * \ingroup galleries
718   - * \brief A gallery held in memory.
719   - * \author Josh Klontz \cite jklontz
720   - */
721   -class memGallery : public Gallery
722   -{
723   - Q_OBJECT
724   - int block;
725   - qint64 gallerySize;
726   -
727   - void init()
728   - {
729   - block = 0;
730   - File galleryFile = file.name.mid(0, file.name.size()-4);
731   - if ((galleryFile.suffix() == "gal") && galleryFile.exists() && !MemoryGalleries::galleries.contains(file)) {
732   - QSharedPointer<Gallery> gallery(Factory<Gallery>::make(galleryFile));
733   - MemoryGalleries::galleries[file] = gallery->read();
734   - gallerySize = MemoryGalleries::galleries[file].size();
735   - }
736   - }
737   -
738   - TemplateList readBlock(bool *done)
739   - {
740   - TemplateList templates = MemoryGalleries::galleries[file].mid(block*readBlockSize, readBlockSize);
741   - for (qint64 i = 0; i < templates.size();i++) {
742   - templates[i].file.set("progress", i + block * readBlockSize);
743   - }
744   -
745   - *done = (templates.size() < readBlockSize);
746   - block = *done ? 0 : block+1;
747   - return templates;
748   - }
749   -
750   - void write(const Template &t)
751   - {
752   - MemoryGalleries::galleries[file].append(t);
753   - }
754   -
755   - qint64 totalSize()
756   - {
757   - return gallerySize;
758   - }
759   -
760   - qint64 position()
761   - {
762   - return block * readBlockSize;
763   - }
764   -
765   -};
766   -
767   -BR_REGISTER(Gallery, memGallery)
768   -
769   -FileList FileList::fromGallery(const File &rFile, bool cache)
770   -{
771   - File file = rFile;
772   - file.remove("append");
773   -
774   - File targetMeta = file;
775   - targetMeta.name = targetMeta.path() + targetMeta.baseName() + "_meta" + targetMeta.hash() + ".mem";
776   -
777   - FileList fileData;
778   -
779   - // Did we already read the data?
780   - if (MemoryGalleries::galleries.contains(targetMeta))
781   - {
782   - return MemoryGalleries::galleries[targetMeta].files();
783   - }
784   -
785   - TemplateList templates;
786   - // OK we read the data in some form, does the gallery type containing matrices?
787   - if ((QStringList() << "gal" << "mem" << "template" << "ut").contains(file.suffix())) {
788   - // Retrieve it block by block, dropping matrices from read templates.
789   - QScopedPointer<Gallery> gallery(Gallery::make(file));
790   - gallery->set_readBlockSize(10);
791   - bool done = false;
792   - while (!done)
793   - {
794   - TemplateList tList = gallery->readBlock(&done);
795   - for (int i=0; i < tList.size();i++)
796   - {
797   - tList[i].clear();
798   - templates.append(tList[i].file);
799   - }
800   - }
801   - }
802   - else {
803   - // this is a gallery format that doesn't include matrices, so we can just read it
804   - QScopedPointer<Gallery> gallery(Gallery::make(file));
805   - templates= gallery->read();
806   - }
807   -
808   - if (cache)
809   - {
810   - QScopedPointer<Gallery> memOutput(Gallery::make(targetMeta));
811   - memOutput->writeBlock(templates);
812   - }
813   - fileData = templates.files();
814   - return fileData;
815   -}
816   -
817   -/*!
818   - * \ingroup galleries
819   - * \brief Treats each line as a file.
820   - * \author Josh Klontz \cite jklontz
821   - *
822   - * Columns should be comma separated with first row containing headers.
823   - * The first column in the file should be the path to the file to enroll.
824   - * Other columns will be treated as file metadata.
825   - *
826   - * \see txtGallery
827   - */
828   -class csvGallery : public FileGallery
829   -{
830   - Q_OBJECT
831   - Q_PROPERTY(int fileIndex READ get_fileIndex WRITE set_fileIndex RESET reset_fileIndex)
832   - BR_PROPERTY(int, fileIndex, 0)
833   -
834   - FileList files;
835   - QStringList headers;
836   -
837   - ~csvGallery()
838   - {
839   - f.close();
840   -
841   - if (files.isEmpty()) return;
842   -
843   - QMap<QString,QVariant> samples;
844   - foreach (const File &file, files)
845   - foreach (const QString &key, file.localKeys())
846   - if (!samples.contains(key))
847   - samples.insert(key, file.value(key));
848   -
849   - // Don't create columns in the CSV for these special fields
850   - samples.remove("Points");
851   - samples.remove("Rects");
852   -
853   - QStringList lines;
854   - lines.reserve(files.size()+1);
855   -
856   - QMap<QString, int> columnCounts;
857   -
858   - { // Make header
859   - QStringList words;
860   - words.append("File");
861   - foreach (const QString &key, samples.keys()) {
862   - int count = 0;
863   - words.append(getCSVElement(key, samples[key], true, count));
864   - columnCounts.insert(key, count);
865   - }
866   - lines.append(words.join(","));
867   - }
868   -
869   - // Make table
870   - foreach (const File &file, files) {
871   - QStringList words;
872   - words.append(file.name);
873   - foreach (const QString &key, samples.keys()) {
874   - int count = columnCounts[key];
875   - words.append(getCSVElement(key, file.value(key), false, count));
876   - }
877   - lines.append(words.join(","));
878   - }
879   -
880   - QtUtils::writeFile(file, lines);
881   - }
882   -
883   - TemplateList readBlock(bool *done)
884   - {
885   - readOpen();
886   - *done = false;
887   - TemplateList templates;
888   - if (!file.exists()) {
889   - *done = true;
890   - return templates;
891   - }
892   - QRegExp regexp("\\s*,\\s*");
893   -
894   - if (f.pos() == 0)
895   - {
896   - // read a line
897   - QByteArray lineBytes = f.readLine();
898   - QString line = QString::fromLocal8Bit(lineBytes).trimmed();
899   - headers = line.split(regexp);
900   - }
901   -
902   - for (qint64 i = 0; i < this->readBlockSize && !f.atEnd(); i++){
903   - QByteArray lineBytes = f.readLine();
904   - QString line = QString::fromLocal8Bit(lineBytes).trimmed();
905   -
906   - QStringList words = line.split(regexp);
907   - if (words.size() != headers.size()) continue;
908   - File fi;
909   - for (int j=0; j<words.size(); j++) {
910   - if (j == 0) fi.name = words[j];
911   - else fi.set(headers[j], words[j]);
912   - }
913   - templates.append(fi);
914   - templates.last().file.set("progress", f.pos());
915   - }
916   - *done = f.atEnd();
917   -
918   - return templates;
919   - }
920   -
921   - void write(const Template &t)
922   - {
923   - files.append(t.file);
924   - }
925   -
926   - static QString getCSVElement(const QString &key, const QVariant &value, bool header, int & columnCount)
927   - {
928   - if (header)
929   - columnCount = 1;
930   -
931   - if (value.canConvert<QString>()) {
932   - if (header) return key;
933   - else {
934   - if (columnCount != 1)
935   - qFatal("Inconsistent datatype for key %s, csv file cannot be generated", qPrintable(key));
936   - return value.value<QString>();
937   - }
938   - } else if (value.canConvert<QPointF>()) {
939   - const QPointF point = value.value<QPointF>();
940   - if (header) {
941   - columnCount = 2;
942   - return key+"_X,"+key+"_Y";
943   - }
944   - else {
945   - if (columnCount != 2)
946   - qFatal("Inconsistent datatype for key %s, csv file cannot be generated", qPrintable(key));
947   -
948   - return QString::number(point.x())+","+QString::number(point.y());
949   - }
950   - } else if (value.canConvert<QRectF>()) {
951   - const QRectF rect = value.value<QRectF>();
952   - if (header) {
953   - columnCount = 4;
954   - return key+"_X,"+key+"_Y,"+key+"_Width,"+key+"_Height";
955   - }
956   - else {
957   - if (columnCount != 4)
958   - qFatal("Inconsistent datatype for key %s, csv file cannot be generated", qPrintable(key));
959   -
960   - return QString::number(rect.x())+","+QString::number(rect.y())+","+QString::number(rect.width())+","+QString::number(rect.height());
961   - }
962   - } else {
963   - if (header) return key;
964   - else {
965   - QString output = QString::number(std::numeric_limits<float>::quiet_NaN());
966   - for (int i = 1; i < columnCount; i++)
967   - output += "," + QString::number(std::numeric_limits<float>::quiet_NaN());
968   - return output;
969   - }
970   - }
971   - }
972   -};
973   -
974   -BR_REGISTER(Gallery, csvGallery)
975   -
976   -/*!
977   - * \ingroup galleries
978   - * \brief Treats each line as a file.
979   - * \author Josh Klontz \cite jklontz
980   - *
981   - * The entire line is treated as the file path. An optional label may be specified using a space ' ' separator:
982   - *
983   -\verbatim
984   -<FILE>
985   -<FILE>
986   -...
987   -<FILE>
988   -\endverbatim
989   - * or
990   -\verbatim
991   -<FILE> <LABEL>
992   -<FILE> <LABEL>
993   -...
994   -<FILE> <LABEL>
995   -\endverbatim
996   - * \see csvGallery
997   - */
998   -class txtGallery : public FileGallery
999   -{
1000   - Q_OBJECT
1001   - Q_PROPERTY(QString label READ get_label WRITE set_label RESET reset_label STORED false)
1002   - BR_PROPERTY(QString, label, "")
1003   -
1004   - TemplateList readBlock(bool *done)
1005   - {
1006   - readOpen();
1007   - *done = false;
1008   - if (f.atEnd())
1009   - f.seek(0);
1010   -
1011   - TemplateList templates;
1012   -
1013   - for (qint64 i = 0; i < readBlockSize; i++)
1014   - {
1015   - QByteArray lineBytes = f.readLine();
1016   - QString line = QString::fromLocal8Bit(lineBytes).trimmed();
1017   -
1018   - if (!line.isEmpty()){
1019   - int splitIndex = line.lastIndexOf(' ');
1020   - if (splitIndex == -1) templates.append(File(line));
1021   - else templates.append(File(line.mid(0, splitIndex), line.mid(splitIndex+1)));
1022   - templates.last().file.set("progress", this->position());
1023   - }
1024   -
1025   - if (f.atEnd()) {
1026   - *done=true;
1027   - break;
1028   - }
1029   - }
1030   -
1031   - return templates;
1032   - }
1033   -
1034   - void write(const Template &t)
1035   - {
1036   - writeOpen();
1037   - QString line = t.file.name;
1038   - if (!label.isEmpty())
1039   - line += " " + t.file.get<QString>(label);
1040   -
1041   - f.write((line+"\n").toLocal8Bit() );
1042   - }
1043   -};
1044   -
1045   -BR_REGISTER(Gallery, txtGallery)
1046   -
1047   -/*!
1048   - * \ingroup galleries
1049   - * \brief Treats each line as a call to File::flat()
1050   - * \author Josh Klontz \cite jklontz
1051   - */
1052   -class flatGallery : public FileGallery
1053   -{
1054   - Q_OBJECT
1055   -
1056   - TemplateList readBlock(bool *done)
1057   - {
1058   - readOpen();
1059   - *done = false;
1060   - if (f.atEnd())
1061   - f.seek(0);
1062   -
1063   - TemplateList templates;
1064   -
1065   - for (qint64 i = 0; i < readBlockSize; i++)
1066   - {
1067   - QByteArray line = f.readLine();
1068   -
1069   - if (!line.isEmpty()) {
1070   - templates.append(File(QString::fromLocal8Bit(line).trimmed()));
1071   - templates.last().file.set("progress", this->position());
1072   - }
1073   -
1074   - if (f.atEnd()) {
1075   - *done=true;
1076   - break;
1077   - }
1078   - }
1079   -
1080   - return templates;
1081   - }
1082   -
1083   - void write(const Template &t)
1084   - {
1085   - writeOpen();
1086   - f.write((t.file.flat()+"\n").toLocal8Bit() );
1087   - }
1088   -};
1089   -
1090   -BR_REGISTER(Gallery, flatGallery)
1091   -
1092   -/*!
1093   - * \ingroup galleries
1094   - * \brief A \ref sigset input.
1095   - * \author Josh Klontz \cite jklontz
1096   - */
1097   -class xmlGallery : public FileGallery
1098   -{
1099   - Q_OBJECT
1100   - Q_PROPERTY(bool ignoreMetadata READ get_ignoreMetadata WRITE set_ignoreMetadata RESET reset_ignoreMetadata STORED false)
1101   - BR_PROPERTY(bool, ignoreMetadata, false)
1102   - FileList files;
1103   -
1104   - QXmlStreamReader reader;
1105   -
1106   - QString currentSignatureName;
1107   - bool signatureActive;
1108   -
1109   - ~xmlGallery()
1110   - {
1111   - f.close();
1112   - if (!files.isEmpty())
1113   - BEE::writeSigset(file, files, ignoreMetadata);
1114   - }
1115   -
1116   - TemplateList readBlock(bool *done)
1117   - {
1118   - if (readOpen())
1119   - reader.setDevice(&f);
1120   -
1121   - if (reader.atEnd())
1122   - f.seek(0);
1123   -
1124   - TemplateList templates;
1125   - qint64 count = 0;
1126   -
1127   - while (!reader.atEnd())
1128   - {
1129   - // if an identity is active we try to read presentations
1130   - if (signatureActive)
1131   - {
1132   - while (signatureActive)
1133   - {
1134   - QXmlStreamReader::TokenType signatureToken = reader.readNext();
1135   -
1136   - // did the signature end?
1137   - if (signatureToken == QXmlStreamReader::EndElement && reader.name() == "biometric-signature") {
1138   - signatureActive = false;
1139   - break;
1140   - }
1141   -
1142   - // did we reach the end of the document? Theoretically this shoudln't happen without reaching the end of
1143   - if (signatureToken == QXmlStreamReader::EndDocument)
1144   - break;
1145   -
1146   - // a presentation!
1147   - if (signatureToken == QXmlStreamReader::StartElement && reader.name() == "presentation") {
1148   - templates.append(Template(File("",currentSignatureName)));
1149   - foreach (const QXmlStreamAttribute &attribute, reader.attributes()) {
1150   - // file-name is stored directly on file, not as a key/value pair
1151   - if (attribute.name() == "file-name")
1152   - templates.last().file.name = attribute.value().toString();
1153   - // other values are directly set as metadata
1154   - else if (!ignoreMetadata) templates.last().file.set(attribute.name().toString(), attribute.value().toString());
1155   - }
1156   -
1157   - // a presentation can have bounding boxes as child elements
1158   - QList<QRectF> rects = templates.last().file.rects();
1159   - while (true)
1160   - {
1161   - QXmlStreamReader::TokenType pToken = reader.readNext();
1162   - if (pToken == QXmlStreamReader::EndElement && reader.name() == "presentation")
1163   - break;
1164   -
1165   - if (pToken == QXmlStreamReader::StartElement)
1166   - {
1167   - if (reader.attributes().hasAttribute("x")
1168   - && reader.attributes().hasAttribute("y")
1169   - && reader.attributes().hasAttribute("width")
1170   - && reader.attributes().hasAttribute("height") )
1171   - {
1172   - // get bounding box properties as attributes, just going to assume this all works
1173   - qreal x = reader.attributes().value("x").string()->toDouble();
1174   - qreal y = reader.attributes().value("y").string()->toDouble();
1175   - qreal width = reader.attributes().value("width").string()->toDouble();
1176   - qreal height = reader.attributes().value("height").string()->toDouble();
1177   - rects += QRectF(x, y, width, height);
1178   - }
1179   - }
1180   - }
1181   - templates.last().file.setRects(rects);
1182   - templates.last().file.set("progress", f.pos());
1183   -
1184   - // we read another complete template
1185   - count++;
1186   - }
1187   - }
1188   - }
1189   - // otherwise, keep reading elements until the next identity is reacehed
1190   - else
1191   - {
1192   - QXmlStreamReader::TokenType token = reader.readNext();
1193   -
1194   - // end of file?
1195   - if (token == QXmlStreamReader::EndDocument)
1196   - break;
1197   -
1198   - // we are only interested in new elements
1199   - if (token != QXmlStreamReader::StartElement)
1200   - continue;
1201   -
1202   - QStringRef elName = reader.name();
1203   -
1204   - // biometric-signature-set is the root element
1205   - if (elName == "biometric-signature-set")
1206   - continue;
1207   -
1208   - // biometric-signature -- an identity
1209   - if (elName == "biometric-signature")
1210   - {
1211   - // read the name associated with the current signature
1212   - if (!reader.attributes().hasAttribute("name"))
1213   - {
1214   - qDebug() << "Biometric signature missing name";
1215   - continue;
1216   - }
1217   - currentSignatureName = reader.attributes().value("name").toString();
1218   - signatureActive = true;
1219   -
1220   - // If we've already read enough templates for this block, then break here.
1221   - // We wait untill the start of the next signature to be sure that done should
1222   - // actually be false (i.e. there are actually items left in this file)
1223   - if (count >= this->readBlockSize) {
1224   - *done = false;
1225   - return templates;
1226   - }
1227   -
1228   - }
1229   - }
1230   - }
1231   - *done = true;
1232   -
1233   - return templates;
1234   - }
1235   -
1236   - void write(const Template &t)
1237   - {
1238   - files.append(t.file);
1239   - }
1240   -
1241   - void init()
1242   - {
1243   - FileGallery::init();
1244   - }
1245   -};
1246   -
1247   -BR_REGISTER(Gallery, xmlGallery)
1248   -
1249   -/*!
1250   - * \ingroup galleries
1251   - * \brief Treat the file as a single binary template.
1252   - * \author Josh Klontz \cite jklontz
1253   - */
1254   -class templateGallery : public Gallery
1255   -{
1256   - Q_OBJECT
1257   -
1258   - TemplateList readBlock(bool *done)
1259   - {
1260   - *done = true;
1261   - QByteArray data;
1262   - QtUtils::readFile(file.name.left(file.name.size()-QString(".template").size()), data);
1263   - return TemplateList() << Template(file, cv::Mat(1, data.size(), CV_8UC1, data.data()).clone());
1264   - }
1265   -
1266   - void write(const Template &t)
1267   - {
1268   - (void) t;
1269   - qFatal("No supported.");
1270   - }
1271   -
1272   - void init()
1273   - {
1274   - //
1275   - }
1276   -};
1277   -
1278   -BR_REGISTER(Gallery, templateGallery)
1279   -
1280   -/*!
1281   - * \ingroup galleries
1282   - * \brief Database input.
1283   - * \author Josh Klontz \cite jklontz
1284   - */
1285   -class dbGallery : public Gallery
1286   -{
1287   - Q_OBJECT
1288   -
1289   - TemplateList readBlock(bool *done)
1290   - {
1291   - TemplateList templates;
1292   - br::File import = file.get<QString>("import", "");
1293   - QString query = file.get<QString>("query");
1294   - QString subset = file.get<QString>("subset", "");
1295   -
1296   -#ifndef BR_EMBEDDED
1297   - QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
1298   - db.setDatabaseName(file);
1299   - if (!db.open()) qFatal("Failed to open SQLite database %s.", qPrintable(file.name));
1300   -
1301   - if (!import.isNull()) {
1302   - qDebug("Parsing %s", qPrintable(import.name));
1303   - QStringList lines = QtUtils::readLines(import);
1304   - QList<QStringList> cells; cells.reserve(lines.size());
1305   - const QRegExp re("\\s*,\\s*");
1306   - foreach (const QString &line, lines) {
1307   - cells.append(line.split(re));
1308   - if (cells.last().size() != cells.first().size()) qFatal("Column count mismatch.");
1309   - }
1310   -
1311   - QStringList columns, qMarks;
1312   - QList<QVariantList> variantLists;
1313   - for (int i=0; i<cells[0].size(); i++) {
1314   - bool isNumeric;
1315   - cells[1][i].toInt(&isNumeric);
1316   - columns.append(cells[0][i] + (isNumeric ? " INTEGER" : " STRING"));
1317   - qMarks.append("?");
1318   -
1319   - QVariantList variantList; variantList.reserve(lines.size()-1);
1320   - for (int j=1; j<lines.size(); j++) {
1321   - if (isNumeric) variantList << cells[j][i].toInt();
1322   - else variantList << cells[j][i];
1323   - }
1324   - variantLists.append(variantList);
1325   - }
1326   -
1327   - const QString &table = import.baseName();
1328   - qDebug("Creating table %s", qPrintable(table));
1329   - QSqlQuery q(db);
1330   - if (!q.exec("CREATE TABLE " + table + " (" + columns.join(", ") + ");"))
1331   - qFatal("%s.", qPrintable(q.lastError().text()));
1332   - if (!q.prepare("insert into " + table + " values (" + qMarks.join(", ") + ")"))
1333   - qFatal("%s.", qPrintable(q.lastError().text()));
1334   - foreach (const QVariantList &vl, variantLists)
1335   - q.addBindValue(vl);
1336   - if (!q.execBatch()) qFatal("%s.", qPrintable(q.lastError().text()));
1337   - }
1338   -
1339   - QSqlQuery q(db);
1340   - if (query.startsWith('\'') && query.endsWith('\''))
1341   - query = query.mid(1, query.size()-2);
1342   - if (!q.exec(query))
1343   - qFatal("%s.", qPrintable(q.lastError().text()));
1344   -
1345   - if ((q.record().count() == 0) || (q.record().count() > 3))
1346   - qFatal("Query record expected one to three fields, got %d.", q.record().count());
1347   - const bool hasMetadata = (q.record().count() >= 2);
1348   - const bool hasFilter = (q.record().count() >= 3);
1349   -
1350   - QString labelName = "Label";
1351   - if (q.record().count() >= 2)
1352   - labelName = q.record().fieldName(1);
1353   -
1354   - // subset = seed:subjectMaxSize:numSubjects:subjectMinSize or
1355   - // subset = seed:{Metadata,...,Metadata}:numSubjects
1356   - int seed = 0, subjectMaxSize = std::numeric_limits<int>::max(), numSubjects = std::numeric_limits<int>::max(), subjectMinSize = 0;
1357   - QList<QRegExp> metadataFields;
1358   - if (!subset.isEmpty()) {
1359   - const QStringList &words = subset.split(":");
1360   - QtUtils::checkArgsSize("Input", words, 2, 4);
1361   - if (words[0] == "train") seed = 0;
1362   - else if (words[0] == "test" ) seed = 1;
1363   - else seed = QtUtils::toInt(words[0]);
1364   - if (words[1].startsWith('{') && words[1].endsWith('}')) {
1365   - foreach (const QString &regexp, words[1].mid(1, words[1].size()-2).split(","))
1366   - metadataFields.append(QRegExp(regexp));
1367   - subjectMaxSize = metadataFields.size();
1368   - } else {
1369   - subjectMaxSize = QtUtils::toInt(words[1]);
1370   - }
1371   - numSubjects = words.size() >= 3 ? QtUtils::toInt(words[2]) : std::numeric_limits<int>::max();
1372   - subjectMinSize = words.size() >= 4 ? QtUtils::toInt(words[3]) : subjectMaxSize;
1373   - }
1374   -
1375   - srand(seed);
1376   -
1377   - typedef QPair<QString,QString> Entry; // QPair<File,Metadata>
1378   - QHash<QString, QList<Entry> > entries; // QHash<Label, QList<Entry> >
1379   - while (q.next()) {
1380   - if (hasFilter && (seed >= 0) && (qHash(q.value(2).toString()) % 2 != (uint)seed % 2)) continue; // Ensures training and testing filters don't overlap
1381   -
1382   - if (metadataFields.isEmpty())
1383   - entries[hasMetadata ? q.value(1).toString() : ""].append(QPair<QString,QString>(q.value(0).toString(), hasFilter ? q.value(2).toString() : ""));
1384   - else
1385   - entries[hasFilter ? q.value(2).toString() : ""].append(QPair<QString,QString>(q.value(0).toString(), hasMetadata ? q.value(1).toString() : ""));
1386   - }
1387   -
1388   - QStringList labels = entries.keys();
1389   - qSort(labels);
1390   -
1391   - if (hasFilter && ((labels.size() > numSubjects) || (numSubjects == std::numeric_limits<int>::max())))
1392   - std::random_shuffle(labels.begin(), labels.end());
1393   -
1394   - foreach (const QString &label, labels) {
1395   - QList<Entry> entryList = entries[label];
1396   - if ((entryList.size() >= subjectMinSize) && (numSubjects > 0)) {
1397   -
1398   - if (!metadataFields.isEmpty()) {
1399   - QList<Entry> subEntryList;
1400   - foreach (const QRegExp &metadata, metadataFields) {
1401   - for (int i=0; i<entryList.size(); i++) {
1402   - if (metadata.exactMatch(entryList[i].second)) {
1403   - subEntryList.append(entryList.takeAt(i));
1404   - break;
1405   - }
1406   - }
1407   - }
1408   - if (subEntryList.size() == metadataFields.size())
1409   - entryList = subEntryList;
1410   - else
1411   - continue;
1412   - }
1413   -
1414   - if (entryList.size() > subjectMaxSize)
1415   - std::random_shuffle(entryList.begin(), entryList.end());
1416   - foreach (const Entry &entry, entryList.mid(0, subjectMaxSize)) {
1417   - templates.append(File(entry.first));
1418   - templates.last().file.set(labelName, label);
1419   - }
1420   - numSubjects--;
1421   - }
1422   - }
1423   -
1424   - db.close();
1425   -#endif // BR_EMBEDDED
1426   -
1427   - *done = true;
1428   - return templates;
1429   - }
1430   -
1431   - void write(const Template &t)
1432   - {
1433   - (void) t;
1434   - qFatal("Not supported.");
1435   - }
1436   -
1437   - void init()
1438   - {
1439   - //
1440   - }
1441   -};
1442   -
1443   -BR_REGISTER(Gallery, dbGallery)
1444   -
1445   -/*!
1446   - * \ingroup inputs
1447   - * \brief Input from a google image search.
1448   - * \author Josh Klontz \cite jklontz
1449   - */
1450   -class googleGallery : public Gallery
1451   -{
1452   - Q_OBJECT
1453   -
1454   - TemplateList readBlock(bool *done)
1455   - {
1456   - TemplateList templates;
1457   -
1458   - static const QString search = "http://images.google.com/images?q=%1&start=%2";
1459   - QString query = file.name.left(file.name.size()-7); // remove ".google"
1460   -
1461   -#ifndef BR_EMBEDDED
1462   - QNetworkAccessManager networkAccessManager;
1463   - for (int i=0; i<100; i+=20) { // Retrieve 100 images
1464   - QNetworkRequest request(search.arg(query, QString::number(i)));
1465   - QNetworkReply *reply = networkAccessManager.get(request);
1466   -
1467   - while (!reply->isFinished())
1468   - QThread::yieldCurrentThread();
1469   -
1470   - QString data(reply->readAll());
1471   - delete reply;
1472   -
1473   - QStringList words = data.split("imgurl=");
1474   - words.takeFirst(); // Remove header
1475   - foreach (const QString &word, words) {
1476   - QString url = word.left(word.indexOf("&amp"));
1477   - url = url.replace("%2520","%20");
1478   - int junk = url.indexOf('%', url.lastIndexOf('.'));
1479   - if (junk != -1) url = url.left(junk);
1480   - templates.append(File(url,query));
1481   - }
1482   - }
1483   -#endif // BR_EMBEDDED
1484   -
1485   - *done = true;
1486   - return templates;
1487   - }
1488   -
1489   - void write(const Template &)
1490   - {
1491   - qFatal("Not supported.");
1492   - }
1493   -};
1494   -
1495   -BR_REGISTER(Gallery, googleGallery)
1496   -
1497   -/*!
1498   - * \ingroup galleries
1499   - * \brief Print template statistics.
1500   - * \author Josh Klontz \cite jklontz
1501   - */
1502   -class statGallery : public Gallery
1503   -{
1504   - Q_OBJECT
1505   - QSet<QString> subjects;
1506   - QList<int> bytes;
1507   -
1508   - ~statGallery()
1509   - {
1510   - int emptyTemplates = 0;
1511   - for (int i=bytes.size()-1; i>=0; i--)
1512   - if (bytes[i] == 0) {
1513   - bytes.removeAt(i);
1514   - emptyTemplates++;
1515   - }
1516   -
1517   - double bytesMean, bytesStdDev;
1518   - Common::MeanStdDev(bytes, &bytesMean, &bytesStdDev);
1519   - printf("Subjects: %d\nEmpty Templates: %d/%d\nBytes/Template: %.4g +/- %.4g\n",
1520   - subjects.size(), emptyTemplates, emptyTemplates+bytes.size(), bytesMean, bytesStdDev);
1521   - }
1522   -
1523   - TemplateList readBlock(bool *done)
1524   - {
1525   - *done = true;
1526   - return TemplateList() << file;
1527   - }
1528   -
1529   - void write(const Template &t)
1530   - {
1531   - subjects.insert(t.file.get<QString>("Label"));
1532   - bytes.append(t.bytes());
1533   - }
1534   -};
1535   -
1536   -BR_REGISTER(Gallery, statGallery)
1537   -
1538   -/*!
1539   - * \ingroup galleries
1540   - * \brief Implements the FDDB detection format.
1541   - * \author Josh Klontz \cite jklontz
1542   - *
1543   - * http://vis-www.cs.umass.edu/fddb/README.txt
1544   - */
1545   -class FDDBGallery : public Gallery
1546   -{
1547   - Q_OBJECT
1548   -
1549   - TemplateList readBlock(bool *done)
1550   - {
1551   - *done = true;
1552   - QStringList lines = QtUtils::readLines(file);
1553   - TemplateList templates;
1554   - while (!lines.empty()) {
1555   - const QString fileName = lines.takeFirst();
1556   - int numDetects = lines.takeFirst().toInt();
1557   - for (int i=0; i<numDetects; i++) {
1558   - const QStringList detect = lines.takeFirst().split(' ');
1559   - Template t(fileName);
1560   - QList<QVariant> faceList; //to be consistent with slidingWindow
1561   - if (detect.size() == 5) { //rectangle
1562   - faceList.append(QRectF(detect[0].toFloat(), detect[1].toFloat(), detect[2].toFloat(), detect[3].toFloat()));
1563   - t.file.set("Confidence", detect[4].toFloat());
1564   - } else if (detect.size() == 6) { //ellipse
1565   - float x = detect[3].toFloat(),
1566   - y = detect[4].toFloat(),
1567   - radius = detect[1].toFloat();
1568   - faceList.append(QRectF(x - radius,y - radius,radius * 2.0, radius * 2.0));
1569   - t.file.set("Confidence", detect[5].toFloat());
1570   - } else {
1571   - qFatal("Unknown FDDB annotation format.");
1572   - }
1573   - t.file.set("Face", faceList);
1574   - t.file.set("Label",QString("face"));
1575   - templates.append(t);
1576   - }
1577   - }
1578   - return templates;
1579   - }
1580   -
1581   - void write(const Template &t)
1582   - {
1583   - (void) t;
1584   - qFatal("Not implemented.");
1585   - }
1586   -
1587   - void init()
1588   - {
1589   - //
1590   - }
1591   -};
1592   -
1593   -BR_REGISTER(Gallery, FDDBGallery)
1594   -
1595   -/*!
1596   - * \ingroup galleries
1597   - * \brief Text format for associating anonymous landmarks with images.
1598   - * \author Josh Klontz \cite jklontz
1599   - *
1600   - * \code
1601   - * file_name:x1,y1,x2,y2,...,xn,yn
1602   - * file_name:x1,y1,x2,y2,...,xn,yn
1603   - * ...
1604   - * file_name:x1,y1,x2,y2,...,xn,yn
1605   - * \endcode
1606   - */
1607   -class landmarksGallery : public Gallery
1608   -{
1609   - Q_OBJECT
1610   -
1611   - TemplateList readBlock(bool *done)
1612   - {
1613   - *done = true;
1614   - TemplateList templates;
1615   - foreach (const QString &line, QtUtils::readLines(file)) {
1616   - const QStringList words = line.split(':');
1617   - if (words.size() != 2) qFatal("Expected exactly one ':' in: %s.", qPrintable(line));
1618   - File file(words[0]);
1619   - const QList<float> vals = QtUtils::toFloats(words[1].split(','));
1620   - if (vals.size() % 2 != 0) qFatal("Expected an even number of comma-separated values.");
1621   - QList<QPointF> points; points.reserve(vals.size()/2);
1622   - for (int i=0; i<vals.size(); i+=2)
1623   - points.append(QPointF(vals[i], vals[i+1]));
1624   - file.setPoints(points);
1625   - templates.append(file);
1626   - }
1627   - return templates;
1628   - }
1629   -
1630   - void write(const Template &t)
1631   - {
1632   - (void) t;
1633   - qFatal("Not implemented.");
1634   - }
1635   -
1636   - void init()
1637   - {
1638   - //
1639   - }
1640   -};
1641   -
1642   -BR_REGISTER(Gallery, landmarksGallery)
1643   -
1644   -#ifdef CVMATIO
1645   -
1646   -using namespace cv;
1647   -
1648   -class vbbGallery : public Gallery
1649   -{
1650   - Q_OBJECT
1651   -
1652   - void init()
1653   - {
1654   - MatlabIO matio;
1655   - QString filename = (Globals->path.isEmpty() ? "" : Globals->path + "/") + file.name;
1656   - bool ok = matio.open(filename.toStdString(), "r");
1657   - if (!ok) qFatal("Couldn't open the vbb file");
1658   -
1659   - vector<MatlabIOContainer> variables;
1660   - variables = matio.read();
1661   - matio.close();
1662   -
1663   - double vers = variables[1].data<Mat>().at<double>(0,0);
1664   - if (vers != 1.4) qFatal("This is an old vbb version, we don't mess with that.");
1665   -
1666   - A = variables[0].data<vector<vector<MatlabIOContainer> > >().at(0);
1667   - objLists = A.at(1).data<vector<MatlabIOContainer> >();
1668   -
1669   - // start at the first frame (duh!)
1670   - currFrame = 0;
1671   - }
1672   -
1673   - TemplateList readBlock(bool *done)
1674   - {
1675   - *done = false;
1676   - Template rects(file);
1677   - if (objLists[currFrame].typeEquals<vector<vector<MatlabIOContainer> > >()) {
1678   - vector<vector<MatlabIOContainer> > bbs = objLists[currFrame].data<vector<vector<MatlabIOContainer> > >();
1679   - for (unsigned int i=0; i<bbs.size(); i++) {
1680   - vector<MatlabIOContainer> bb = bbs[i];
1681   - Mat pos = bb[1].data<Mat>();
1682   - double left = pos.at<double>(0,0);
1683   - double top = pos.at<double>(0,1);
1684   - double width = pos.at<double>(0,2);
1685   - double height = pos.at<double>(0,3);
1686   - rects.file.appendRect(QRectF(left, top, width, height));
1687   - }
1688   - }
1689   - TemplateList tl;
1690   - tl.append(rects);
1691   - if (++currFrame == (int)objLists.size()) *done = true;
1692   - return tl;
1693   - }
1694   -
1695   - void write(const Template &t)
1696   - {
1697   - (void)t; qFatal("Not implemented");
1698   - }
1699   -
1700   -private:
1701   - // this holds a bunch of stuff, maybe we'll use it all later
1702   - vector<MatlabIOContainer> A;
1703   - // this, a field in A, holds bounding boxes for each frame
1704   - vector<MatlabIOContainer> objLists;
1705   - int currFrame;
1706   -};
1707   -
1708   -BR_REGISTER(Gallery, vbbGallery)
1709   -
1710   -#endif
1711   -
1712   -
1713   -// Read a video frame by frame using cv::VideoCapture
1714   -class videoGallery : public Gallery
1715   -{
1716   - Q_OBJECT
1717   -public:
1718   - qint64 idx;
1719   - ~videoGallery()
1720   - {
1721   - video.release();
1722   - }
1723   -
1724   - static QMutex openLock;
1725   -
1726   - virtual void deferredInit()
1727   - {
1728   - bool status = video.open(QtUtils::getAbsolutePath(file.name).toStdString());
1729   -
1730   - if (!status)
1731   - qFatal("Failed to open file %s with path %s", qPrintable(file.name), qPrintable(QtUtils::getAbsolutePath(file.name)));
1732   - }
1733   -
1734   - TemplateList readBlock(bool *done)
1735   - {
1736   - if (!video.isOpened()) {
1737   - // opening videos appears to not be thread safe on windows
1738   - QMutexLocker lock(&openLock);
1739   -
1740   - deferredInit();
1741   - idx = 0;
1742   - }
1743   -
1744   - Template output;
1745   - output.file = file;
1746   - output.m() = cv::Mat();
1747   -
1748   - cv::Mat temp;
1749   - bool res = video.read(temp);
1750   -
1751   - if (!res) {
1752   - // The video capture broke, return an empty list.
1753   - output.m() = cv::Mat();
1754   - video.release();
1755   - *done = true;
1756   - return TemplateList();
1757   - }
1758   -
1759   - // This clone is critical, if we don't do it then the output matrix will
1760   - // be an alias of an internal buffer of the video source, leading to various
1761   - // problems later.
1762   - output.m() = temp.clone();
1763   -
1764   - output.file.set("progress", idx);
1765   - idx++;
1766   -
1767   - TemplateList rVal;
1768   - rVal.append(temp);
1769   - *done = false;
1770   - return rVal;
1771   - }
1772   -
1773   - void write(const Template &t)
1774   - {
1775   - (void)t; qFatal("Not implemented");
1776   - }
1777   -
1778   -protected:
1779   - cv::VideoCapture video;
1780   -};
1781   -BR_REGISTER(Gallery,videoGallery)
1782   -
1783   -QMutex videoGallery::openLock;
1784   -
1785   -class aviGallery : public videoGallery
1786   -{
1787   - Q_OBJECT
1788   -};
1789   -BR_REGISTER(Gallery, aviGallery)
1790   -
1791   -class wmvGallery : public videoGallery
1792   -{
1793   - Q_OBJECT
1794   -};
1795   -BR_REGISTER(Gallery, wmvGallery)
1796   -
1797   -// Mostly the same as videoGallery, but we open the VideoCapture with an integer index
1798   -// rather than file name/web address
1799   -class webcamGallery : public videoGallery
1800   -{
1801   -public:
1802   - Q_OBJECT
1803   -
1804   - void deferredInit()
1805   - {
1806   - bool intOK = false;
1807   - int anInt = file.baseName().toInt(&intOK);
1808   -
1809   - if (!intOK)
1810   - qFatal("Expected integer basename, got %s", qPrintable(file.baseName()));
1811   -
1812   - bool rc = video.open(anInt);
1813   -
1814   - if (!rc)
1815   - qFatal("Failed to open webcam with index: %s", qPrintable(file.baseName()));
1816   - }
1817   -
1818   -};
1819   -BR_REGISTER(Gallery,webcamGallery)
1820   -
1821   -class seqGallery : public Gallery
1822   -{
1823   -public:
1824   - Q_OBJECT
1825   -
1826   - bool open()
1827   - {
1828   - seqFile.open(QtUtils::getAbsolutePath(file.name).toStdString().c_str(), std::ios::in | std::ios::binary | std::ios::ate);
1829   - if (!isOpen()) {
1830   - qDebug("Failed to open file %s for reading", qPrintable(file.name));
1831   - return false;
1832   - }
1833   -
1834   - int headSize = 1024;
1835   - // start at end of file to get full size
1836   - int fileSize = seqFile.tellg();
1837   - if (fileSize < headSize) {
1838   - qDebug("No header in seq file");
1839   - return false;
1840   - }
1841   -
1842   - // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq '
1843   - char firstFour[4];
1844   - seqFile.seekg(0, std::ios::beg);
1845   - seqFile.read(firstFour, 4);
1846   - char nextTwentyFour[24];
1847   - readText(24, nextTwentyFour);
1848   - if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) {
1849   - qDebug("Invalid header in seq file");
1850   - return false;
1851   - }
1852   -
1853   - // next 8 bytes for version (skipped below) and header size (1024), then 512 for descr
1854   - seqFile.seekg(4, std::ios::cur);
1855   - int hSize = readInt();
1856   - if (hSize != headSize) {
1857   - qDebug("Invalid header size");
1858   - return false;
1859   - }
1860   - char desc[512];
1861   - readText(512, desc);
1862   - file.set("Description", QString(desc));
1863   -
1864   - width = readInt();
1865   - height = readInt();
1866   - // get # channels from bit depth
1867   - numChan = readInt()/8;
1868   - int imageBitDepthReal = readInt();
1869   - if (imageBitDepthReal != 8) {
1870   - qDebug("Invalid bit depth");
1871   - return false;
1872   - }
1873   - // the size of just the image part of a raw img
1874   - imgSizeBytes = readInt();
1875   -
1876   - int imgFormatInt = readInt();
1877   - if (imgFormatInt == 100 || imgFormatInt == 200 || imgFormatInt == 101) {
1878   - imgFormat = "raw";
1879   - } else if (imgFormatInt == 102 || imgFormatInt == 201 || imgFormatInt == 103 ||
1880   - imgFormatInt == 1 || imgFormatInt == 2) {
1881   - imgFormat = "compressed";
1882   - } else {
1883   - qFatal("unsupported image format");
1884   - }
1885   -
1886   - numFrames = readInt();
1887   - // skip empty int
1888   - seqFile.seekg(4, std::ios::cur);
1889   - // the size of a full raw file, with extra crap after img data
1890   - trueImgSizeBytes = readInt();
1891   -
1892   - // gather all the frame positions in an array
1893   - seekPos.reserve(numFrames);
1894   - // start at end of header
1895   - seekPos.append(headSize);
1896   - // extra 8 bytes at end of img
1897   - int extra = 8;
1898   - for (int i=1; i<numFrames; i++) {
1899   - int s;
1900   - // compressed images have different sizes
1901   - // the first byte at the beginning of the file
1902   - // says how big the current img is
1903   - if (imgFormat == "compressed") {
1904   - int lastPos = seekPos[i-1];
1905   - seqFile.seekg(lastPos, std::ios::beg);
1906   - int currSize = readInt();
1907   - s = lastPos + currSize + extra;
1908   -
1909   - // but there might be 16 extra bytes instead of 8...
1910   - if (i == 1) {
1911   - seqFile.seekg(s, std::ios::beg);
1912   - char zero;
1913   - seqFile.read(&zero, 1);
1914   - if (zero == 0) {
1915   - s += 8;
1916   - extra += 8;
1917   - }
1918   - }
1919   - }
1920   - // raw images are all the same size
1921   - else {
1922   - s = headSize + (i*trueImgSizeBytes);
1923   - }
1924   -
1925   - seekPos.enqueue(s);
1926   - }
1927   -
1928   -#ifdef CVMATIO
1929   - if (basis.file.contains("vbb")) {
1930   - QString vbb = basis.file.get<QString>("vbb");
1931   - annotations = TemplateList::fromGallery(File(vbb));
1932   - }
1933   -#else
1934   - qWarning("cvmatio not installed, bounding boxes will not be available. Add -DBR_WITH_CVMATIO cmake flag to install.");
1935   -#endif
1936   -
1937   - return true;
1938   - }
1939   -
1940   - bool isOpen()
1941   - {
1942   - return seqFile.is_open();
1943   - }
1944   -
1945   - void close()
1946   - {
1947   - seqFile.close();
1948   - }
1949   -
1950   - TemplateList readBlock(bool *done)
1951   - {
1952   - if (!isOpen()) {
1953   - if (!open())
1954   - qFatal("Failed to open file %s for reading", qPrintable(file.name));
1955   - else
1956   - idx = 0;
1957   - }
1958   -
1959   - // if we've reached the last frame, we're done
1960   - if (seekPos.size() == 0) {
1961   - *done = true;
1962   - return TemplateList();
1963   - }
1964   -
1965   - seqFile.seekg(seekPos.dequeue(), std::ios::beg);
1966   -
1967   - cv::Mat temp;
1968   - // let imdecode do all the work to decode the compressed img
1969   - if (imgFormat == "compressed") {
1970   - int imgSize = readInt() - 4;
1971   - std::vector<char> imgBuf(imgSize);
1972   - seqFile.read(&imgBuf[0], imgSize);
1973   - // flags < 0 means load image as-is (keep color info if available)
1974   - cv::imdecode(imgBuf, -1, &temp);
1975   - }
1976   - // raw images can be loaded straight into a Mat
1977   - else {
1978   - char *imgBuf = new char[imgSizeBytes];
1979   - seqFile.read(imgBuf, imgSizeBytes);
1980   - int type = (numChan == 1 ? CV_8UC1 : CV_8UC3);
1981   - temp = cv::Mat(height, width, type, imgBuf);
1982   - }
1983   - Template output;
1984   - output.file = file;
1985   - if (!annotations.empty()) {
1986   - output.file.setRects(annotations.first().file.rects());
1987   - annotations.removeFirst();
1988   - }
1989   - output.m() = temp;
1990   - output.file.set("position",idx);
1991   - idx++;
1992   -
1993   - *done = false;
1994   - TemplateList rVal;
1995   - rVal.append(output);
1996   -
1997   - return rVal;
1998   - }
1999   -
2000   - void write(const Template &t)
2001   - {
2002   - (void) t;
2003   - qFatal("Not implemented.");
2004   - }
2005   -
2006   -private:
2007   - qint64 idx;
2008   - int readInt()
2009   - {
2010   - int num;
2011   - seqFile.read((char*)&num, 4);
2012   - return num;
2013   - }
2014   -
2015   - // apparently the text in seq files is 16 bit characters (UTF-16?)
2016   - // since we don't really need the last byte, snad since it gets interpreted as
2017   - // a terminating char, let's just grab the first byte for storage
2018   - void readText(int bytes, char *buffer)
2019   - {
2020   - seqFile.read(buffer, bytes);
2021   - for (int i=0; i<bytes; i+=2) {
2022   - buffer[i/2] = buffer[i];
2023   - }
2024   - buffer[bytes/2] = '\0';
2025   - }
2026   -
2027   -protected:
2028   - std::ifstream seqFile;
2029   - QQueue<int> seekPos;
2030   - int width, height, numChan, imgSizeBytes, trueImgSizeBytes, numFrames;
2031   - QString imgFormat;
2032   - TemplateList annotations;
2033   -};
2034   -BR_REGISTER(Gallery, seqGallery)
2035   -
2036   -void FileGallery::init()
2037   -{
2038   - f.setFileName(file);
2039   -
2040   - Gallery::init();
2041   -}
2042   -
2043   -void FileGallery::writeOpen()
2044   -{
2045   - if (!f.isOpen() ) {
2046   - QtUtils::touchDir(f);
2047   - if (!f.open(QFile::WriteOnly))
2048   - qFatal("Failed to open %s for writing.", qPrintable(file));
2049   - }
2050   -}
2051   -
2052   -bool FileGallery::readOpen()
2053   -{
2054   - if (!f.isOpen() ) {
2055   - if (!f.exists() ) {
2056   - qFatal("File %s does not exist.", qPrintable(file));
2057   - }
2058   -
2059   - if (!f.open(QFile::ReadOnly))
2060   - qFatal("Failed to open %s for reading.", qPrintable(file));
2061   - return true;
2062   - }
2063   - return false;
2064   -}
2065   -
2066   -qint64 FileGallery::totalSize()
2067   -{
2068   - readOpen();
2069   - return f.size();
2070   -}
2071   -
2072   -
2073   -} // namespace br
2074   -
2075   -#include "gallery.moc"
openbr/plugins/gallery/arff.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/opencvutils.h>
  3 +
  4 +namespace br
  5 +{
  6 +
  7 +/*!
  8 + * \ingroup galleries
  9 + * \brief Weka ARFF file format.
  10 + * \author Josh Klontz \cite jklontz
  11 + * http://weka.wikispaces.com/ARFF+%28stable+version%29
  12 + */
  13 +class arffGallery : public Gallery
  14 +{
  15 + Q_OBJECT
  16 + QFile arffFile;
  17 +
  18 + TemplateList readBlock(bool *done)
  19 + {
  20 + (void) done;
  21 + qFatal("Not implemented.");
  22 + return TemplateList();
  23 + }
  24 +
  25 + void write(const Template &t)
  26 + {
  27 + if (!arffFile.isOpen()) {
  28 + arffFile.setFileName(file.name);
  29 + arffFile.open(QFile::WriteOnly);
  30 + arffFile.write("% OpenBR templates\n"
  31 + "@RELATION OpenBR\n"
  32 + "\n");
  33 +
  34 + const int dimensions = t.m().rows * t.m().cols;
  35 + for (int i=0; i<dimensions; i++)
  36 + arffFile.write(qPrintable("@ATTRIBUTE v" + QString::number(i) + " REAL\n"));
  37 + arffFile.write(qPrintable("@ATTRIBUTE class string\n"));
  38 +
  39 + arffFile.write("\n@DATA\n");
  40 + }
  41 +
  42 + arffFile.write(qPrintable(OpenCVUtils::matrixToStringList(t).join(',')));
  43 + arffFile.write(qPrintable(",'" + t.file.get<QString>("Label") + "'\n"));
  44 + }
  45 +};
  46 +
  47 +BR_REGISTER(Gallery, arffGallery)
  48 +
  49 +} // namespace br
  50 +
  51 +#include "gallery/arff.moc"
... ...
openbr/plugins/gallery/binary.cpp 0 → 100644
  1 +#include <QJsonObject>
  2 +#include <QJsonParseError>
  3 +
  4 +#include <openbr/plugins/openbr_internal.h>
  5 +#include <openbr/core/qtutils.h>
  6 +#include <openbr/universal_template.h>
  7 +
  8 +namespace br
  9 +{
  10 +
  11 +class BinaryGallery : public Gallery
  12 +{
  13 + Q_OBJECT
  14 +
  15 + void init()
  16 + {
  17 + const QString baseName = file.baseName();
  18 +
  19 + if (baseName == "stdin") {
  20 +#ifdef _WIN32
  21 + if(_setmode(_fileno(stdin), _O_BINARY) == -1)
  22 + qFatal("Failed to set stdin to binary mode!");
  23 +#endif // _WIN32
  24 +
  25 + gallery.open(stdin, QFile::ReadOnly);
  26 + } else if (baseName == "stdout") {
  27 +#ifdef _WIN32
  28 + if(_setmode(_fileno(stdout), _O_BINARY) == -1)
  29 + qFatal("Failed to set stdout to binary mode!");
  30 +#endif // _WIN32
  31 +
  32 + gallery.open(stdout, QFile::WriteOnly);
  33 + } else if (baseName == "stderr") {
  34 +#ifdef _WIN32
  35 + if(_setmode(_fileno(stderr), _O_BINARY) == -1)
  36 + qFatal("Failed to set stderr to binary mode!");
  37 +#endif // _WIN32
  38 +
  39 + gallery.open(stderr, QFile::WriteOnly);
  40 + } else {
  41 + // Defer opening the file, in the general case we don't know if we
  42 + // need read or write mode yet
  43 + return;
  44 + }
  45 + stream.setDevice(&gallery);
  46 + }
  47 +
  48 + void readOpen()
  49 + {
  50 + if (!gallery.isOpen()) {
  51 + gallery.setFileName(file);
  52 + if (!gallery.exists())
  53 + qFatal("File %s does not exist", qPrintable(gallery.fileName()));
  54 +
  55 + QFile::OpenMode mode = QFile::ReadOnly;
  56 + if (!gallery.open(mode))
  57 + qFatal("Can't open gallery: %s for reading", qPrintable(gallery.fileName()));
  58 + stream.setDevice(&gallery);
  59 + }
  60 + }
  61 +
  62 + void writeOpen()
  63 + {
  64 + if (!gallery.isOpen()) {
  65 + gallery.setFileName(file);
  66 +
  67 + // Do we remove the pre-existing gallery?
  68 + if (file.get<bool>("remove"))
  69 + gallery.remove();
  70 + QtUtils::touchDir(gallery);
  71 + QFile::OpenMode mode = QFile::WriteOnly;
  72 +
  73 + // Do we append?
  74 + if (file.get<bool>("append"))
  75 + mode |= QFile::Append;
  76 +
  77 + if (!gallery.open(mode))
  78 + qFatal("Can't open gallery: %s for writing", qPrintable(gallery.fileName()));
  79 + stream.setDevice(&gallery);
  80 + }
  81 + }
  82 +
  83 + TemplateList readBlock(bool *done)
  84 + {
  85 + readOpen();
  86 + if (gallery.atEnd())
  87 + gallery.seek(0);
  88 +
  89 + TemplateList templates;
  90 + while ((templates.size() < readBlockSize) && !gallery.atEnd()) {
  91 + const Template t = readTemplate();
  92 + if (!t.isEmpty() || !t.file.isNull()) {
  93 + templates.append(t);
  94 + templates.last().file.set("progress", position());
  95 + }
  96 +
  97 + // Special case for pipes where we want to process data as soon as it is available
  98 + if (gallery.isSequential())
  99 + break;
  100 + }
  101 +
  102 + *done = gallery.atEnd();
  103 + return templates;
  104 + }
  105 +
  106 + void write(const Template &t)
  107 + {
  108 + writeOpen();
  109 + writeTemplate(t);
  110 + if (gallery.isSequential())
  111 + gallery.flush();
  112 + }
  113 +
  114 +protected:
  115 + QFile gallery;
  116 + QDataStream stream;
  117 +
  118 + qint64 totalSize()
  119 + {
  120 + readOpen();
  121 + return gallery.size();
  122 + }
  123 +
  124 + qint64 position()
  125 + {
  126 + return gallery.pos();
  127 + }
  128 +
  129 + virtual Template readTemplate() = 0;
  130 + virtual void writeTemplate(const Template &t) = 0;
  131 +};
  132 +
  133 +/*!
  134 + * \ingroup galleries
  135 + * \brief A binary gallery.
  136 + *
  137 + * Designed to be a literal translation of templates to disk.
  138 + * Compatible with TemplateList::fromBuffer.
  139 + * \author Josh Klontz \cite jklontz
  140 + */
  141 +class galGallery : public BinaryGallery
  142 +{
  143 + Q_OBJECT
  144 +
  145 + Template readTemplate()
  146 + {
  147 + Template t;
  148 + stream >> t;
  149 + return t;
  150 + }
  151 +
  152 + void writeTemplate(const Template &t)
  153 + {
  154 + if (t.isEmpty() && t.file.isNull())
  155 + return;
  156 + else if (t.file.fte)
  157 + stream << Template(t.file); // only write metadata for failure to enroll
  158 + else
  159 + stream << t;
  160 + }
  161 +};
  162 +
  163 +BR_REGISTER(Gallery, galGallery)
  164 +
  165 +/*!
  166 + * \ingroup galleries
  167 + * \brief A contiguous array of br_universal_template.
  168 + * \author Josh Klontz \cite jklontz
  169 + */
  170 +class utGallery : public BinaryGallery
  171 +{
  172 + Q_OBJECT
  173 +
  174 + Template readTemplate()
  175 + {
  176 + Template t;
  177 + br_universal_template ut;
  178 + if (gallery.read((char*)&ut, sizeof(br_universal_template)) == sizeof(br_universal_template)) {
  179 + QByteArray data(ut.urlSize + ut.fvSize, Qt::Uninitialized);
  180 + char *dst = data.data();
  181 + qint64 bytesNeeded = ut.urlSize + ut.fvSize;
  182 + while (bytesNeeded > 0) {
  183 + qint64 bytesRead = gallery.read(dst, bytesNeeded);
  184 + if (bytesRead <= 0) {
  185 + qDebug() << gallery.errorString();
  186 + qFatal("Unexepected EOF while reading universal template data, needed: %d more of: %d bytes.", int(bytesNeeded), int(ut.urlSize + ut.fvSize));
  187 + }
  188 + bytesNeeded -= bytesRead;
  189 + dst += bytesRead;
  190 + }
  191 +
  192 + t.file.set("ImageID", QVariant(QByteArray((const char*)ut.imageID, 16).toHex()));
  193 + t.file.set("AlgorithmID", ut.algorithmID);
  194 + t.file.set("URL", QString(data.data()));
  195 + char *dataStart = data.data() + ut.urlSize;
  196 + uint32_t dataSize = ut.fvSize;
  197 + if ((ut.algorithmID <= -1) && (ut.algorithmID >= -3)) {
  198 + t.file.set("FrontalFace", QRectF(ut.x, ut.y, ut.width, ut.height));
  199 + uint32_t *rightEyeX = reinterpret_cast<uint32_t*>(dataStart);
  200 + dataStart += sizeof(uint32_t);
  201 + uint32_t *rightEyeY = reinterpret_cast<uint32_t*>(dataStart);
  202 + dataStart += sizeof(uint32_t);
  203 + uint32_t *leftEyeX = reinterpret_cast<uint32_t*>(dataStart);
  204 + dataStart += sizeof(uint32_t);
  205 + uint32_t *leftEyeY = reinterpret_cast<uint32_t*>(dataStart);
  206 + dataStart += sizeof(uint32_t);
  207 + dataSize -= sizeof(uint32_t)*4;
  208 + t.file.set("First_Eye", QPointF(*rightEyeX, *rightEyeY));
  209 + t.file.set("Second_Eye", QPointF(*leftEyeX, *leftEyeY));
  210 + } else {
  211 + t.file.set("X", ut.x);
  212 + t.file.set("Y", ut.y);
  213 + t.file.set("Width", ut.width);
  214 + t.file.set("Height", ut.height);
  215 + }
  216 + t.file.set("Label", ut.label);
  217 + t.append(cv::Mat(1, dataSize, CV_8UC1, dataStart).clone() /* We don't want a shallow copy! */);
  218 + } else {
  219 + if (!gallery.atEnd())
  220 + qFatal("Failed to read universal template header!");
  221 + }
  222 + return t;
  223 + }
  224 +
  225 + void writeTemplate(const Template &t)
  226 + {
  227 + const QByteArray imageID = QByteArray::fromHex(t.file.get<QByteArray>("ImageID", QByteArray(32, '0')));
  228 + if (imageID.size() != 16)
  229 + qFatal("Expected 16-byte ImageID, got: %d bytes.", imageID.size());
  230 +
  231 + const int32_t algorithmID = (t.isEmpty() || t.file.fte) ? 0 : t.file.get<int32_t>("AlgorithmID");
  232 + const QByteArray url = t.file.get<QString>("URL", t.file.name).toLatin1();
  233 +
  234 + uint32_t x = 0, y = 0, width = 0, height = 0;
  235 + QByteArray header;
  236 + if ((algorithmID <= -1) && (algorithmID >= -3)) {
  237 + const QRectF frontalFace = t.file.get<QRectF>("FrontalFace");
  238 + x = frontalFace.x();
  239 + y = frontalFace.y();
  240 + width = frontalFace.width();
  241 + height = frontalFace.height();
  242 +
  243 + const QPointF firstEye = t.file.get<QPointF>("First_Eye");
  244 + const QPointF secondEye = t.file.get<QPointF>("Second_Eye");
  245 + const uint32_t rightEyeX = firstEye.x();
  246 + const uint32_t rightEyeY = firstEye.y();
  247 + const uint32_t leftEyeX = secondEye.x();
  248 + const uint32_t leftEyeY = secondEye.y();
  249 +
  250 + header.append((const char*)&rightEyeX, sizeof(uint32_t));
  251 + header.append((const char*)&rightEyeY, sizeof(uint32_t));
  252 + header.append((const char*)&leftEyeX , sizeof(uint32_t));
  253 + header.append((const char*)&leftEyeY , sizeof(uint32_t));
  254 + } else {
  255 + x = t.file.get<uint32_t>("X", 0);
  256 + y = t.file.get<uint32_t>("Y", 0);
  257 + width = t.file.get<uint32_t>("Width", 0);
  258 + height = t.file.get<uint32_t>("Height", 0);
  259 + }
  260 + const uint32_t label = t.file.get<uint32_t>("Label", 0);
  261 +
  262 + gallery.write(imageID);
  263 + gallery.write((const char*) &algorithmID, sizeof(int32_t));
  264 + gallery.write((const char*) &x , sizeof(uint32_t));
  265 + gallery.write((const char*) &y , sizeof(uint32_t));
  266 + gallery.write((const char*) &width , sizeof(uint32_t));
  267 + gallery.write((const char*) &height , sizeof(uint32_t));
  268 + gallery.write((const char*) &label , sizeof(uint32_t));
  269 +
  270 + const uint32_t urlSize = url.size() + 1;
  271 + gallery.write((const char*) &urlSize, sizeof(uint32_t));
  272 +
  273 + const uint32_t signatureSize = (algorithmID == 0) ? 0 : t.m().rows * t.m().cols * t.m().elemSize();
  274 + const uint32_t fvSize = header.size() + signatureSize;
  275 + gallery.write((const char*) &fvSize, sizeof(uint32_t));
  276 +
  277 + gallery.write((const char*) url.data(), urlSize);
  278 + if (algorithmID != 0) {
  279 + gallery.write(header);
  280 + gallery.write((const char*) t.m().data, signatureSize);
  281 + }
  282 + }
  283 +};
  284 +
  285 +BR_REGISTER(Gallery, utGallery)
  286 +
  287 +/*!
  288 + * \ingroup galleries
  289 + * \brief Newline-separated URLs.
  290 + * \author Josh Klontz \cite jklontz
  291 + */
  292 +class urlGallery : public BinaryGallery
  293 +{
  294 + Q_OBJECT
  295 +
  296 + Template readTemplate()
  297 + {
  298 + Template t;
  299 + const QString url = QString::fromLocal8Bit(gallery.readLine()).simplified();
  300 + if (!url.isEmpty())
  301 + t.file.set("URL", url);
  302 + return t;
  303 + }
  304 +
  305 + void writeTemplate(const Template &t)
  306 + {
  307 + const QString url = t.file.get<QString>("URL", t.file.name);
  308 + if (!url.isEmpty()) {
  309 + gallery.write(qPrintable(url));
  310 + gallery.write("\n");
  311 + }
  312 + }
  313 +};
  314 +
  315 +BR_REGISTER(Gallery, urlGallery)
  316 +
  317 +/*!
  318 + * \ingroup galleries
  319 + * \brief Newline-separated JSON objects.
  320 + * \author Josh Klontz \cite jklontz
  321 + */
  322 +class jsonGallery : public BinaryGallery
  323 +{
  324 + Q_OBJECT
  325 +
  326 + Template readTemplate()
  327 + {
  328 + QJsonParseError error;
  329 + const QByteArray line = gallery.readLine().simplified();
  330 + if (line.isEmpty())
  331 + return Template();
  332 + File file = QJsonDocument::fromJson(line, &error).object().toVariantMap();
  333 + if (error.error != QJsonParseError::NoError) {
  334 + qWarning("Couldn't parse: %s\n", line.data());
  335 + qFatal("%s\n", qPrintable(error.errorString()));
  336 + }
  337 + return file;
  338 + }
  339 +
  340 + void writeTemplate(const Template &t)
  341 + {
  342 + const QByteArray json = QJsonDocument(QJsonObject::fromVariantMap(t.file.localMetadata())).toJson().replace('\n', "");
  343 + if (!json.isEmpty()) {
  344 + gallery.write(json);
  345 + gallery.write("\n");
  346 + }
  347 + }
  348 +};
  349 +
  350 +BR_REGISTER(Gallery, jsonGallery)
  351 +
  352 +} // namespace br
  353 +
  354 +#include "gallery/binary.moc"
... ...
openbr/plugins/gallery/crawl.cpp 0 → 100644
  1 +#include <QStandardPaths>
  2 +
  3 +#include <openbr/plugins/openbr_internal.h>
  4 +
  5 +namespace br
  6 +{
  7 +
  8 +/*!
  9 + * \ingroup galleries
  10 + * \brief Crawl a root location for image files.
  11 + * \author Josh Klontz \cite jklontz
  12 + */
  13 +class crawlGallery : public Gallery
  14 +{
  15 + Q_OBJECT
  16 + Q_PROPERTY(bool autoRoot READ get_autoRoot WRITE set_autoRoot RESET reset_autoRoot STORED false)
  17 + Q_PROPERTY(int depth READ get_depth WRITE set_depth RESET reset_depth STORED false)
  18 + Q_PROPERTY(bool depthFirst READ get_depthFirst WRITE set_depthFirst RESET reset_depthFirst STORED false)
  19 + Q_PROPERTY(int images READ get_images WRITE set_images RESET reset_images STORED false)
  20 + Q_PROPERTY(bool json READ get_json WRITE set_json RESET reset_json STORED false)
  21 + Q_PROPERTY(int timeLimit READ get_timeLimit WRITE set_timeLimit RESET reset_timeLimit STORED false)
  22 + BR_PROPERTY(bool, autoRoot, false)
  23 + BR_PROPERTY(int, depth, INT_MAX)
  24 + BR_PROPERTY(bool, depthFirst, false)
  25 + BR_PROPERTY(int, images, INT_MAX)
  26 + BR_PROPERTY(bool, json, false)
  27 + BR_PROPERTY(int, timeLimit, INT_MAX)
  28 +
  29 + QTime elapsed;
  30 + TemplateList templates;
  31 +
  32 + void crawl(QFileInfo url, int currentDepth = 0)
  33 + {
  34 + if ((templates.size() >= images) || (currentDepth >= depth) || (elapsed.elapsed()/1000 >= timeLimit))
  35 + return;
  36 +
  37 + if (url.filePath().startsWith("file://"))
  38 + url = QFileInfo(url.filePath().mid(7));
  39 +
  40 + if (url.isDir()) {
  41 + const QDir dir(url.absoluteFilePath());
  42 + const QFileInfoList files = dir.entryInfoList(QDir::Files);
  43 + const QFileInfoList subdirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
  44 + foreach (const QFileInfo &first, depthFirst ? subdirs : files)
  45 + crawl(first, currentDepth + 1);
  46 + foreach (const QFileInfo &second, depthFirst ? files : subdirs)
  47 + crawl(second, currentDepth + 1);
  48 + } else if (url.isFile()) {
  49 + const QString suffix = url.suffix();
  50 + if ((suffix == "bmp") || (suffix == "jpg") || (suffix == "jpeg") || (suffix == "png") || (suffix == "tiff")) {
  51 + File f;
  52 + if (json) f.set("URL", "file://"+url.canonicalFilePath());
  53 + else f.name = "file://"+url.canonicalFilePath();
  54 + templates.append(f);
  55 + }
  56 + }
  57 + }
  58 +
  59 + void init()
  60 + {
  61 + elapsed.start();
  62 + const QString root = file.name.mid(0, file.name.size()-6); // Remove .crawl suffix";
  63 + if (!root.isEmpty()) {
  64 + crawl(root);
  65 + } else {
  66 + if (autoRoot) {
  67 + foreach (const QString &path, QStandardPaths::standardLocations(QStandardPaths::HomeLocation))
  68 + crawl(path);
  69 + } else {
  70 + QFile file;
  71 + file.open(stdin, QFile::ReadOnly);
  72 + while (!file.atEnd()) {
  73 + const QString url = QString::fromLocal8Bit(file.readLine()).simplified();
  74 + if (!url.isEmpty())
  75 + crawl(url);
  76 + }
  77 + }
  78 + }
  79 + }
  80 +
  81 + TemplateList readBlock(bool *done)
  82 + {
  83 + *done = true;
  84 + return templates;
  85 + }
  86 +
  87 + void write(const Template &)
  88 + {
  89 + qFatal("Not supported");
  90 + }
  91 +};
  92 +
  93 +BR_REGISTER(Gallery, crawlGallery)
  94 +
  95 +} // namespace br
  96 +
  97 +#include "gallery/crawl.moc"
... ...