Commit 81f98a0a858a060220dc40dfd7d3e1326b46ff2f
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
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
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
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
openbr/plugins/pp4.cpp renamed to openbr/plugins/classification/pp4.cpp
openbr/plugins/pp5.cpp renamed to openbr/plugins/classification/pp5.cpp
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
openbr/plugins/cluster/kmeans.cpp
openbr/plugins/cluster/knn.cpp
openbr/plugins/cluster/lognn.cpp
openbr/plugins/cluster/randomcentroids.cpp
openbr/plugins/eigen3.cmake renamed to openbr/plugins/cmake/eigen3.cmake
| ... | ... | @@ -2,6 +2,8 @@ set(BR_WITH_EIGEN3 ON CACHE BOOL "Build Eigen3 plugins") |
| 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 "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 "Use Java Code") |
| 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 "Build with LibLinear") |
| 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 "Build with Likely") |
| 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 "Build with Neurotec Biometric 4") |
| 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 "Build with PittPatt 4") |
| 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 "Build with PittPatt 5") |
| 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
openbr/plugins/stasm4.cmake renamed to openbr/plugins/cmake/stasm4.cmake
| ... | ... | @@ -2,7 +2,6 @@ set(BR_WITH_STASM4 OFF CACHE BOOL "Build with Stasm") |
| 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
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
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
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
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
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
openbr/plugins/distance/attribute.cpp
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
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
openbr/plugins/distance/dist.cpp
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
openbr/plugins/distance/halfbyteL1.cpp
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
openbr/plugins/distance/keypointmatcher.cpp
openbr/plugins/distance/l1.cpp
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
openbr/plugins/distance/online.cpp
openbr/plugins/distance/pipe.cpp
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
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
openbr/plugins/format/csv.cpp
openbr/plugins/format/ebts.cpp
openbr/plugins/format/lffs.cpp
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
openbr/plugins/format/mtx.cpp
openbr/plugins/format/null.cpp
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
openbr/plugins/format/scores.cpp
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
openbr/plugins/format/xml.cpp
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 ®exp, 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("&")); | |
| 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" | ... | ... |