Commit 40b8933df3fc1355305961c5bd0d99de8f9eca9d
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
62 changed files
with
1010 additions
and
282 deletions
.gitignore
| 1 | ### Repository Specific ### | 1 | ### Repository Specific ### |
| 2 | 3rdparty/LatentSDK* | 2 | 3rdparty/LatentSDK* |
| 3 | 3rdparty/pittpatt* | 3 | 3rdparty/pittpatt* |
| 4 | +3rdparty/cvmatio | ||
| 4 | data/*/img | 5 | data/*/img |
| 5 | data/*/vid | 6 | data/*/vid |
| 6 | data/PCSO/* | 7 | data/PCSO/* |
| @@ -39,4 +40,10 @@ scripts/results | @@ -39,4 +40,10 @@ scripts/results | ||
| 39 | ### autogenerated sigsets ### | 40 | ### autogenerated sigsets ### |
| 40 | data/INRIAPerson/sigset | 41 | data/INRIAPerson/sigset |
| 41 | data/KTH/sigset | 42 | data/KTH/sigset |
| 43 | +data/CaltechPedestrians/annotations | ||
| 44 | +data/CaltechPedestrians/*.xml | ||
| 42 | 45 | ||
| 46 | +### Sublime ### | ||
| 47 | +*.check_cache | ||
| 48 | +*.sublime-project | ||
| 49 | +*.sublime-workspace |
CMakeLists.txt
| @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 2.8.9) | @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 2.8.9) | ||
| 4 | # Global settings | 4 | # Global settings |
| 5 | set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr") | 5 | set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr") |
| 6 | set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") | 6 | set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") |
| 7 | +set(BR_THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty") | ||
| 7 | set(CMAKE_AUTOMOC ON) | 8 | set(CMAKE_AUTOMOC ON) |
| 8 | set(CPACK_PACKAGE_NAME "OpenBR") | 9 | set(CPACK_PACKAGE_NAME "OpenBR") |
| 9 | set(CPACK_PACKAGE_VENDOR "OpenBiometrics") | 10 | set(CPACK_PACKAGE_VENDOR "OpenBiometrics") |
| @@ -90,6 +91,18 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS}) | @@ -90,6 +91,18 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS}) | ||
| 90 | # Find Alphanum | 91 | # Find Alphanum |
| 91 | find_package(Alphanum REQUIRED) | 92 | find_package(Alphanum REQUIRED) |
| 92 | 93 | ||
| 94 | +# Find cvmatio (if using it) | ||
| 95 | +set(BR_WITH_CVMATIO OFF CACHE BOOL "Build with cvmatio library to read Matlab data files (required to use Caltech Pedestrians dataset)") | ||
| 96 | +if(${BR_WITH_CVMATIO}) | ||
| 97 | + find_package(cvmatio REQUIRED) | ||
| 98 | + add_definitions(-DCVMATIO) | ||
| 99 | + add_subdirectory(${CVMATIO_DIR}) | ||
| 100 | + include_directories(${CVMATIO_DIR}/include) | ||
| 101 | + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${CVMATIO_DIR}/src/MatlabIO.cpp) | ||
| 102 | + link_directories(${CVMATIO_LIB_DIR}) | ||
| 103 | + set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} cvmatio) | ||
| 104 | +endif() | ||
| 105 | + | ||
| 93 | # Compiler flags | 106 | # Compiler flags |
| 94 | if(UNIX) | 107 | if(UNIX) |
| 95 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-strict-overflow -fvisibility=hidden -fno-omit-frame-pointer") | 108 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-strict-overflow -fvisibility=hidden -fno-omit-frame-pointer") |
README.md
| @@ -14,4 +14,3 @@ To optionally check out a particular [tagged release](https://github.com/biometr | @@ -14,4 +14,3 @@ To optionally check out a particular [tagged release](https://github.com/biometr | ||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | [](https://bitdeli.com/free "Bitdeli Badge") | 16 | [](https://bitdeli.com/free "Bitdeli Badge") |
| 17 | - |
app/CMakeLists.txt
app/br/br.cpp
| @@ -158,12 +158,17 @@ public: | @@ -158,12 +158,17 @@ public: | ||
| 158 | } else if (!strcmp(fun, "plotMetadata")) { | 158 | } else if (!strcmp(fun, "plotMetadata")) { |
| 159 | check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); | 159 | check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); |
| 160 | br_plot_metadata(parc-1, parv, parv[parc-1], true); | 160 | br_plot_metadata(parc-1, parv, parv[parc-1], true); |
| 161 | + } else if (!strcmp(fun, "deduplicate")) { | ||
| 162 | + check(parc == 3, "Incorrect parameter count for 'deduplicate'."); | ||
| 163 | + br_deduplicate(parv[0], parv[1], parv[2]); | ||
| 161 | } | 164 | } |
| 162 | 165 | ||
| 163 | // Miscellaneous | 166 | // Miscellaneous |
| 164 | else if (!strcmp(fun, "help")) { | 167 | else if (!strcmp(fun, "help")) { |
| 165 | check(parc == 0, "No parameters expected for 'help'."); | 168 | check(parc == 0, "No parameters expected for 'help'."); |
| 166 | help(); | 169 | help(); |
| 170 | + } else if (!strcmp(fun, "gui")) { | ||
| 171 | + // Do nothing because we checked for this flag prior to initialization | ||
| 167 | } else if (!strcmp(fun, "objects")) { | 172 | } else if (!strcmp(fun, "objects")) { |
| 168 | check(parc <= 2, "Incorrect parameter count for 'objects'."); | 173 | check(parc <= 2, "Incorrect parameter count for 'objects'."); |
| 169 | printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*")); | 174 | printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*")); |
| @@ -177,11 +182,10 @@ public: | @@ -177,11 +182,10 @@ public: | ||
| 177 | check(parc == 1, "Incorrect parameter count for 'daemon'."); | 182 | check(parc == 1, "Incorrect parameter count for 'daemon'."); |
| 178 | daemon = true; | 183 | daemon = true; |
| 179 | daemon_pipe = parv[0]; | 184 | daemon_pipe = parv[0]; |
| 180 | - } else if (!strcmp(fun,"slave")) { | 185 | + } else if (!strcmp(fun, "slave")) { |
| 181 | check(parc == 1, "Incorrect parameter count for 'slave'"); | 186 | check(parc == 1, "Incorrect parameter count for 'slave'"); |
| 182 | br_slave_process(parv[0]); | 187 | br_slave_process(parv[0]); |
| 183 | - } | ||
| 184 | - else if (!strcmp(fun, "exit")) { | 188 | + } else if (!strcmp(fun, "exit")) { |
| 185 | check(parc == 0, "No parameters expected for 'exit'."); | 189 | check(parc == 0, "No parameters expected for 'exit'."); |
| 186 | daemon = false; | 190 | daemon = false; |
| 187 | } else if (!strcmp(fun, "getHeader")) { | 191 | } else if (!strcmp(fun, "getHeader")) { |
| @@ -245,6 +249,7 @@ private: | @@ -245,6 +249,7 @@ private: | ||
| 245 | "\n" | 249 | "\n" |
| 246 | "==== Miscellaneous ====\n" | 250 | "==== Miscellaneous ====\n" |
| 247 | "-help\n" | 251 | "-help\n" |
| 252 | + "-gui\n" | ||
| 248 | "-objects [abstraction [implementation]]\n" | 253 | "-objects [abstraction [implementation]]\n" |
| 249 | "-about\n" | 254 | "-about\n" |
| 250 | "-version\n" | 255 | "-version\n" |
| @@ -255,7 +260,7 @@ private: | @@ -255,7 +260,7 @@ private: | ||
| 255 | 260 | ||
| 256 | int main(int argc, char *argv[]) | 261 | int main(int argc, char *argv[]) |
| 257 | { | 262 | { |
| 258 | - br_initialize(argc, argv); | 263 | + br_initialize(argc, argv, "", argc >= 2 && !strcmp(argv[1], "-gui")); |
| 259 | 264 | ||
| 260 | FakeMain *fakeMain = new FakeMain(argc, argv); | 265 | FakeMain *fakeMain = new FakeMain(argc, argv); |
| 261 | QThreadPool::globalInstance()->start(fakeMain); | 266 | QThreadPool::globalInstance()->start(fakeMain); |
data/CaltechPedestrians/README.md
0 โ 100644
| 1 | +## Caltech Pedestrians Dataset | ||
| 2 | +The Caltech Pedestrian Dataset consists of approximately 10 hours of 640x480 30Hz video taken from a vehicle driving through regular traffic in an urban environment. About 250,000 frames (in 137 approximately minute long segments) with a total of 350,000 bounding boxes and 2300 unique pedestrians were annotated. The annotation includes temporal correspondence between bounding boxes and detailed occlusion labels. | ||
| 3 | +* [Website](http://www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/) |
openbr/CMakeLists.txt
| @@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL "Build Janus implementatio | @@ -34,7 +34,7 @@ set(JANUS_BUILD_PP5_WRAPPER ${BR_WITH_PP5} CACHE BOOL "Build Janus implementatio | ||
| 34 | set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation") | 34 | set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation") |
| 35 | mark_as_advanced(JANUS_BUILD_PP5_WRAPPER) | 35 | mark_as_advanced(JANUS_BUILD_PP5_WRAPPER) |
| 36 | mark_as_advanced(JANUS_BUILD_DOCS) | 36 | mark_as_advanced(JANUS_BUILD_DOCS) |
| 37 | -set(JANUS_TEST_IMPLEMENTATION openbr) | 37 | +set(JANUS_IMPLEMENTATION openbr) |
| 38 | add_subdirectory(janus) | 38 | add_subdirectory(janus) |
| 39 | 39 | ||
| 40 | # Install | 40 | # Install |
openbr/core/bee.cpp
| @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi | @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi | ||
| 172 | qint64 read = file.read((char*)m.data, bytesExpected); | 172 | qint64 read = file.read((char*)m.data, bytesExpected); |
| 173 | if (read != bytesExpected) | 173 | if (read != bytesExpected) |
| 174 | qFatal("Invalid matrix size."); | 174 | qFatal("Invalid matrix size."); |
| 175 | + if (!file.atEnd()) | ||
| 176 | + qFatal("Expected matrix end of file."); | ||
| 175 | file.close(); | 177 | file.close(); |
| 176 | 178 | ||
| 177 | Mat result; | 179 | Mat result; |
openbr/core/cluster.cpp
| @@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
| 21 | #include <QSet> | 21 | #include <QSet> |
| 22 | #include <limits> | 22 | #include <limits> |
| 23 | #include <openbr/openbr_plugin.h> | 23 | #include <openbr/openbr_plugin.h> |
| 24 | +#include <assert.h> | ||
| 24 | 25 | ||
| 25 | #include "openbr/core/bee.h" | 26 | #include "openbr/core/bee.h" |
| 26 | #include "openbr/core/cluster.h" | 27 | #include "openbr/core/cluster.h" |
openbr/core/common.cpp
| @@ -63,3 +63,16 @@ QList<int> Common::RandSample(int n, const QSet<int> &values, bool unique) | @@ -63,3 +63,16 @@ QList<int> Common::RandSample(int n, const QSet<int> &values, bool unique) | ||
| 63 | } | 63 | } |
| 64 | return samples; | 64 | return samples; |
| 65 | } | 65 | } |
| 66 | + | ||
| 67 | +QList<float> Common::linspace(float start, float stop, int n) { | ||
| 68 | + float delta = (stop - start) / (n - 1); | ||
| 69 | + float curValue = start; | ||
| 70 | + QList<float> spaced; | ||
| 71 | + spaced.reserve(n); | ||
| 72 | + spaced.append(start); | ||
| 73 | + for (int i = 1; i < (n - 1); i++) { | ||
| 74 | + spaced.append(curValue += delta); | ||
| 75 | + } | ||
| 76 | + spaced.append(stop); | ||
| 77 | + return spaced; | ||
| 78 | +} |
openbr/core/common.h
| @@ -253,6 +253,11 @@ QList<int> RandSample(int n, const QList<T> &weights, bool unique = false) | @@ -253,6 +253,11 @@ QList<int> RandSample(int n, const QList<T> &weights, bool unique = false) | ||
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | /*! | 255 | /*! |
| 256 | + * \brief See Matlab function linspace() for documentation. | ||
| 257 | + */ | ||
| 258 | +QList<float> linspace(float start, float stop, int n); | ||
| 259 | + | ||
| 260 | +/*! | ||
| 256 | * \brief See Matlab function unique() for documentation. | 261 | * \brief See Matlab function unique() for documentation. |
| 257 | */ | 262 | */ |
| 258 | template <typename T> | 263 | template <typename T> |
openbr/core/core.cpp
| @@ -254,6 +254,56 @@ struct AlgorithmCore | @@ -254,6 +254,56 @@ struct AlgorithmCore | ||
| 254 | Globals->blockSize = old_block_size; | 254 | Globals->blockSize = old_block_size; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | + void deduplicate(const File &inputGallery, const File &outputGallery, const float threshold) | ||
| 258 | + { | ||
| 259 | + qDebug("Deduplicating %s to %s with a score threshold of %f", qPrintable(inputGallery.flat()), qPrintable(outputGallery.flat()), threshold); | ||
| 260 | + | ||
| 261 | + if (distance.isNull()) qFatal("Null distance."); | ||
| 262 | + | ||
| 263 | + QScopedPointer<Gallery> i; | ||
| 264 | + FileList inputFiles; | ||
| 265 | + retrieveOrEnroll(inputGallery, i, inputFiles); | ||
| 266 | + | ||
| 267 | + TemplateList t = i->read(); | ||
| 268 | + | ||
| 269 | + Output *o = Output::make(QString("buffer.tail[selfSimilar,threshold=%1,atLeast=0]").arg(QString::number(threshold)),inputFiles,inputFiles); | ||
| 270 | + | ||
| 271 | + // Compare to global tail output | ||
| 272 | + distance->compare(t,t,o); | ||
| 273 | + | ||
| 274 | + delete o; | ||
| 275 | + | ||
| 276 | + QString buffer(Globals->buffer); | ||
| 277 | + | ||
| 278 | + QStringList tail = buffer.split("\n"); | ||
| 279 | + | ||
| 280 | + // Remove header | ||
| 281 | + tail.removeFirst(); | ||
| 282 | + | ||
| 283 | + QStringList toRemove; | ||
| 284 | + foreach(const QString &s, tail) | ||
| 285 | + toRemove.append(s.split(',').at(1)); | ||
| 286 | + | ||
| 287 | + QSet<QString> duplicates = QSet<QString>::fromList(toRemove); | ||
| 288 | + | ||
| 289 | + QStringList fileNames = inputFiles.names(); | ||
| 290 | + | ||
| 291 | + QList<int> indices; | ||
| 292 | + foreach(const QString &d, duplicates) | ||
| 293 | + indices.append(fileNames.indexOf(d)); | ||
| 294 | + | ||
| 295 | + std::sort(indices.begin(),indices.end(),std::greater<float>()); | ||
| 296 | + | ||
| 297 | + qDebug("\n%d duplicates removed.", indices.size()); | ||
| 298 | + | ||
| 299 | + for (int i=0; i<indices.size(); i++) | ||
| 300 | + inputFiles.removeAt(indices[i]); | ||
| 301 | + | ||
| 302 | + QScopedPointer<Gallery> og(Gallery::make(outputGallery)); | ||
| 303 | + | ||
| 304 | + og->writeBlock(inputFiles); | ||
| 305 | + } | ||
| 306 | + | ||
| 257 | void compare(File targetGallery, File queryGallery, File output) | 307 | void compare(File targetGallery, File queryGallery, File output) |
| 258 | { | 308 | { |
| 259 | qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), | 309 | qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), |
| @@ -499,6 +549,14 @@ void br::Cat(const QStringList &inputGalleries, const QString &outputGallery) | @@ -499,6 +549,14 @@ void br::Cat(const QStringList &inputGalleries, const QString &outputGallery) | ||
| 499 | } | 549 | } |
| 500 | } | 550 | } |
| 501 | 551 | ||
| 552 | +void br::Deduplicate(const File &inputGallery, const File &outputGallery, const QString &threshold) | ||
| 553 | +{ | ||
| 554 | + bool ok; | ||
| 555 | + float thresh = threshold.toFloat(&ok); | ||
| 556 | + if (ok) AlgorithmManager::getAlgorithm(inputGallery.get<QString>("algorithm"))->deduplicate(inputGallery, outputGallery, thresh); | ||
| 557 | + else qFatal("Unable to convert deduplication threshold to float."); | ||
| 558 | +} | ||
| 559 | + | ||
| 502 | QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess) | 560 | QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess) |
| 503 | { | 561 | { |
| 504 | if (!preprocess) | 562 | if (!preprocess) |
openbr/core/eigenutils.cpp
| @@ -54,3 +54,16 @@ void printEigen(Eigen::MatrixXd X) { | @@ -54,3 +54,16 @@ void printEigen(Eigen::MatrixXd X) { | ||
| 54 | qDebug() << str; | 54 | qDebug() << str; |
| 55 | } | 55 | } |
| 56 | } | 56 | } |
| 57 | +void printEigen(Eigen::MatrixXf X) { | ||
| 58 | + for (int i = 0; i < X.rows(); i++) { | ||
| 59 | + QString str; | ||
| 60 | + for (int j = 0; j < X.cols(); j++) { | ||
| 61 | + str.append(QString::number(X(i,j)) + " "); | ||
| 62 | + } | ||
| 63 | + qDebug() << str; | ||
| 64 | + } | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +void printSize(Eigen::MatrixXf X) { | ||
| 68 | + qDebug() << "Rows=" << X.rows() << "\tCols=" << X.cols(); | ||
| 69 | +} |
openbr/core/eigenutils.h
| @@ -26,6 +26,8 @@ void writeEigen(Eigen::MatrixXd X, QString filename); | @@ -26,6 +26,8 @@ void writeEigen(Eigen::MatrixXd X, QString filename); | ||
| 26 | void writeEigen(Eigen::VectorXd X, QString filename); | 26 | void writeEigen(Eigen::VectorXd X, QString filename); |
| 27 | void writeEigen(Eigen::VectorXf X, QString filename); | 27 | void writeEigen(Eigen::VectorXf X, QString filename); |
| 28 | void printEigen(Eigen::MatrixXd X); | 28 | void printEigen(Eigen::MatrixXd X); |
| 29 | +void printEigen(Eigen::MatrixXf X); | ||
| 30 | +void printSize(Eigen::MatrixXf X); | ||
| 29 | 31 | ||
| 30 | template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> | 32 | template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> |
| 31 | inline QDataStream &operator<<(QDataStream &stream, const Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > &mat) | 33 | inline QDataStream &operator<<(QDataStream &stream, const Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > &mat) |
openbr/core/opencvutils.cpp
| @@ -15,7 +15,9 @@ | @@ -15,7 +15,9 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/highgui/highgui.hpp> | 17 | #include <opencv2/highgui/highgui.hpp> |
| 18 | +#include <opencv2/highgui/highgui_c.h> | ||
| 18 | #include <opencv2/imgproc/imgproc.hpp> | 19 | #include <opencv2/imgproc/imgproc.hpp> |
| 20 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 19 | #include <openbr/openbr_plugin.h> | 21 | #include <openbr/openbr_plugin.h> |
| 20 | 22 | ||
| 21 | #include "opencvutils.h" | 23 | #include "opencvutils.h" |
openbr/core/opencvutils.h
openbr/gui/tail.cpp
openbr/gui/utility.cpp
| 1 | #include <limits> | 1 | #include <limits> |
| 2 | #include <vector> | 2 | #include <vector> |
| 3 | +#include <assert.h> | ||
| 3 | #include <opencv2/imgproc/imgproc.hpp> | 4 | #include <opencv2/imgproc/imgproc.hpp> |
| 5 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 4 | #include "utility.h" | 6 | #include "utility.h" |
| 5 | 7 | ||
| 6 | using namespace cv; | 8 | using namespace cv; |
openbr/janus.cpp
| @@ -3,140 +3,138 @@ | @@ -3,140 +3,138 @@ | ||
| 3 | #endif | 3 | #endif |
| 4 | 4 | ||
| 5 | #include "janus.h" | 5 | #include "janus.h" |
| 6 | +#include "janus_io.h" | ||
| 6 | #include "openbr_plugin.h" | 7 | #include "openbr_plugin.h" |
| 7 | 8 | ||
| 8 | -// Use the provided default implementation of some functions | ||
| 9 | -#include "janus/src/janus.cpp" | ||
| 10 | - | ||
| 11 | using namespace br; | 9 | using namespace br; |
| 12 | 10 | ||
| 13 | static QSharedPointer<Transform> transform; | 11 | static QSharedPointer<Transform> transform; |
| 14 | static QSharedPointer<Distance> distance; | 12 | static QSharedPointer<Distance> distance; |
| 15 | 13 | ||
| 14 | +size_t janus_max_template_size() | ||
| 15 | +{ | ||
| 16 | + return 33554432; // 32 MB | ||
| 17 | +} | ||
| 18 | + | ||
| 16 | janus_error janus_initialize(const char *sdk_path, const char *model_file) | 19 | janus_error janus_initialize(const char *sdk_path, const char *model_file) |
| 17 | { | 20 | { |
| 18 | int argc = 1; | 21 | int argc = 1; |
| 19 | const char *argv[1] = { "janus" }; | 22 | const char *argv[1] = { "janus" }; |
| 20 | Context::initialize(argc, (char**)argv, sdk_path); | 23 | Context::initialize(argc, (char**)argv, sdk_path); |
| 21 | QString algorithm = model_file; | 24 | QString algorithm = model_file; |
| 22 | - if (algorithm.isEmpty()) algorithm = "Cvt(Gray)+Affine(88,88,0.25,0.35)+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>:ByteL1"; | ||
| 23 | - transform = Transform::fromAlgorithm(algorithm, false); | ||
| 24 | - distance = Distance::fromAlgorithm(algorithm); | 25 | + if (algorithm.isEmpty()) { |
| 26 | + transform = Transform::fromAlgorithm("Cvt(Gray)+Affine(88,88,0.25,0.35)+<FaceRecognitionExtraction>+<FaceRecognitionEmbedding>+<FaceRecognitionQuantization>", false); | ||
| 27 | + distance = Distance::fromAlgorithm("FaceRecognition"); | ||
| 28 | + } else if (algorithm == "PP5") { | ||
| 29 | + transform.reset(Transform::make("PP5Enroll", NULL)); | ||
| 30 | + distance.reset(Distance::make("PP5Compare", NULL)); | ||
| 31 | + } else { | ||
| 32 | + transform = Transform::fromAlgorithm(algorithm, false); | ||
| 33 | + distance = Distance::fromAlgorithm(algorithm); | ||
| 34 | + } | ||
| 25 | return JANUS_SUCCESS; | 35 | return JANUS_SUCCESS; |
| 26 | } | 36 | } |
| 27 | 37 | ||
| 28 | janus_error janus_finalize() | 38 | janus_error janus_finalize() |
| 29 | { | 39 | { |
| 40 | + transform.reset(); | ||
| 41 | + distance.reset(); | ||
| 30 | Context::finalize(); | 42 | Context::finalize(); |
| 31 | return JANUS_SUCCESS; | 43 | return JANUS_SUCCESS; |
| 32 | } | 44 | } |
| 33 | 45 | ||
| 34 | -struct janus_incomplete_template_type | ||
| 35 | -{ | ||
| 36 | - QList<cv::Mat> data; | ||
| 37 | -}; | 46 | +struct janus_template_type : public Template |
| 47 | +{}; | ||
| 38 | 48 | ||
| 39 | -janus_error janus_initialize_template(janus_incomplete_template *incomplete_template) | 49 | +janus_error janus_initialize_template(janus_template *template_) |
| 40 | { | 50 | { |
| 41 | - *incomplete_template = new janus_incomplete_template_type(); | 51 | + *template_ = new janus_template_type(); |
| 42 | return JANUS_SUCCESS; | 52 | return JANUS_SUCCESS; |
| 43 | } | 53 | } |
| 44 | 54 | ||
| 45 | -janus_error janus_add_image(const janus_image image, const janus_attribute_list attributes, janus_incomplete_template incomplete_template) | 55 | +janus_error janus_augment(const janus_image image, const janus_attribute_list attributes, janus_template template_) |
| 46 | { | 56 | { |
| 47 | Template t; | 57 | Template t; |
| 48 | t.append(cv::Mat(image.height, | 58 | t.append(cv::Mat(image.height, |
| 49 | image.width, | 59 | image.width, |
| 50 | - image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC1, | 60 | + image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC3, |
| 51 | image.data)); | 61 | image.data)); |
| 52 | for (size_t i=0; i<attributes.size; i++) | 62 | for (size_t i=0; i<attributes.size; i++) |
| 53 | t.file.set(janus_attribute_to_string(attributes.attributes[i]), attributes.values[i]); | 63 | t.file.set(janus_attribute_to_string(attributes.attributes[i]), attributes.values[i]); |
| 54 | 64 | ||
| 55 | - if (!t.file.contains("JANUS_RIGHT_EYE_X") || | ||
| 56 | - !t.file.contains("JANUS_RIGHT_EYE_Y") || | ||
| 57 | - !t.file.contains("JANUS_LEFT_EYE_X") || | ||
| 58 | - !t.file.contains("JANUS_LEFT_EYE_Y")) | 65 | + if (!t.file.contains("RIGHT_EYE_X") || |
| 66 | + !t.file.contains("RIGHT_EYE_Y") || | ||
| 67 | + !t.file.contains("LEFT_EYE_X") || | ||
| 68 | + !t.file.contains("LEFT_EYE_Y")) | ||
| 59 | return JANUS_SUCCESS; | 69 | return JANUS_SUCCESS; |
| 60 | 70 | ||
| 61 | - t.file.set("Affine_0", QPointF(t.file.get<float>("JANUS_RIGHT_EYE_X"), t.file.get<float>("JANUS_RIGHT_EYE_Y"))); | ||
| 62 | - t.file.set("Affine_1", QPointF(t.file.get<float>("JANUS_LEFT_EYE_X"), t.file.get<float>("JANUS_LEFT_EYE_Y"))); | 71 | + t.file.set("Affine_0", QPointF(t.file.get<float>("RIGHT_EYE_X"), t.file.get<float>("RIGHT_EYE_Y"))); |
| 72 | + t.file.set("Affine_1", QPointF(t.file.get<float>("LEFT_EYE_X"), t.file.get<float>("LEFT_EYE_Y"))); | ||
| 63 | Template u; | 73 | Template u; |
| 64 | transform->project(t, u); | 74 | transform->project(t, u); |
| 65 | - incomplete_template->data.append(u); | 75 | + template_->append(u); |
| 66 | return JANUS_SUCCESS; | 76 | return JANUS_SUCCESS; |
| 67 | } | 77 | } |
| 68 | 78 | ||
| 69 | -janus_error janus_finalize_template(janus_incomplete_template incomplete_template, janus_template template_, size_t *bytes) | 79 | +janus_error janus_finalize_template(janus_template template_, janus_flat_template flat_template, size_t *bytes) |
| 70 | { | 80 | { |
| 71 | - size_t templateBytes = 0; | ||
| 72 | - size_t numTemplates = 0; | ||
| 73 | - *bytes = sizeof(templateBytes) + sizeof(numTemplates); | ||
| 74 | - janus_template pos = template_ + *bytes; | ||
| 75 | - | ||
| 76 | - foreach (const cv::Mat &m, incomplete_template->data) { | 81 | + foreach (const cv::Mat &m, *template_) { |
| 77 | assert(m.isContinuous()); | 82 | assert(m.isContinuous()); |
| 78 | - const size_t currentTemplateBytes = m.rows * m.cols * m.elemSize(); | ||
| 79 | - if (templateBytes == 0) | ||
| 80 | - templateBytes = currentTemplateBytes; | ||
| 81 | - if (templateBytes != currentTemplateBytes) | ||
| 82 | - return JANUS_UNKNOWN_ERROR; | ||
| 83 | - if (*bytes + templateBytes > janus_max_template_size()) | 83 | + const size_t templateBytes = m.rows * m.cols * m.elemSize(); |
| 84 | + if (*bytes + sizeof(size_t) + templateBytes > janus_max_template_size()) | ||
| 84 | break; | 85 | break; |
| 85 | - memcpy(pos, m.data, templateBytes); | ||
| 86 | - *bytes += templateBytes; | ||
| 87 | - pos = pos + templateBytes; | ||
| 88 | - numTemplates++; | 86 | + memcpy(flat_template, &templateBytes, sizeof(templateBytes)); |
| 87 | + flat_template += sizeof(templateBytes); | ||
| 88 | + memcpy(flat_template, m.data, templateBytes); | ||
| 89 | + flat_template += templateBytes; | ||
| 90 | + *bytes += sizeof(size_t) + templateBytes; | ||
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | - *(reinterpret_cast<size_t*>(template_)+0) = templateBytes; | ||
| 92 | - *(reinterpret_cast<size_t*>(template_)+1) = numTemplates; | ||
| 93 | - delete incomplete_template; | 93 | + delete template_; |
| 94 | return JANUS_SUCCESS; | 94 | return JANUS_SUCCESS; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | -janus_error janus_verify(const janus_template a, const size_t a_bytes, const janus_template b, const size_t b_bytes, double *similarity) | 97 | +janus_error janus_verify(const janus_flat_template a, const size_t a_bytes, const janus_flat_template b, const size_t b_bytes, double *similarity) |
| 98 | { | 98 | { |
| 99 | - (void) a_bytes; | ||
| 100 | - (void) b_bytes; | ||
| 101 | - | ||
| 102 | - size_t a_template_bytes, a_templates, b_template_bytes, b_templates; | ||
| 103 | - a_template_bytes = *(reinterpret_cast<size_t*>(a)+0); | ||
| 104 | - a_templates = *(reinterpret_cast<size_t*>(a)+1); | ||
| 105 | - b_template_bytes = *(reinterpret_cast<size_t*>(b)+0); | ||
| 106 | - b_templates = *(reinterpret_cast<size_t*>(b)+1); | ||
| 107 | - if (a_template_bytes != b_template_bytes) | ||
| 108 | - return JANUS_UNKNOWN_ERROR; | 99 | + *similarity = 0; |
| 109 | 100 | ||
| 110 | - float dist = 0; | ||
| 111 | - for (size_t i=0; i<a_templates; i++) | ||
| 112 | - for (size_t j=0; j<b_templates; j++) | ||
| 113 | - dist += distance->compare(cv::Mat(1, a_template_bytes, CV_8UC1, a+2*sizeof(size_t)+i*a_template_bytes), | ||
| 114 | - cv::Mat(1, b_template_bytes, CV_8UC1, b+2*sizeof(size_t)+i*b_template_bytes)); | ||
| 115 | - *similarity = a_templates * b_templates / dist; | ||
| 116 | - return JANUS_SUCCESS; | ||
| 117 | -} | 101 | + int comparisons = 0; |
| 102 | + janus_flat_template a_template = a; | ||
| 103 | + while (a_template < a + a_bytes) { | ||
| 104 | + const size_t a_template_bytes = *reinterpret_cast<size_t*>(a_template); | ||
| 105 | + a_template += sizeof(a_template_bytes); | ||
| 118 | 106 | ||
| 119 | -struct janus_incomplete_gallery_type | ||
| 120 | -{ | ||
| 121 | - QList< QPair<janus_template, janus_template_id> > templates; | ||
| 122 | -}; | 107 | + janus_flat_template b_template = b; |
| 108 | + while (b_template < b + b_bytes) { | ||
| 109 | + const size_t b_template_bytes = *reinterpret_cast<size_t*>(b_template); | ||
| 110 | + b_template += sizeof(b_template_bytes); | ||
| 123 | 111 | ||
| 124 | -janus_error janus_initialize_gallery(janus_incomplete_gallery *incomplete_gallery) | ||
| 125 | -{ | ||
| 126 | - *incomplete_gallery = new janus_incomplete_gallery_type(); | ||
| 127 | - return JANUS_SUCCESS; | ||
| 128 | -} | 112 | + *similarity += distance->compare(cv::Mat(1, a_template_bytes, CV_8UC1, a_template), |
| 113 | + cv::Mat(1, b_template_bytes, CV_8UC1, b_template)); | ||
| 114 | + comparisons++; | ||
| 129 | 115 | ||
| 130 | -janus_error janus_add_template(const janus_template template_, const size_t bytes, const janus_template_id template_id, janus_incomplete_gallery incomplete_gallery) | ||
| 131 | -{ | ||
| 132 | - (void) bytes; | ||
| 133 | - incomplete_gallery->templates.append(QPair<janus_template, janus_template_id>(template_, template_id)); | 116 | + b_template += b_template_bytes; |
| 117 | + } | ||
| 118 | + | ||
| 119 | + a_template += a_template_bytes; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + if (*similarity != *similarity) // True for NaN | ||
| 123 | + return JANUS_UNKNOWN_ERROR; | ||
| 124 | + | ||
| 125 | + *similarity /= comparisons; | ||
| 134 | return JANUS_SUCCESS; | 126 | return JANUS_SUCCESS; |
| 135 | } | 127 | } |
| 136 | 128 | ||
| 137 | -janus_error janus_finalize_gallery(janus_incomplete_gallery incomplete_gallery, const char *gallery_file) | 129 | +janus_error janus_enroll(const janus_template template_, const janus_template_id template_id, janus_gallery gallery) |
| 138 | { | 130 | { |
| 139 | - (void) incomplete_gallery; | ||
| 140 | - (void) gallery_file; | 131 | + template_->file.set("TEMPLATE_ID", template_id); |
| 132 | + QFile file(gallery); | ||
| 133 | + if (!file.open(QFile::WriteOnly | QFile::Append)) | ||
| 134 | + return JANUS_WRITE_ERROR; | ||
| 135 | + QDataStream stream(&file); | ||
| 136 | + stream << *template_; | ||
| 137 | + file.close(); | ||
| 138 | + delete template_; | ||
| 141 | return JANUS_SUCCESS; | 139 | return JANUS_SUCCESS; |
| 142 | } | 140 | } |
openbr/openbr.cpp
| @@ -24,6 +24,7 @@ | @@ -24,6 +24,7 @@ | ||
| 24 | #include "core/qtutils.h" | 24 | #include "core/qtutils.h" |
| 25 | #include "plugins/openbr_internal.h" | 25 | #include "plugins/openbr_internal.h" |
| 26 | #include <opencv2/highgui/highgui.hpp> | 26 | #include <opencv2/highgui/highgui.hpp> |
| 27 | +#include <opencv2/highgui/highgui_c.h> | ||
| 27 | 28 | ||
| 28 | using namespace br; | 29 | using namespace br; |
| 29 | 30 | ||
| @@ -121,9 +122,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], | @@ -121,9 +122,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], | ||
| 121 | Fuse(QtUtils::toStringList(num_input_simmats, input_simmats), normalization, fusion, output_simmat); | 122 | Fuse(QtUtils::toStringList(num_input_simmats, input_simmats), normalization, fusion, output_simmat); |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | -void br_initialize(int &argc, char *argv[], const char *sdk_path) | 125 | +void br_initialize(int &argc, char *argv[], const char *sdk_path, bool use_gui) |
| 125 | { | 126 | { |
| 126 | - Context::initialize(argc, argv, sdk_path); | 127 | + Context::initialize(argc, argv, sdk_path, use_gui); |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | void br_initialize_default() | 130 | void br_initialize_default() |
| @@ -381,8 +382,9 @@ bool br_img_is_empty(br_template tmpl) | @@ -381,8 +382,9 @@ bool br_img_is_empty(br_template tmpl) | ||
| 381 | 382 | ||
| 382 | const char* br_get_filename(br_template tmpl) | 383 | const char* br_get_filename(br_template tmpl) |
| 383 | { | 384 | { |
| 384 | - Template *t = reinterpret_cast<Template*>(tmpl); | ||
| 385 | - return t->file.name.toStdString().c_str(); | 385 | + static QByteArray buffer; |
| 386 | + buffer = reinterpret_cast<Template*>(tmpl)->file.name.toLocal8Bit(); | ||
| 387 | + return buffer.data(); | ||
| 386 | } | 388 | } |
| 387 | 389 | ||
| 388 | void br_set_filename(br_template tmpl, const char *filename) | 390 | void br_set_filename(br_template tmpl, const char *filename) |
| @@ -470,3 +472,8 @@ void br_close_gallery(br_gallery gallery) | @@ -470,3 +472,8 @@ void br_close_gallery(br_gallery gallery) | ||
| 470 | Gallery *gal = reinterpret_cast<Gallery*>(gallery); | 472 | Gallery *gal = reinterpret_cast<Gallery*>(gallery); |
| 471 | delete gal; | 473 | delete gal; |
| 472 | } | 474 | } |
| 475 | + | ||
| 476 | +void br_deduplicate(const char *input_gallery, const char *output_gallery, const char *threshold) | ||
| 477 | +{ | ||
| 478 | + br::Deduplicate(input_gallery, output_gallery, threshold); | ||
| 479 | +} |
openbr/openbr.h
| @@ -67,6 +67,17 @@ BR_EXPORT const char *br_about(); | @@ -67,6 +67,17 @@ BR_EXPORT const char *br_about(); | ||
| 67 | BR_EXPORT void br_cat(int num_input_galleries, const char *input_galleries[], const char *output_gallery); | 67 | BR_EXPORT void br_cat(int num_input_galleries, const char *input_galleries[], const char *output_gallery); |
| 68 | 68 | ||
| 69 | /*! | 69 | /*! |
| 70 | + * \brief Removes duplicate templates in a gallery. | ||
| 71 | + * \param input_gallery Gallery to be deduplicated. | ||
| 72 | + * \param output_gallery Deduplicated gallery. | ||
| 73 | + * \param threshold Comparisons with a match score >= this value are designated to be duplicates. | ||
| 74 | + * \note If a gallery contains n duplicates, the first n-1 duplicates in the gallery will be removed and the nth will be kept. | ||
| 75 | + * \note Users are encouraged to use binary gallery formats as the entire gallery is read into memory in one call to Gallery::read. | ||
| 76 | + */ | ||
| 77 | + | ||
| 78 | +BR_EXPORT void br_deduplicate(const char *input_gallery, const char *output_gallery, const char *threshold); | ||
| 79 | + | ||
| 80 | +/*! | ||
| 70 | * \brief Clusters one or more similarity matrices into a list of subjects. | 81 | * \brief Clusters one or more similarity matrices into a list of subjects. |
| 71 | * | 82 | * |
| 72 | * A similarity matrix is a type of br::Output. The current clustering algorithm is a simplified implementation of \cite zhu11. | 83 | * A similarity matrix is a type of br::Output. The current clustering algorithm is a simplified implementation of \cite zhu11. |
| @@ -213,7 +224,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], | @@ -213,7 +224,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], | ||
| 213 | * \brief Wraps br::Context::initialize() | 224 | * \brief Wraps br::Context::initialize() |
| 214 | * \see br_finalize | 225 | * \see br_finalize |
| 215 | */ | 226 | */ |
| 216 | -BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = ""); | 227 | +BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = "", bool use_gui = false); |
| 217 | /*! | 228 | /*! |
| 218 | * \brief Wraps br::Context::initialize() with default arguments. | 229 | * \brief Wraps br::Context::initialize() with default arguments. |
| 219 | * \see br_finalize | 230 | * \see br_finalize |
openbr/openbr_plugin.cpp
| @@ -44,12 +44,6 @@ using namespace cv; | @@ -44,12 +44,6 @@ using namespace cv; | ||
| 44 | 44 | ||
| 45 | Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState) | 45 | Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState) |
| 46 | 46 | ||
| 47 | -// Some globals used to transfer data to Context::messageHandler so that | ||
| 48 | -// we can restart the process if we try and fail to create a QApplication. | ||
| 49 | -static bool creating_qapp = false; | ||
| 50 | -static int * argc_ptr = NULL; | ||
| 51 | -static char ** argv_ptr = NULL; | ||
| 52 | - | ||
| 53 | /* File - public methods */ | 47 | /* File - public methods */ |
| 54 | // Note that the convention for displaying metadata is as follows: | 48 | // Note that the convention for displaying metadata is as follows: |
| 55 | // [] for lists in which argument order does not matter (e.g. [FTO=false, Index=0]), | 49 | // [] for lists in which argument order does not matter (e.g. [FTO=false, Index=0]), |
| @@ -848,13 +842,7 @@ int br::Context::blocks(int size) const | @@ -848,13 +842,7 @@ int br::Context::blocks(int size) const | ||
| 848 | 842 | ||
| 849 | bool br::Context::contains(const QString &name) | 843 | bool br::Context::contains(const QString &name) |
| 850 | { | 844 | { |
| 851 | - QByteArray bytes = name.toLocal8Bit(); | ||
| 852 | - const char * c_name = bytes.constData(); | ||
| 853 | - | ||
| 854 | - for (int i=0; i<metaObject()->propertyCount(); i++) | ||
| 855 | - if (!strcmp(c_name, metaObject()->property(i).name())) | ||
| 856 | - return true; | ||
| 857 | - return false; | 845 | + return property(qPrintable(name)).isValid(); |
| 858 | } | 846 | } |
| 859 | 847 | ||
| 860 | void br::Context::printStatus() | 848 | void br::Context::printStatus() |
| @@ -907,42 +895,30 @@ bool br::Context::checkSDKPath(const QString &sdkPath) | @@ -907,42 +895,30 @@ bool br::Context::checkSDKPath(const QString &sdkPath) | ||
| 907 | // We create our own when the user hasn't | 895 | // We create our own when the user hasn't |
| 908 | static QCoreApplication *application = NULL; | 896 | static QCoreApplication *application = NULL; |
| 909 | 897 | ||
| 910 | -void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool use_gui) | 898 | +void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useGui) |
| 911 | { | 899 | { |
| 912 | - for (int i=0; i < argc; i ++) | ||
| 913 | - { | ||
| 914 | - if (strcmp("-useGui", argv[i]) == 0) { | ||
| 915 | - const char * val = i+1 < argc ? argv[i+1] : ""; | ||
| 916 | - if (strcmp(val, "false") ==0 || strcmp(val, "0") == 0) | ||
| 917 | - use_gui = false; | ||
| 918 | - break; | ||
| 919 | - } | ||
| 920 | - } | ||
| 921 | - | ||
| 922 | qInstallMessageHandler(messageHandler); | 900 | qInstallMessageHandler(messageHandler); |
| 923 | 901 | ||
| 902 | + QString sep; | ||
| 903 | +#ifndef _WIN32 | ||
| 904 | + useGui = useGui && (getenv("DISPLAY") != NULL); | ||
| 905 | + sep = ":"; | ||
| 906 | +#else | ||
| 907 | + sep = ";"; | ||
| 908 | +#endif // not _WIN32 | ||
| 909 | + | ||
| 924 | // We take in argc as a reference due to: | 910 | // We take in argc as a reference due to: |
| 925 | // https://bugreports.qt-project.org/browse/QTBUG-5637 | 911 | // https://bugreports.qt-project.org/browse/QTBUG-5637 |
| 926 | // QApplication should be initialized before anything else. | 912 | // QApplication should be initialized before anything else. |
| 927 | // Since we can't ensure that it gets deleted last, we never delete it. | 913 | // Since we can't ensure that it gets deleted last, we never delete it. |
| 928 | if (QCoreApplication::instance() == NULL) { | 914 | if (QCoreApplication::instance() == NULL) { |
| 929 | #ifndef BR_EMBEDDED | 915 | #ifndef BR_EMBEDDED |
| 930 | - if (use_gui) { | ||
| 931 | - // Set up variables to be used in the message handler if this fails. | ||
| 932 | - // Just so you know, we | ||
| 933 | - creating_qapp = true; | ||
| 934 | - argc_ptr = &argc; | ||
| 935 | - argv_ptr = argv; | ||
| 936 | - | ||
| 937 | - application = new QApplication(argc, argv); | ||
| 938 | - creating_qapp = false; | ||
| 939 | - } | ||
| 940 | - else { | ||
| 941 | - application = new QCoreApplication(argc, argv); | ||
| 942 | - } | ||
| 943 | -#else | 916 | + if (useGui) application = new QApplication(argc, argv); |
| 917 | + else application = new QCoreApplication(argc, argv); | ||
| 918 | +#else // not BR_EMBEDDED | ||
| 919 | + useGui = false; | ||
| 944 | application = new QCoreApplication(argc, argv); | 920 | application = new QCoreApplication(argc, argv); |
| 945 | -#endif | 921 | +#endif // BR_EMBEDDED |
| 946 | } | 922 | } |
| 947 | 923 | ||
| 948 | QCoreApplication::setOrganizationName(COMPANY_NAME); | 924 | QCoreApplication::setOrganizationName(COMPANY_NAME); |
| @@ -965,14 +941,14 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool use_ | @@ -965,14 +941,14 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool use_ | ||
| 965 | 941 | ||
| 966 | Globals = new Context(); | 942 | Globals = new Context(); |
| 967 | Globals->init(File()); | 943 | Globals->init(File()); |
| 968 | - Globals->useGui = use_gui; | ||
| 969 | - | 944 | + Globals->useGui = useGui; |
| 970 | 945 | ||
| 971 | Common::seedRNG(); | 946 | Common::seedRNG(); |
| 972 | 947 | ||
| 973 | // Search for SDK | 948 | // Search for SDK |
| 974 | if (sdkPath.isEmpty()) { | 949 | if (sdkPath.isEmpty()) { |
| 975 | QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); | 950 | QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); |
| 951 | + checkPaths << QString(getenv("PATH")).split(sep, QString::SkipEmptyParts); | ||
| 976 | 952 | ||
| 977 | bool foundSDK = false; | 953 | bool foundSDK = false; |
| 978 | foreach (const QString &path, checkPaths) { | 954 | foreach (const QString &path, checkPaths) { |
| @@ -1035,26 +1011,6 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte | @@ -1035,26 +1011,6 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte | ||
| 1035 | static QMutex generalLock; | 1011 | static QMutex generalLock; |
| 1036 | QMutexLocker locker(&generalLock); | 1012 | QMutexLocker locker(&generalLock); |
| 1037 | 1013 | ||
| 1038 | - // If we are trying to create a QApplication, and get a fatal, then restart the process | ||
| 1039 | - // with useGui set to 0. | ||
| 1040 | - if (creating_qapp && type == QtFatalMsg) | ||
| 1041 | - { | ||
| 1042 | - // re-launch process with useGui = 0 | ||
| 1043 | - std::cout << "Failed to initialize gui, restarting with -useGui 0" << std::endl; | ||
| 1044 | - QStringList arguments; | ||
| 1045 | - arguments.append("-useGui"); | ||
| 1046 | - arguments.append("0"); | ||
| 1047 | - for (int i=1; i < *argc_ptr; i++) | ||
| 1048 | - { | ||
| 1049 | - arguments.append(argv_ptr[i]); | ||
| 1050 | - } | ||
| 1051 | - // QProcess::execute blocks until the other process completes. | ||
| 1052 | - QProcess::execute(argv_ptr[0], arguments); | ||
| 1053 | - // have to unlock this for some reason | ||
| 1054 | - locker.unlock(); | ||
| 1055 | - std::exit(0); | ||
| 1056 | - } | ||
| 1057 | - | ||
| 1058 | QString txt; | 1014 | QString txt; |
| 1059 | if (type == QtDebugMsg) { | 1015 | if (type == QtDebugMsg) { |
| 1060 | if (Globals->quiet) return; | 1016 | if (Globals->quiet) return; |
| @@ -1076,8 +1032,13 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte | @@ -1076,8 +1032,13 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte | ||
| 1076 | Globals->logFile.flush(); | 1032 | Globals->logFile.flush(); |
| 1077 | } | 1033 | } |
| 1078 | 1034 | ||
| 1079 | - if (type == QtFatalMsg) | 1035 | + if (type == QtFatalMsg) { |
| 1036 | +#ifdef _WIN32 | ||
| 1037 | + QCoreApplication::quit(); // abort() hangs the console on Windows for some reason related to the event loop not being exited | ||
| 1038 | +#else // not _WIN32 | ||
| 1080 | abort(); // We abort so we can get a stack trace back to the code that triggered the message. | 1039 | abort(); // We abort so we can get a stack trace back to the code that triggered the message. |
| 1040 | +#endif // _WIN32 | ||
| 1041 | + } | ||
| 1081 | } | 1042 | } |
| 1082 | 1043 | ||
| 1083 | Context *br::Globals = NULL; | 1044 | Context *br::Globals = NULL; |
openbr/openbr_plugin.h
| @@ -41,6 +41,7 @@ | @@ -41,6 +41,7 @@ | ||
| 41 | #include <QVector> | 41 | #include <QVector> |
| 42 | #include <opencv2/core/core.hpp> | 42 | #include <opencv2/core/core.hpp> |
| 43 | #include <openbr/openbr.h> | 43 | #include <openbr/openbr.h> |
| 44 | +#include <assert.h> | ||
| 44 | 45 | ||
| 45 | /*! | 46 | /*! |
| 46 | * \defgroup cpp_plugin_sdk C++ Plugin SDK | 47 | * \defgroup cpp_plugin_sdk C++ Plugin SDK |
| @@ -794,12 +795,12 @@ public: | @@ -794,12 +795,12 @@ public: | ||
| 794 | * By default <tt>share/openbr/openbr.bib</tt> will be searched for relative to: | 795 | * By default <tt>share/openbr/openbr.bib</tt> will be searched for relative to: |
| 795 | * -# The working directory | 796 | * -# The working directory |
| 796 | * -# The executable's location | 797 | * -# The executable's location |
| 797 | - * \param use_gui Create a QApplication instead of a QCoreApplication. | 798 | + * \param useGui Create a QApplication instead of a QCoreApplication. |
| 798 | * \note Tiggers \em abort() on failure to locate <tt>share/openbr/openbr.bib</tt>. | 799 | * \note Tiggers \em abort() on failure to locate <tt>share/openbr/openbr.bib</tt>. |
| 799 | * \note <a href="http://qt-project.org/">Qt</a> users should instead call this <i>after</i> initializing QApplication. | 800 | * \note <a href="http://qt-project.org/">Qt</a> users should instead call this <i>after</i> initializing QApplication. |
| 800 | * \see finalize | 801 | * \see finalize |
| 801 | */ | 802 | */ |
| 802 | - static void initialize(int &argc, char *argv[], QString sdkPath = "", bool use_gui = true); | 803 | + static void initialize(int &argc, char *argv[], QString sdkPath = "", bool useGui = true); |
| 803 | 804 | ||
| 804 | /*! | 805 | /*! |
| 805 | * \brief Call \em once at the end of the application to deallocate global variables. | 806 | * \brief Call \em once at the end of the application to deallocate global variables. |
| @@ -1371,6 +1372,14 @@ BR_EXPORT void Convert(const File &fileType, const File &inputFile, const File & | @@ -1371,6 +1372,14 @@ BR_EXPORT void Convert(const File &fileType, const File &inputFile, const File & | ||
| 1371 | */ | 1372 | */ |
| 1372 | BR_EXPORT void Cat(const QStringList &inputGalleries, const QString &outputGallery); | 1373 | BR_EXPORT void Cat(const QStringList &inputGalleries, const QString &outputGallery); |
| 1373 | 1374 | ||
| 1375 | +/*! | ||
| 1376 | + * \brief Deduplicate a gallery. | ||
| 1377 | + * \param inputGallery Gallery to deduplicate. | ||
| 1378 | + * \param outputGallery Gallery to store the deduplicated result. | ||
| 1379 | + * \param threshold Match score threshold to determine duplicates. | ||
| 1380 | + */ | ||
| 1381 | +BR_EXPORT void Deduplicate(const File &inputGallery, const File &outputGallery, const QString &threshold); | ||
| 1382 | + | ||
| 1374 | /*! @}*/ | 1383 | /*! @}*/ |
| 1375 | 1384 | ||
| 1376 | } // namespace br | 1385 | } // namespace br |
openbr/plugins/algorithms.cpp
| @@ -50,6 +50,9 @@ class AlgorithmsInitializer : public Initializer | @@ -50,6 +50,9 @@ class AlgorithmsInitializer : public Initializer | ||
| 50 | Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)"); | 50 | Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)"); |
| 51 | Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)"); | 51 | Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)"); |
| 52 | Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)"); | 52 | Globals->abbreviations.insert("AgeGenderDemo", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+Expand+<FaceClassificationRegistration>+<FaceClassificationExtraction>+<AgeRegressor>/<GenderClassifier>+Discard+RestoreMat(original)+Draw(inPlace=true)+DrawPropertiesPoint([Age,Gender],Affine_0,inPlace=true)+SaveMat(original)+Discard+Contract+RestoreMat(original)+FPSCalc+Show(false,[AvgFPS,Age,Gender])+Discard)"); |
| 53 | + Globals->abbreviations.insert("ShowOpticalFlowField", "Stream(SaveMat(original)+AggregateFrames(2)+OpticalFlow(useMagnitude=false)+Grid(100,100)+DrawOpticalFlow+FPSLimit(30)+Show(false)+Discard)"); | ||
| 54 | + Globals->abbreviations.insert("ShowOpticalFlowMagnitude", "Stream(AggregateFrames(2)+OpticalFlow+Normalize(Range,false,0,255)+Cvt(Color)+Draw+FPSLimit(30)+Show(false)+Discard)"); | ||
| 55 | + Globals->abbreviations.insert("ShowMotionSegmentation", "Stream(DropFrames(5)+AggregateFrames(2)+OpticalFlow+CvtUChar+WatershedSegmentation+DrawSegmentation+Draw+FPSLimit(30)+Show(false)+Discard)"); | ||
| 53 | 56 | ||
| 54 | Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); | 57 | Globals->abbreviations.insert("HOG", "Stream(DropFrames(5)+Cvt(Gray)+Grid(5,5)+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)+SVM"); |
| 55 | Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); | 58 | Globals->abbreviations.insert("HOF", "Stream(DropFrames(5)+Grid(5,5)+AggregateFrames(2)+OpticalFlow+ROIFromPts(32,24)+Expand+Resize(32,32)+Gradient+RectRegions+Bin(0,360,8)+Hist(8)+Cat)+Contract+CatRows+KMeans(500)+Hist(500)"); |
| @@ -76,7 +79,7 @@ class AlgorithmsInitializer : public Initializer | @@ -76,7 +79,7 @@ class AlgorithmsInitializer : public Initializer | ||
| 76 | Globals->abbreviations.insert("ColoredLBP", "Open+Affine(128,128,0.37,0.45)+Cvt(Gray)+Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+ColoredU2"); | 79 | Globals->abbreviations.insert("ColoredLBP", "Open+Affine(128,128,0.37,0.45)+Cvt(Gray)+Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+ColoredU2"); |
| 77 | 80 | ||
| 78 | // Transforms | 81 | // Transforms |
| 79 | - Globals->abbreviations.insert("FaceDetection", "(Open+Cvt(Gray)+Cascade(FrontalFace))"); | 82 | + Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)"); |
| 80 | Globals->abbreviations.insert("DenseLBP", "(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))"); | 83 | Globals->abbreviations.insert("DenseLBP", "(Blur(1.1)+Gamma(0.2)+DoG(1,2)+ContrastEq(0.1,10)+LBP(1,2)+RectRegions(8,8,6,6)+Hist(59))"); |
| 81 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); | 84 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); |
| 82 | Globals->abbreviations.insert("FaceRecognitionRegistration", "(ASEFEyes+Affine(88,88,0.25,0.35)+DownsampleTraining(FTE(DFFS),instances=1))"); | 85 | Globals->abbreviations.insert("FaceRecognitionRegistration", "(ASEFEyes+Affine(88,88,0.25,0.35)+DownsampleTraining(FTE(DFFS),instances=1))"); |
openbr/plugins/cascade.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/objdetect/objdetect.hpp> | 17 | #include <opencv2/objdetect/objdetect.hpp> |
| 18 | +//#include <opencv2/objdetect/objdetect_c.h> | ||
| 18 | #include "openbr_internal.h" | 19 | #include "openbr_internal.h" |
| 19 | #include "openbr/core/opencvutils.h" | 20 | #include "openbr/core/opencvutils.h" |
| 20 | #include "openbr/core/resource.h" | 21 | #include "openbr/core/resource.h" |
| @@ -86,11 +87,11 @@ class CascadeTransform : public UntrainableMetaTransform | @@ -86,11 +87,11 @@ class CascadeTransform : public UntrainableMetaTransform | ||
| 86 | 87 | ||
| 87 | for (int i=0; i<t.size(); i++) { | 88 | for (int i=0; i<t.size(); i++) { |
| 88 | const Mat &m = t[i]; | 89 | const Mat &m = t[i]; |
| 89 | - vector<Rect> rects; | ||
| 90 | - vector<int> rejectLevels; | ||
| 91 | - vector<double> levelWeights; | ||
| 92 | - if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, 5, (enrollAll ? 0 : CV_HAAR_FIND_BIGGEST_OBJECT) | CV_HAAR_SCALE_IMAGE, Size(minSize, minSize), Size(), true); | ||
| 93 | - else cascade->detectMultiScale(m, rects, 1.2, 5, enrollAll ? 0 : CV_HAAR_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); | 90 | + std::vector<Rect> rects; |
| 91 | + std::vector<int> rejectLevels; | ||
| 92 | + std::vector<double> levelWeights; | ||
| 93 | + if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, 5, (enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT) | CASCADE_SCALE_IMAGE, Size(minSize, minSize), Size(), true); | ||
| 94 | + else cascade->detectMultiScale(m, rects, 1.2, 5, enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); | ||
| 94 | 95 | ||
| 95 | if (!enrollAll && rects.empty()) | 96 | if (!enrollAll && rects.empty()) |
| 96 | rects.push_back(Rect(0, 0, m.cols, m.rows)); | 97 | rects.push_back(Rect(0, 0, m.cols, m.rows)); |
openbr/plugins/cvt.cpp
| @@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
| 14 | * limitations under the License. * | 14 | * limitations under the License. * |
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 18 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | #include "openbr_internal.h" | 19 | #include "openbr_internal.h" |
| 19 | #include "openbr/core/opencvutils.h" | 20 | #include "openbr/core/opencvutils.h" |
| @@ -44,7 +45,8 @@ public: | @@ -44,7 +45,8 @@ public: | ||
| 44 | Luv = CV_BGR2Luv, | 45 | Luv = CV_BGR2Luv, |
| 45 | RGB = CV_BGR2RGB, | 46 | RGB = CV_BGR2RGB, |
| 46 | XYZ = CV_BGR2XYZ, | 47 | XYZ = CV_BGR2XYZ, |
| 47 | - YCrCb = CV_BGR2YCrCb }; | 48 | + YCrCb = CV_BGR2YCrCb, |
| 49 | + Color = CV_GRAY2BGR }; | ||
| 48 | 50 | ||
| 49 | private: | 51 | private: |
| 50 | BR_PROPERTY(ColorSpace, colorSpace, Gray) | 52 | BR_PROPERTY(ColorSpace, colorSpace, Gray) |
| @@ -52,8 +54,8 @@ private: | @@ -52,8 +54,8 @@ private: | ||
| 52 | 54 | ||
| 53 | void project(const Template &src, Template &dst) const | 55 | void project(const Template &src, Template &dst) const |
| 54 | { | 56 | { |
| 55 | - if (src.m().channels() > 1) cvtColor(src, dst, colorSpace); | ||
| 56 | - else dst = src; | 57 | + if (src.m().channels() > 1 || colorSpace == CV_GRAY2BGR) cvtColor(src, dst, colorSpace); |
| 58 | + else dst = src; | ||
| 57 | 59 | ||
| 58 | if (channel != -1) { | 60 | if (channel != -1) { |
| 59 | std::vector<Mat> mv; | 61 | std::vector<Mat> mv; |
openbr/plugins/distance.cpp
| @@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
| 18 | #include <QtConcurrentRun> | 18 | #include <QtConcurrentRun> |
| 19 | #include <numeric> | 19 | #include <numeric> |
| 20 | #include <opencv2/imgproc/imgproc.hpp> | 20 | #include <opencv2/imgproc/imgproc.hpp> |
| 21 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 21 | #include "openbr_internal.h" | 22 | #include "openbr_internal.h" |
| 22 | 23 | ||
| 23 | #include "openbr/core/distance_sse.h" | 24 | #include "openbr/core/distance_sse.h" |
| @@ -61,6 +62,7 @@ private: | @@ -61,6 +62,7 @@ private: | ||
| 61 | (a.m().type() != b.m().type())) | 62 | (a.m().type() != b.m().type())) |
| 62 | return -std::numeric_limits<float>::max(); | 63 | return -std::numeric_limits<float>::max(); |
| 63 | 64 | ||
| 65 | +// TODO: this max value is never returned based on the switch / default | ||
| 64 | float result = std::numeric_limits<float>::max(); | 66 | float result = std::numeric_limits<float>::max(); |
| 65 | switch (metric) { | 67 | switch (metric) { |
| 66 | case Correlation: | 68 | case Correlation: |
| @@ -386,5 +388,67 @@ class OnlineDistance : public Distance | @@ -386,5 +388,67 @@ class OnlineDistance : public Distance | ||
| 386 | 388 | ||
| 387 | BR_REGISTER(Distance, OnlineDistance) | 389 | BR_REGISTER(Distance, OnlineDistance) |
| 388 | 390 | ||
| 391 | +/*! | ||
| 392 | + * \ingroup distances | ||
| 393 | + * \brief Attenuation function based distance from attributes | ||
| 394 | + * \author Scott Klum \cite sklum | ||
| 395 | + */ | ||
| 396 | +class AttributeDistance : public Distance | ||
| 397 | +{ | ||
| 398 | + Q_OBJECT | ||
| 399 | + Q_PROPERTY(QString attribute READ get_attribute WRITE set_attribute RESET reset_attribute STORED false) | ||
| 400 | + BR_PROPERTY(QString, attribute, QString()) | ||
| 401 | + | ||
| 402 | + float compare(const Template &target, const Template &query) const | ||
| 403 | + { | ||
| 404 | + float queryValue = query.file.get<float>(attribute); | ||
| 405 | + float targetValue = target.file.get<float>(attribute); | ||
| 406 | + | ||
| 407 | + // TODO: Set this magic number to something meaningful | ||
| 408 | + float stddev = 1; | ||
| 409 | + | ||
| 410 | + if (queryValue == targetValue) return 1; | ||
| 411 | + else return 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((targetValue-queryValue)/stddev, 2)); | ||
| 412 | + } | ||
| 413 | +}; | ||
| 414 | + | ||
| 415 | +BR_REGISTER(Distance, AttributeDistance) | ||
| 416 | + | ||
| 417 | +/*! | ||
| 418 | + * \ingroup distances | ||
| 419 | + * \brief Sum match scores across multiple distances | ||
| 420 | + * \author Scott Klum \cite sklum | ||
| 421 | + */ | ||
| 422 | +class SumDistance : public Distance | ||
| 423 | +{ | ||
| 424 | + Q_OBJECT | ||
| 425 | + Q_PROPERTY(QList<br::Distance*> distances READ get_distances WRITE set_distances RESET reset_distances) | ||
| 426 | + BR_PROPERTY(QList<br::Distance*>, distances, QList<br::Distance*>()) | ||
| 427 | + | ||
| 428 | + void train(const TemplateList &data) | ||
| 429 | + { | ||
| 430 | + QFutureSynchronizer<void> futures; | ||
| 431 | + foreach (br::Distance *distance, distances) | ||
| 432 | + futures.addFuture(QtConcurrent::run(distance, &Distance::train, data)); | ||
| 433 | + futures.waitForFinished(); | ||
| 434 | + } | ||
| 435 | + | ||
| 436 | + float compare(const Template &target, const Template &query) const | ||
| 437 | + { | ||
| 438 | + float result = 0; | ||
| 439 | + | ||
| 440 | + foreach (br::Distance *distance, distances) { | ||
| 441 | + result += distance->compare(target, query); | ||
| 442 | + | ||
| 443 | + if (result == -std::numeric_limits<float>::max()) | ||
| 444 | + return result; | ||
| 445 | + } | ||
| 446 | + | ||
| 447 | + return result; | ||
| 448 | + } | ||
| 449 | +}; | ||
| 450 | + | ||
| 451 | +BR_REGISTER(Distance, SumDistance) | ||
| 452 | + | ||
| 389 | } // namespace br | 453 | } // namespace br |
| 390 | #include "distance.moc" | 454 | #include "distance.moc" |
openbr/plugins/draw.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/highgui/highgui.hpp> | 17 | #include <opencv2/highgui/highgui.hpp> |
| 18 | +#include <opencv2/highgui/highgui_c.h> | ||
| 18 | #include <opencv2/imgproc/imgproc.hpp> | 19 | #include <opencv2/imgproc/imgproc.hpp> |
| 19 | #include <vector> | 20 | #include <vector> |
| 20 | #include "openbr_internal.h" | 21 | #include "openbr_internal.h" |
| @@ -40,10 +41,12 @@ class DrawTransform : public UntrainableTransform | @@ -40,10 +41,12 @@ class DrawTransform : public UntrainableTransform | ||
| 40 | Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false) | 41 | Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false) |
| 41 | Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) | 42 | Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) |
| 42 | Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) | 43 | Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) |
| 44 | + Q_PROPERTY(int lineThickness READ get_lineThickness WRITE set_lineThickness RESET reset_lineThickness STORED false) | ||
| 43 | BR_PROPERTY(bool, verbose, false) | 45 | BR_PROPERTY(bool, verbose, false) |
| 44 | BR_PROPERTY(bool, points, true) | 46 | BR_PROPERTY(bool, points, true) |
| 45 | BR_PROPERTY(bool, rects, true) | 47 | BR_PROPERTY(bool, rects, true) |
| 46 | BR_PROPERTY(bool, inPlace, false) | 48 | BR_PROPERTY(bool, inPlace, false) |
| 49 | + BR_PROPERTY(int, lineThickness, 1) | ||
| 47 | 50 | ||
| 48 | void project(const Template &src, Template &dst) const | 51 | void project(const Template &src, Template &dst) const |
| 49 | { | 52 | { |
| @@ -61,7 +64,7 @@ class DrawTransform : public UntrainableTransform | @@ -61,7 +64,7 @@ class DrawTransform : public UntrainableTransform | ||
| 61 | } | 64 | } |
| 62 | if (rects) { | 65 | if (rects) { |
| 63 | foreach (const Rect &rect, OpenCVUtils::toRects(src.file.namedRects() + src.file.rects())) | 66 | foreach (const Rect &rect, OpenCVUtils::toRects(src.file.namedRects() + src.file.rects())) |
| 64 | - rectangle(dst, rect, color); | 67 | + rectangle(dst, rect, color, lineThickness); |
| 65 | } | 68 | } |
| 66 | } | 69 | } |
| 67 | }; | 70 | }; |
| @@ -343,6 +346,75 @@ class AdjacentOverlayTransform : public Transform | @@ -343,6 +346,75 @@ class AdjacentOverlayTransform : public Transform | ||
| 343 | 346 | ||
| 344 | BR_REGISTER(Transform, AdjacentOverlayTransform) | 347 | BR_REGISTER(Transform, AdjacentOverlayTransform) |
| 345 | 348 | ||
| 349 | +/*! | ||
| 350 | + * \ingroup transforms | ||
| 351 | + * \brief Draw a line representing the direction and magnitude of optical flow at the specified points. | ||
| 352 | + * \author Austin Blanton \cite imaus10 | ||
| 353 | + */ | ||
| 354 | +class DrawOpticalFlow : public UntrainableTransform | ||
| 355 | +{ | ||
| 356 | + Q_OBJECT | ||
| 357 | + Q_PROPERTY(QString original READ get_original WRITE set_original RESET reset_original STORED false) | ||
| 358 | + BR_PROPERTY(QString, original, "original") | ||
| 359 | + | ||
| 360 | + void project(const Template &src, Template &dst) const | ||
| 361 | + { | ||
| 362 | + const Scalar color(0,255,0); | ||
| 363 | + Mat flow = src.m(); | ||
| 364 | + dst = src; | ||
| 365 | + if (!dst.file.contains(original)) qFatal("The original img must be saved in the metadata with SaveMat."); | ||
| 366 | + dst.m() = dst.file.get<Mat>(original); | ||
| 367 | + dst.file.remove(original); | ||
| 368 | + foreach (const Point2f &pt, OpenCVUtils::toPoints(dst.file.points())) { | ||
| 369 | + Point2f dxy = flow.at<Point2f>(pt.y, pt.x); | ||
| 370 | + Point2f newPt(pt.x+dxy.x, pt.y+dxy.y); | ||
| 371 | + line(dst, pt, newPt, color); | ||
| 372 | + } | ||
| 373 | + } | ||
| 374 | +}; | ||
| 375 | +BR_REGISTER(Transform, DrawOpticalFlow) | ||
| 376 | + | ||
| 377 | +/*! | ||
| 378 | + * \ingroup transforms | ||
| 379 | + * \brief Fill in the segmentations or draw a line between intersecting segments. | ||
| 380 | + * \author Austin Blanton \cite imaus10 | ||
| 381 | + */ | ||
| 382 | +class DrawSegmentation : public UntrainableTransform | ||
| 383 | +{ | ||
| 384 | + Q_OBJECT | ||
| 385 | + Q_PROPERTY(bool fillSegment READ get_fillSegment WRITE set_fillSegment RESET reset_fillSegment STORED false) | ||
| 386 | + BR_PROPERTY(bool, fillSegment, true) | ||
| 387 | + | ||
| 388 | + void project(const Template &src, Template &dst) const | ||
| 389 | + { | ||
| 390 | + if (!src.file.contains("SegmentsMask") || !src.file.contains("NumSegments")) qFatal("Must supply a Contours object in the metadata to drawContours."); | ||
| 391 | + Mat segments = src.file.get<Mat>("SegmentsMask"); | ||
| 392 | + int numSegments = src.file.get<int>("NumSegments"); | ||
| 393 | + | ||
| 394 | + dst.file = src.file; | ||
| 395 | + Mat drawn = fillSegment ? Mat(segments.size(), CV_8UC3, Scalar::all(0)) : src.m(); | ||
| 396 | + | ||
| 397 | + for (int i=1; i<numSegments+1; i++) { | ||
| 398 | + Mat mask = segments == i; | ||
| 399 | + if (fillSegment) { // color the whole segment | ||
| 400 | + // set to a random color - get ready for a craaaazy acid trip | ||
| 401 | + int b = theRNG().uniform(0, 255); | ||
| 402 | + int g = theRNG().uniform(0, 255); | ||
| 403 | + int r = theRNG().uniform(0, 255); | ||
| 404 | + drawn.setTo(Scalar(r,g,b), mask); | ||
| 405 | + } else { // draw lines where there's a color change | ||
| 406 | + vector<vector<Point> > contours; | ||
| 407 | + Scalar color(0,255,0); | ||
| 408 | + findContours(mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); | ||
| 409 | + drawContours(drawn, contours, -1, color); | ||
| 410 | + } | ||
| 411 | + } | ||
| 412 | + | ||
| 413 | + dst.m() = drawn; | ||
| 414 | + } | ||
| 415 | +}; | ||
| 416 | +BR_REGISTER(Transform, DrawSegmentation) | ||
| 417 | + | ||
| 346 | // TODO: re-implement EditTransform using Qt | 418 | // TODO: re-implement EditTransform using Qt |
| 347 | #if 0 | 419 | #if 0 |
| 348 | /*! | 420 | /*! |
openbr/plugins/eigen3.cpp
| @@ -302,8 +302,8 @@ class LDATransform : public Transform | @@ -302,8 +302,8 @@ class LDATransform : public Transform | ||
| 302 | Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false) | 302 | Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false) |
| 303 | Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false) | 303 | Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false) |
| 304 | Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | 304 | Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) |
| 305 | - Q_PROPERTY(bool isBinary READ get_isBinary WRITE set_isBinary RESET reset_isBinary STORED true) | ||
| 306 | - Q_PROPERTY(bool normalize READ get_normalize WRITE set_normalize RESET reset_normalize STORED true) | 305 | + Q_PROPERTY(bool isBinary READ get_isBinary WRITE set_isBinary RESET reset_isBinary STORED false) |
| 306 | + Q_PROPERTY(bool normalize READ get_normalize WRITE set_normalize RESET reset_normalize STORED false) | ||
| 307 | BR_PROPERTY(float, pcaKeep, 0.98) | 307 | BR_PROPERTY(float, pcaKeep, 0.98) |
| 308 | BR_PROPERTY(bool, pcaWhiten, false) | 308 | BR_PROPERTY(bool, pcaWhiten, false) |
| 309 | BR_PROPERTY(int, directLDA, 0) | 309 | BR_PROPERTY(int, directLDA, 0) |
| @@ -316,12 +316,6 @@ class LDATransform : public Transform | @@ -316,12 +316,6 @@ class LDATransform : public Transform | ||
| 316 | Eigen::VectorXf mean; | 316 | Eigen::VectorXf mean; |
| 317 | Eigen::MatrixXf projection; | 317 | Eigen::MatrixXf projection; |
| 318 | float stdDev; | 318 | float stdDev; |
| 319 | - bool trained; | ||
| 320 | - | ||
| 321 | - void init() | ||
| 322 | - { | ||
| 323 | - trained = false; | ||
| 324 | - } | ||
| 325 | 319 | ||
| 326 | void train(const TemplateList &_trainingSet) | 320 | void train(const TemplateList &_trainingSet) |
| 327 | { | 321 | { |
| @@ -461,9 +455,9 @@ class LDATransform : public Transform | @@ -461,9 +455,9 @@ class LDATransform : public Transform | ||
| 461 | projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose(); | 455 | projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose(); |
| 462 | dimsOut = dim2; | 456 | dimsOut = dim2; |
| 463 | 457 | ||
| 458 | + stdDev = 1; // default initialize | ||
| 464 | if (isBinary) { | 459 | if (isBinary) { |
| 465 | assert(dimsOut == 1); | 460 | assert(dimsOut == 1); |
| 466 | - TemplateList projected; | ||
| 467 | float posVal = 0; | 461 | float posVal = 0; |
| 468 | float negVal = 0; | 462 | float negVal = 0; |
| 469 | Eigen::MatrixXf results(trainingSet.size(),1); | 463 | Eigen::MatrixXf results(trainingSet.size(),1); |
| @@ -493,8 +487,6 @@ class LDATransform : public Transform | @@ -493,8 +487,6 @@ class LDATransform : public Transform | ||
| 493 | if (normalize) | 487 | if (normalize) |
| 494 | stdDev = sqrt(results.array().square().sum() / trainingSet.size()); | 488 | stdDev = sqrt(results.array().square().sum() / trainingSet.size()); |
| 495 | } | 489 | } |
| 496 | - | ||
| 497 | - trained = true; | ||
| 498 | } | 490 | } |
| 499 | 491 | ||
| 500 | void project(const Template &src, Template &dst) const | 492 | void project(const Template &src, Template &dst) const |
| @@ -508,18 +500,22 @@ class LDATransform : public Transform | @@ -508,18 +500,22 @@ class LDATransform : public Transform | ||
| 508 | // Do projection | 500 | // Do projection |
| 509 | outMap = projection.transpose() * (inMap - mean); | 501 | outMap = projection.transpose() * (inMap - mean); |
| 510 | 502 | ||
| 511 | - if (normalize && isBinary && trained) | 503 | + if (normalize && isBinary) |
| 512 | dst.m().at<float>(0,0) = dst.m().at<float>(0,0) / stdDev; | 504 | dst.m().at<float>(0,0) = dst.m().at<float>(0,0) / stdDev; |
| 513 | } | 505 | } |
| 514 | 506 | ||
| 515 | void store(QDataStream &stream) const | 507 | void store(QDataStream &stream) const |
| 516 | { | 508 | { |
| 517 | - stream << pcaKeep << directLDA << directDrop << dimsOut << mean << projection << stdDev << normalize << isBinary << trained; | 509 | + stream << pcaKeep << directLDA << directDrop << dimsOut << mean << projection; |
| 510 | + if (normalize && isBinary) | ||
| 511 | + stream << stdDev; | ||
| 518 | } | 512 | } |
| 519 | 513 | ||
| 520 | void load(QDataStream &stream) | 514 | void load(QDataStream &stream) |
| 521 | { | 515 | { |
| 522 | - stream >> pcaKeep >> directLDA >> directDrop >> dimsOut >> mean >> projection >> stdDev >> normalize >> isBinary >> trained; | 516 | + stream >> pcaKeep >> directLDA >> directDrop >> dimsOut >> mean >> projection; |
| 517 | + if (normalize && isBinary) | ||
| 518 | + stream >> stdDev; | ||
| 523 | } | 519 | } |
| 524 | }; | 520 | }; |
| 525 | 521 |
openbr/plugins/eyes.cpp
| @@ -34,6 +34,7 @@ | @@ -34,6 +34,7 @@ | ||
| 34 | */ | 34 | */ |
| 35 | 35 | ||
| 36 | #include <opencv2/imgproc/imgproc.hpp> | 36 | #include <opencv2/imgproc/imgproc.hpp> |
| 37 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 37 | #include "openbr_internal.h" | 38 | #include "openbr_internal.h" |
| 38 | #include "openbr/core/opencvutils.h" | 39 | #include "openbr/core/opencvutils.h" |
| 39 | 40 |
openbr/plugins/format.cpp
| @@ -16,10 +16,12 @@ | @@ -16,10 +16,12 @@ | ||
| 16 | 16 | ||
| 17 | #include <QDate> | 17 | #include <QDate> |
| 18 | #include <QSize> | 18 | #include <QSize> |
| 19 | +#include <QChar> | ||
| 19 | #ifndef BR_EMBEDDED | 20 | #ifndef BR_EMBEDDED |
| 20 | #include <QtXml> | 21 | #include <QtXml> |
| 21 | #endif // BR_EMBEDDED | 22 | #endif // BR_EMBEDDED |
| 22 | #include <opencv2/highgui/highgui.hpp> | 23 | #include <opencv2/highgui/highgui.hpp> |
| 24 | +#include <opencv2/highgui/highgui_c.h> | ||
| 23 | #include "openbr_internal.h" | 25 | #include "openbr_internal.h" |
| 24 | 26 | ||
| 25 | #include "openbr/core/bee.h" | 27 | #include "openbr/core/bee.h" |
| @@ -719,7 +721,7 @@ BR_REGISTER(Format, xmlFormat) | @@ -719,7 +721,7 @@ BR_REGISTER(Format, xmlFormat) | ||
| 719 | /*! | 721 | /*! |
| 720 | * \ingroup formats | 722 | * \ingroup formats |
| 721 | * \brief Reads in scores or ground truth from a text table. | 723 | * \brief Reads in scores or ground truth from a text table. |
| 722 | - * \author Josh Klontz | 724 | + * \author Josh Klontz \cite jklontz |
| 723 | * | 725 | * |
| 724 | * Example of the format: | 726 | * Example of the format: |
| 725 | * \code | 727 | * \code |
| @@ -768,6 +770,90 @@ class scoresFormat : public Format | @@ -768,6 +770,90 @@ class scoresFormat : public Format | ||
| 768 | 770 | ||
| 769 | BR_REGISTER(Format, scoresFormat) | 771 | BR_REGISTER(Format, scoresFormat) |
| 770 | 772 | ||
| 773 | +/*! | ||
| 774 | + * \ingroup formats | ||
| 775 | + * \brief Reads FBI EBTS transactions. | ||
| 776 | + * \author Scott Klum \cite sklum | ||
| 777 | + * https://www.fbibiospecs.org/ebts.html | ||
| 778 | + * \note This will fail if a binary blob contains any of the fields attempt to locate within the file | ||
| 779 | + */ | ||
| 780 | +class ebtsFormat : public Format | ||
| 781 | +{ | ||
| 782 | + Q_OBJECT | ||
| 783 | + | ||
| 784 | + QString textFieldValue(const QByteArray &byteArray, const QString &fieldNumber, int from = 0) const | ||
| 785 | + { | ||
| 786 | + // Find the field, skip the number bytes, and account for the semicolon | ||
| 787 | + int fieldPosition = byteArray.indexOf(fieldNumber, from) + fieldNumber.size() + 1; | ||
| 788 | + int sepPosition = byteArray.indexOf(QChar(0x1D),fieldPosition); | ||
| 789 | + | ||
| 790 | + return byteArray.mid(fieldPosition,sepPosition-fieldPosition); | ||
| 791 | + } | ||
| 792 | + | ||
| 793 | + Template read() const | ||
| 794 | + { | ||
| 795 | + QByteArray byteArray; | ||
| 796 | + QtUtils::readFile(file, byteArray); | ||
| 797 | + | ||
| 798 | + Template t; | ||
| 799 | + | ||
| 800 | + Mat m; | ||
| 801 | + | ||
| 802 | + // Demographics | ||
| 803 | + { | ||
| 804 | + QString name = textFieldValue(byteArray, "2.018"); | ||
| 805 | + QStringList names = name.split(','); | ||
| 806 | + t.file.set("FIRSTNAME", names.at(1)); | ||
| 807 | + t.file.set("LASTNAME", names.at(0)); | ||
| 808 | + t.file.set("DOB", textFieldValue(byteArray, "2.022").toInt()); | ||
| 809 | + t.file.set("GENDER", textFieldValue(byteArray, "2.024")); | ||
| 810 | + t.file.set("RACE", textFieldValue(byteArray, "2.025")); | ||
| 811 | + } | ||
| 812 | + | ||
| 813 | + // Mugshot (first in file used) | ||
| 814 | + // Todo: Check for face designation | ||
| 815 | + { | ||
| 816 | + const QString imageRecord = "10.001:"; | ||
| 817 | + const QString imageDataRecord = "10.999:"; | ||
| 818 | + | ||
| 819 | + int fieldPosition = byteArray.indexOf(imageRecord); | ||
| 820 | + | ||
| 821 | + if (fieldPosition != -1) { | ||
| 822 | + int sepPosition = byteArray.indexOf(QChar(0x1D),fieldPosition); | ||
| 823 | + int dataPosition = byteArray.indexOf(imageDataRecord,sepPosition); | ||
| 824 | + | ||
| 825 | + int recordBytes = byteArray.mid(fieldPosition,sepPosition-fieldPosition).toInt(); | ||
| 826 | + int headerBytes = byteArray.mid(fieldPosition,dataPosition-fieldPosition).size() + imageDataRecord.size(); | ||
| 827 | + | ||
| 828 | + QByteArray data = byteArray.mid(dataPosition+imageRecord.size(),recordBytes-headerBytes); | ||
| 829 | + | ||
| 830 | + m = imdecode(Mat(3, data.size(), CV_8UC3, data.data()), CV_LOAD_IMAGE_COLOR); | ||
| 831 | + if (!m.data) qWarning("ebtsFormat::read failed to decode image data."); | ||
| 832 | + t.m() = m; | ||
| 833 | + } else qWarning("ebtsFormat::cannot find image data within file."); | ||
| 834 | + | ||
| 835 | + } | ||
| 836 | + | ||
| 837 | + if (t.file.contains("DOB")) { | ||
| 838 | + const QDate dob = QDate::fromString(t.file.get<QString>("DOB"), "yyyyMMdd"); | ||
| 839 | + const QDate current = QDate::currentDate(); | ||
| 840 | + int age = current.year() - dob.year(); | ||
| 841 | + if (current.month() < dob.month()) age--; | ||
| 842 | + t.file.set("Age", age); | ||
| 843 | + } | ||
| 844 | + | ||
| 845 | + return t; | ||
| 846 | + } | ||
| 847 | + | ||
| 848 | + void write(const Template &t) const | ||
| 849 | + { | ||
| 850 | + (void) t; | ||
| 851 | + qFatal("Writing EBTS files is not supported."); | ||
| 852 | + } | ||
| 853 | +}; | ||
| 854 | + | ||
| 855 | +BR_REGISTER(Format, ebtsFormat) | ||
| 856 | + | ||
| 771 | } // namespace br | 857 | } // namespace br |
| 772 | 858 | ||
| 773 | #include "format.moc" | 859 | #include "format.moc" |
openbr/plugins/gallery.cpp
| @@ -32,6 +32,11 @@ | @@ -32,6 +32,11 @@ | ||
| 32 | #include "openbr/core/opencvutils.h" | 32 | #include "openbr/core/opencvutils.h" |
| 33 | #include "openbr/core/qtutils.h" | 33 | #include "openbr/core/qtutils.h" |
| 34 | 34 | ||
| 35 | +#ifdef CVMATIO | ||
| 36 | +#include "MatlabIO.hpp" | ||
| 37 | +#include "MatlabIOContainer.hpp" | ||
| 38 | +#endif | ||
| 39 | + | ||
| 35 | namespace br | 40 | namespace br |
| 36 | { | 41 | { |
| 37 | 42 | ||
| @@ -969,6 +974,74 @@ class landmarksGallery : public Gallery | @@ -969,6 +974,74 @@ class landmarksGallery : public Gallery | ||
| 969 | 974 | ||
| 970 | BR_REGISTER(Gallery, landmarksGallery) | 975 | BR_REGISTER(Gallery, landmarksGallery) |
| 971 | 976 | ||
| 977 | +#ifdef CVMATIO | ||
| 978 | + | ||
| 979 | +using namespace cv; | ||
| 980 | + | ||
| 981 | +class vbbGallery : public Gallery | ||
| 982 | +{ | ||
| 983 | + Q_OBJECT | ||
| 984 | + | ||
| 985 | + void init() | ||
| 986 | + { | ||
| 987 | + MatlabIO matio; | ||
| 988 | + QString filename = (Globals->path.isEmpty() ? "" : Globals->path + "/") + file.name; | ||
| 989 | + bool ok = matio.open(filename.toStdString(), "r"); | ||
| 990 | + if (!ok) qFatal("Couldn't open the vbb file"); | ||
| 991 | + | ||
| 992 | + vector<MatlabIOContainer> variables; | ||
| 993 | + variables = matio.read(); | ||
| 994 | + matio.close(); | ||
| 995 | + | ||
| 996 | + double vers = variables[1].data<Mat>().at<double>(0,0); | ||
| 997 | + if (vers != 1.4) qFatal("This is an old vbb version, we don't mess with that."); | ||
| 998 | + | ||
| 999 | + A = variables[0].data<vector<vector<MatlabIOContainer> > >().at(0); | ||
| 1000 | + objLists = A.at(1).data<vector<MatlabIOContainer> >(); | ||
| 1001 | + | ||
| 1002 | + // start at the first frame (duh!) | ||
| 1003 | + currFrame = 0; | ||
| 1004 | + } | ||
| 1005 | + | ||
| 1006 | + TemplateList readBlock(bool *done) | ||
| 1007 | + { | ||
| 1008 | + *done = false; | ||
| 1009 | + Template rects(file); | ||
| 1010 | + if (objLists[currFrame].typeEquals<vector<vector<MatlabIOContainer> > >()) { | ||
| 1011 | + vector<vector<MatlabIOContainer> > bbs = objLists[currFrame].data<vector<vector<MatlabIOContainer> > >(); | ||
| 1012 | + for (unsigned int i=0; i<bbs.size(); i++) { | ||
| 1013 | + vector<MatlabIOContainer> bb = bbs[i]; | ||
| 1014 | + Mat pos = bb[1].data<Mat>(); | ||
| 1015 | + double left = pos.at<double>(0,0); | ||
| 1016 | + double top = pos.at<double>(0,1); | ||
| 1017 | + double width = pos.at<double>(0,2); | ||
| 1018 | + double height = pos.at<double>(0,3); | ||
| 1019 | + rects.file.appendRect(QRectF(left, top, width, height)); | ||
| 1020 | + } | ||
| 1021 | + } | ||
| 1022 | + TemplateList tl; | ||
| 1023 | + tl.append(rects); | ||
| 1024 | + if (++currFrame == (int)objLists.size()) *done = true; | ||
| 1025 | + return tl; | ||
| 1026 | + } | ||
| 1027 | + | ||
| 1028 | + void write(const Template &t) | ||
| 1029 | + { | ||
| 1030 | + (void)t; qFatal("Not implemented"); | ||
| 1031 | + } | ||
| 1032 | + | ||
| 1033 | +private: | ||
| 1034 | + // this holds a bunch of stuff, maybe we'll use it all later | ||
| 1035 | + vector<MatlabIOContainer> A; | ||
| 1036 | + // this, a field in A, holds bounding boxes for each frame | ||
| 1037 | + vector<MatlabIOContainer> objLists; | ||
| 1038 | + int currFrame; | ||
| 1039 | +}; | ||
| 1040 | + | ||
| 1041 | +BR_REGISTER(Gallery, vbbGallery) | ||
| 1042 | + | ||
| 1043 | +#endif | ||
| 1044 | + | ||
| 972 | } // namespace br | 1045 | } // namespace br |
| 973 | 1046 | ||
| 974 | #include "gallery.moc" | 1047 | #include "gallery.moc" |
openbr/plugins/gui.cpp
| @@ -12,6 +12,7 @@ | @@ -12,6 +12,7 @@ | ||
| 12 | #include <QLineEdit> | 12 | #include <QLineEdit> |
| 13 | 13 | ||
| 14 | #include <opencv2/imgproc/imgproc.hpp> | 14 | #include <opencv2/imgproc/imgproc.hpp> |
| 15 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 15 | #include "openbr_internal.h" | 16 | #include "openbr_internal.h" |
| 16 | #include "openbr/gui/utility.h" | 17 | #include "openbr/gui/utility.h" |
| 17 | 18 |
openbr/plugins/hist.cpp
| @@ -94,7 +94,7 @@ class BinTransform : public UntrainableTransform | @@ -94,7 +94,7 @@ class BinTransform : public UntrainableTransform | ||
| 94 | } else if (channels == 2) { | 94 | } else if (channels == 2) { |
| 95 | // If there are two channels, the first is channel is assumed to be a weight vector | 95 | // If there are two channels, the first is channel is assumed to be a weight vector |
| 96 | // and the second channel contains the vectors we would like to bin. | 96 | // and the second channel contains the vectors we would like to bin. |
| 97 | - vector<Mat> mv; | 97 | + std::vector<Mat> mv; |
| 98 | cv::split(src, mv); | 98 | cv::split(src, mv); |
| 99 | weights = mv[0]; | 99 | weights = mv[0]; |
| 100 | weights.convertTo(weights, CV_32F); | 100 | weights.convertTo(weights, CV_32F); |
openbr/plugins/integral.cpp
| 1 | #include <opencv2/imgproc/imgproc.hpp> | 1 | #include <opencv2/imgproc/imgproc.hpp> |
| 2 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 2 | #include <Eigen/Core> | 3 | #include <Eigen/Core> |
| 3 | #include "openbr_internal.h" | 4 | #include "openbr_internal.h" |
| 4 | 5 | ||
| @@ -293,7 +294,7 @@ private: | @@ -293,7 +294,7 @@ private: | ||
| 293 | Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR); | 294 | Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR); |
| 294 | Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR); | 295 | Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR); |
| 295 | cartToPolar(dx, dy, magnitude, angle, true); | 296 | cartToPolar(dx, dy, magnitude, angle, true); |
| 296 | - vector<Mat> mv; | 297 | + std::vector<Mat> mv; |
| 297 | if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) { | 298 | if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) { |
| 298 | const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f)); | 299 | const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f)); |
| 299 | mv.push_back(magnitude / theoreticalMaxMagnitude); | 300 | mv.push_back(magnitude / theoreticalMaxMagnitude); |
openbr/plugins/landmarks.cpp
| @@ -290,16 +290,18 @@ class DrawDelaunayTransform : public UntrainableTransform | @@ -290,16 +290,18 @@ class DrawDelaunayTransform : public UntrainableTransform | ||
| 290 | 290 | ||
| 291 | void project(const Template &src, Template &dst) const | 291 | void project(const Template &src, Template &dst) const |
| 292 | { | 292 | { |
| 293 | - QList<Point2f> validTriangles = OpenCVUtils::toPoints(src.file.getList<QPointF>("DelaunayTriangles")); | 293 | + dst = src; |
| 294 | 294 | ||
| 295 | - // Clone the matrix do draw on it | ||
| 296 | - dst.m() = src.m().clone(); | 295 | + if (src.file.contains("DelaunayTriangles")) { |
| 296 | + QList<Point2f> validTriangles = OpenCVUtils::toPoints(src.file.getList<QPointF>("DelaunayTriangles")); | ||
| 297 | 297 | ||
| 298 | - for (int i = 0; i < validTriangles.size(); i+=3) { | ||
| 299 | - line(dst.m(), validTriangles[i], validTriangles[i+1], Scalar(0,0,0), 1); | ||
| 300 | - line(dst.m(), validTriangles[i+1], validTriangles[i+2], Scalar(0,0,0), 1); | ||
| 301 | - line(dst.m(), validTriangles[i+2], validTriangles[i], Scalar(0,0,0), 1); | ||
| 302 | - } | 298 | + // Clone the matrix do draw on it |
| 299 | + for (int i = 0; i < validTriangles.size(); i+=3) { | ||
| 300 | + line(dst, validTriangles[i], validTriangles[i+1], Scalar(0,0,0), 1); | ||
| 301 | + line(dst, validTriangles[i+1], validTriangles[i+2], Scalar(0,0,0), 1); | ||
| 302 | + line(dst, validTriangles[i+2], validTriangles[i], Scalar(0,0,0), 1); | ||
| 303 | + } | ||
| 304 | + } else qWarning("Template does not contain Delaunay triangulation."); | ||
| 303 | } | 305 | } |
| 304 | }; | 306 | }; |
| 305 | 307 |
openbr/plugins/lbp.cpp
| @@ -15,7 +15,9 @@ | @@ -15,7 +15,9 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 18 | #include <opencv2/highgui/highgui.hpp> | 19 | #include <opencv2/highgui/highgui.hpp> |
| 20 | +#include <opencv2/highgui/highgui_c.h> | ||
| 19 | #include <limits> | 21 | #include <limits> |
| 20 | #include "openbr_internal.h" | 22 | #include "openbr_internal.h" |
| 21 | 23 |
openbr/plugins/ltp.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 18 | #include <limits> | 19 | #include <limits> |
| 19 | #include "openbr_internal.h" | 20 | #include "openbr_internal.h" |
| 20 | 21 |
openbr/plugins/mask.cpp
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | ||
| 17 | #include <opencv2/imgproc/imgproc.hpp> | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | ||
| 18 | #include "openbr_internal.h" | 19 | #include "openbr_internal.h" |
| 19 | 20 | ||
| 20 | using namespace cv; | 21 | using namespace cv; |
| @@ -164,7 +165,7 @@ class LargestConvexAreaTransform : public UntrainableTransform | @@ -164,7 +165,7 @@ class LargestConvexAreaTransform : public UntrainableTransform | ||
| 164 | void project(const Template &src, Template &dst) const | 165 | void project(const Template &src, Template &dst) const |
| 165 | { | 166 | { |
| 166 | std::vector< std::vector<Point> > contours; | 167 | std::vector< std::vector<Point> > contours; |
| 167 | - findContours(src.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); | 168 | + findContours(src.m().clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); |
| 168 | double maxArea = 0; | 169 | double maxArea = 0; |
| 169 | foreach (const std::vector<Point> &contour, contours) { | 170 | foreach (const std::vector<Point> &contour, contours) { |
| 170 | std::vector<Point> hull; | 171 | std::vector<Point> hull; |
openbr/plugins/misc.cpp
| @@ -537,7 +537,7 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -537,7 +537,7 @@ class ProgressCounterTransform : public TimeVaryingTransform | ||
| 537 | { | 537 | { |
| 538 | (void) data; | 538 | (void) data; |
| 539 | float p = br_progress(); | 539 | float p = br_progress(); |
| 540 | - qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100., QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); | 540 | + qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | void init() | 543 | void init() |
openbr/plugins/motion.cpp
| @@ -23,6 +23,7 @@ class OpticalFlowTransform : public UntrainableMetaTransform | @@ -23,6 +23,7 @@ class OpticalFlowTransform : public UntrainableMetaTransform | ||
| 23 | Q_PROPERTY(int poly_n READ get_poly_n WRITE set_poly_n RESET reset_poly_n STORED false) | 23 | Q_PROPERTY(int poly_n READ get_poly_n WRITE set_poly_n RESET reset_poly_n STORED false) |
| 24 | Q_PROPERTY(double poly_sigma READ get_poly_sigma WRITE set_poly_sigma RESET reset_poly_sigma STORED false) | 24 | Q_PROPERTY(double poly_sigma READ get_poly_sigma WRITE set_poly_sigma RESET reset_poly_sigma STORED false) |
| 25 | Q_PROPERTY(int flags READ get_flags WRITE set_flags RESET reset_flags STORED false) | 25 | Q_PROPERTY(int flags READ get_flags WRITE set_flags RESET reset_flags STORED false) |
| 26 | + Q_PROPERTY(bool useMagnitude READ get_useMagnitude WRITE set_useMagnitude RESET reset_useMagnitude STORED false) | ||
| 26 | // these defaults are optimized for KTH | 27 | // these defaults are optimized for KTH |
| 27 | BR_PROPERTY(double, pyr_scale, 0.1) | 28 | BR_PROPERTY(double, pyr_scale, 0.1) |
| 28 | BR_PROPERTY(int, levels, 1) | 29 | BR_PROPERTY(int, levels, 1) |
| @@ -31,22 +32,27 @@ class OpticalFlowTransform : public UntrainableMetaTransform | @@ -31,22 +32,27 @@ class OpticalFlowTransform : public UntrainableMetaTransform | ||
| 31 | BR_PROPERTY(int, poly_n, 7) | 32 | BR_PROPERTY(int, poly_n, 7) |
| 32 | BR_PROPERTY(double, poly_sigma, 1.1) | 33 | BR_PROPERTY(double, poly_sigma, 1.1) |
| 33 | BR_PROPERTY(int, flags, 0) | 34 | BR_PROPERTY(int, flags, 0) |
| 35 | + BR_PROPERTY(bool, useMagnitude, true) | ||
| 34 | 36 | ||
| 35 | void project(const Template &src, Template &dst) const | 37 | void project(const Template &src, Template &dst) const |
| 36 | { | 38 | { |
| 37 | // get the two images put there by AggregateFrames | 39 | // get the two images put there by AggregateFrames |
| 38 | if (src.size() != 2) qFatal("Optical Flow requires two images."); | 40 | if (src.size() != 2) qFatal("Optical Flow requires two images."); |
| 39 | - Mat prevImg = src[0], nextImg = src[1], flow, flowOneCh; | 41 | + Mat prevImg = src[0], nextImg = src[1], flow; |
| 40 | if (src[0].channels() != 1) OpenCVUtils::cvtGray(src[0], prevImg); | 42 | if (src[0].channels() != 1) OpenCVUtils::cvtGray(src[0], prevImg); |
| 41 | if (src[1].channels() != 1) OpenCVUtils::cvtGray(src[1], nextImg); | 43 | if (src[1].channels() != 1) OpenCVUtils::cvtGray(src[1], nextImg); |
| 42 | calcOpticalFlowFarneback(prevImg, nextImg, flow, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags); | 44 | calcOpticalFlowFarneback(prevImg, nextImg, flow, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags); |
| 43 | 45 | ||
| 44 | - // the result is two channels | ||
| 45 | - std::vector<Mat> channels(2); | ||
| 46 | - split(flow, channels); | ||
| 47 | - magnitude(channels[0], channels[1], flowOneCh); | ||
| 48 | - | ||
| 49 | - dst += flowOneCh; | 46 | + if (useMagnitude) { |
| 47 | + // the result is two channels | ||
| 48 | + Mat flowOneCh; | ||
| 49 | + std::vector<Mat> channels(2); | ||
| 50 | + split(flow, channels); | ||
| 51 | + magnitude(channels[0], channels[1], flowOneCh); | ||
| 52 | + dst += flowOneCh; | ||
| 53 | + } else { | ||
| 54 | + dst += flow; | ||
| 55 | + } | ||
| 50 | dst.file = src.file; | 56 | dst.file = src.file; |
| 51 | } | 57 | } |
| 52 | }; | 58 | }; |
| @@ -62,7 +68,8 @@ class SubtractBackgroundTransform : public TimeVaryingTransform | @@ -62,7 +68,8 @@ class SubtractBackgroundTransform : public TimeVaryingTransform | ||
| 62 | { | 68 | { |
| 63 | Q_OBJECT | 69 | Q_OBJECT |
| 64 | 70 | ||
| 65 | - BackgroundSubtractorMOG2 mog; | 71 | + // TODO: This is broken. |
| 72 | + // BackgroundSubtractorMOG2 mog; | ||
| 66 | 73 | ||
| 67 | public: | 74 | public: |
| 68 | SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {} | 75 | SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {} |
| @@ -72,7 +79,8 @@ private: | @@ -72,7 +79,8 @@ private: | ||
| 72 | { | 79 | { |
| 73 | dst = src; | 80 | dst = src; |
| 74 | Mat mask; | 81 | Mat mask; |
| 75 | - mog(src, mask); | 82 | + // TODO: broken |
| 83 | + // mog(src, mask); | ||
| 76 | erode(mask, mask, Mat()); | 84 | erode(mask, mask, Mat()); |
| 77 | dilate(mask, mask, Mat()); | 85 | dilate(mask, mask, Mat()); |
| 78 | dst.file.set("Mask", QVariant::fromValue(mask)); | 86 | dst.file.set("Mask", QVariant::fromValue(mask)); |
| @@ -86,7 +94,8 @@ private: | @@ -86,7 +94,8 @@ private: | ||
| 86 | void finalize(TemplateList &output) | 94 | void finalize(TemplateList &output) |
| 87 | { | 95 | { |
| 88 | (void) output; | 96 | (void) output; |
| 89 | - mog = BackgroundSubtractorMOG2(); | 97 | + // TODO: Broken |
| 98 | + // mog = BackgroundSubtractorMOG2(); | ||
| 90 | } | 99 | } |
| 91 | }; | 100 | }; |
| 92 | 101 |
openbr/plugins/normalize.cpp
| @@ -60,24 +60,29 @@ class NormalizeTransform : public UntrainableTransform | @@ -60,24 +60,29 @@ class NormalizeTransform : public UntrainableTransform | ||
| 60 | 60 | ||
| 61 | Q_PROPERTY(bool ByRow READ get_ByRow WRITE set_ByRow RESET reset_ByRow STORED false) | 61 | Q_PROPERTY(bool ByRow READ get_ByRow WRITE set_ByRow RESET reset_ByRow STORED false) |
| 62 | BR_PROPERTY(bool, ByRow, false) | 62 | BR_PROPERTY(bool, ByRow, false) |
| 63 | + Q_PROPERTY(int alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) | ||
| 64 | + BR_PROPERTY(int, alpha, 1) | ||
| 65 | + Q_PROPERTY(int beta READ get_beta WRITE set_beta RESET reset_beta STORED false) | ||
| 66 | + BR_PROPERTY(int, beta, 0) | ||
| 63 | 67 | ||
| 64 | public: | 68 | public: |
| 65 | /*!< */ | 69 | /*!< */ |
| 66 | enum NormType { Inf = NORM_INF, | 70 | enum NormType { Inf = NORM_INF, |
| 67 | L1 = NORM_L1, | 71 | L1 = NORM_L1, |
| 68 | - L2 = NORM_L2 }; | 72 | + L2 = NORM_L2, |
| 73 | + Range = NORM_MINMAX }; | ||
| 69 | 74 | ||
| 70 | private: | 75 | private: |
| 71 | BR_PROPERTY(NormType, normType, L2) | 76 | BR_PROPERTY(NormType, normType, L2) |
| 72 | 77 | ||
| 73 | void project(const Template &src, Template &dst) const | 78 | void project(const Template &src, Template &dst) const |
| 74 | { | 79 | { |
| 75 | - if (!ByRow) normalize(src, dst, 1, 0, normType, CV_32F); | 80 | + if (!ByRow) normalize(src, dst, alpha, beta, normType, CV_32F); |
| 76 | else { | 81 | else { |
| 77 | dst = src; | 82 | dst = src; |
| 78 | for (int i=0; i<dst.m().rows; i++) { | 83 | for (int i=0; i<dst.m().rows; i++) { |
| 79 | Mat temp; | 84 | Mat temp; |
| 80 | - cv::normalize(dst.m().row(i), temp, 1, 0, normType); | 85 | + cv::normalize(dst.m().row(i), temp, alpha, beta, normType); |
| 81 | temp.copyTo(dst.m().row(i)); | 86 | temp.copyTo(dst.m().row(i)); |
| 82 | } | 87 | } |
| 83 | } | 88 | } |
| @@ -132,7 +137,7 @@ private: | @@ -132,7 +137,7 @@ private: | ||
| 132 | const QList<int> labels = data.indexProperty(inputVariable); | 137 | const QList<int> labels = data.indexProperty(inputVariable); |
| 133 | const int dims = m.cols; | 138 | const int dims = m.cols; |
| 134 | 139 | ||
| 135 | - vector<Mat> mv, av, bv; | 140 | + std::vector<Mat> mv, av, bv; |
| 136 | split(m, mv); | 141 | split(m, mv); |
| 137 | for (size_t c = 0; c < mv.size(); c++) { | 142 | for (size_t c = 0; c < mv.size(); c++) { |
| 138 | av.push_back(Mat(1, dims, CV_64FC1)); | 143 | av.push_back(Mat(1, dims, CV_64FC1)); |
openbr/plugins/output.cpp
| @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput | @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput | ||
| 268 | 268 | ||
| 269 | for (int i=0; i<queryFiles.size(); i++) { | 269 | for (int i=0; i<queryFiles.size(); i++) { |
| 270 | QStringList files; | 270 | QStringList files; |
| 271 | - if (simple) files.append(queryFiles[i]); | 271 | + if (simple) files.append(queryFiles[i].fileName()); |
| 272 | 272 | ||
| 273 | typedef QPair<float,int> Pair; | 273 | typedef QPair<float,int> Pair; |
| 274 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true, limit)) { | 274 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true, limit)) { |
| @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput | @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput | ||
| 276 | if (pair.first < threshold) break; | 276 | if (pair.first < threshold) break; |
| 277 | File target = targetFiles[pair.second]; | 277 | File target = targetFiles[pair.second]; |
| 278 | target.set("Score", QString::number(pair.first)); | 278 | target.set("Score", QString::number(pair.first)); |
| 279 | - if (simple) files.append(target.baseName() + " " + QString::number(pair.first)); | 279 | + if (simple) files.append(target.fileName() + " " + QString::number(pair.first)); |
| 280 | else files.append(target.flat()); | 280 | else files.append(target.flat()); |
| 281 | } | 281 | } |
| 282 | } | 282 | } |
| @@ -528,7 +528,7 @@ class tailOutput : public Output | @@ -528,7 +528,7 @@ class tailOutput : public Output | ||
| 528 | } else { | 528 | } else { |
| 529 | // General case | 529 | // General case |
| 530 | for (int k=0; k<comparisons.size(); k++) { | 530 | for (int k=0; k<comparisons.size(); k++) { |
| 531 | - if (comparisons[k].value < value) { | 531 | + if (comparisons[k].value <= value) { |
| 532 | comparisons.insert(k, Comparison(queryFiles[i], targetFiles[j], value)); | 532 | comparisons.insert(k, Comparison(queryFiles[i], targetFiles[j], value)); |
| 533 | break; | 533 | break; |
| 534 | } | 534 | } |
| @@ -539,6 +539,7 @@ class tailOutput : public Output | @@ -539,6 +539,7 @@ class tailOutput : public Output | ||
| 539 | comparisons.removeLast(); | 539 | comparisons.removeLast(); |
| 540 | while ((comparisons.size() > atLeast) && (comparisons.last().value < threshold)) | 540 | while ((comparisons.size() > atLeast) && (comparisons.last().value < threshold)) |
| 541 | comparisons.removeLast(); | 541 | comparisons.removeLast(); |
| 542 | + | ||
| 542 | lastValue = comparisons.last().value; | 543 | lastValue = comparisons.last().value; |
| 543 | comparisonsLock.unlock(); | 544 | comparisonsLock.unlock(); |
| 544 | } | 545 | } |
openbr/plugins/process.cpp
| @@ -531,8 +531,6 @@ class ProcessWrapperTransform : public TimeVaryingTransform | @@ -531,8 +531,6 @@ class ProcessWrapperTransform : public TimeVaryingTransform | ||
| 531 | baseKey = id.toString(); | 531 | baseKey = id.toString(); |
| 532 | 532 | ||
| 533 | QStringList argumentList; | 533 | QStringList argumentList; |
| 534 | - argumentList.append("-useGui"); | ||
| 535 | - argumentList.append("0"); | ||
| 536 | argumentList.append("-algorithm"); | 534 | argumentList.append("-algorithm"); |
| 537 | argumentList.append(transform); | 535 | argumentList.append(transform); |
| 538 | if (!Globals->path.isEmpty()) { | 536 | if (!Globals->path.isEmpty()) { |
openbr/plugins/quality.cpp
| @@ -272,92 +272,75 @@ BR_REGISTER(Distance, ZScoreDistance) | @@ -272,92 +272,75 @@ BR_REGISTER(Distance, ZScoreDistance) | ||
| 272 | 272 | ||
| 273 | /*! | 273 | /*! |
| 274 | * \ingroup distances | 274 | * \ingroup distances |
| 275 | - * \brief Match Probability modification for heat maps \cite klare12 | 275 | + * \brief 1v1 heat map comparison |
| 276 | * \author Scott Klum \cite sklum | 276 | * \author Scott Klum \cite sklum |
| 277 | */ | 277 | */ |
| 278 | class HeatMapDistance : public Distance | 278 | class HeatMapDistance : public Distance |
| 279 | { | 279 | { |
| 280 | Q_OBJECT | 280 | Q_OBJECT |
| 281 | - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | ||
| 282 | - Q_PROPERTY(bool gaussian READ get_gaussian WRITE set_gaussian RESET reset_gaussian STORED false) | ||
| 283 | - Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false) | 281 | + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) |
| 284 | Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false) | 282 | Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false) |
| 285 | Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) | 283 | Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) |
| 286 | - BR_PROPERTY(br::Distance*, distance, make("Dist(L2)")) | ||
| 287 | - BR_PROPERTY(bool, gaussian, true) | ||
| 288 | - BR_PROPERTY(bool, crossModality, false) | 284 | + BR_PROPERTY(QString, description, "IdenticalDistance") |
| 289 | BR_PROPERTY(int, step, 1) | 285 | BR_PROPERTY(int, step, 1) |
| 290 | BR_PROPERTY(QString, inputVariable, "Label") | 286 | BR_PROPERTY(QString, inputVariable, "Label") |
| 291 | 287 | ||
| 292 | - QList<MP> mp; | 288 | + QList<br::Distance*> distances; |
| 293 | 289 | ||
| 294 | void train(const TemplateList &src) | 290 | void train(const TemplateList &src) |
| 295 | { | 291 | { |
| 296 | - distance->train(src); | ||
| 297 | - | ||
| 298 | - const QList<int> labels = src.indexProperty(inputVariable); | ||
| 299 | - | ||
| 300 | QList<TemplateList> patches; | 292 | QList<TemplateList> patches; |
| 301 | 293 | ||
| 302 | // Split src into list of TemplateLists of corresponding patches across all Templates | 294 | // Split src into list of TemplateLists of corresponding patches across all Templates |
| 303 | for (int i=0; i<step; i++) { | 295 | for (int i=0; i<step; i++) { |
| 304 | TemplateList patchBuffer; | 296 | TemplateList patchBuffer; |
| 305 | - for (int j=i; j<src.size(); j+=step) { | ||
| 306 | - patchBuffer.append(src[j]); | ||
| 307 | - } | 297 | + for (int j=0; j<src.size(); j++) |
| 298 | + patchBuffer.append(Template(src[j].file, src[j][i])); | ||
| 308 | patches.append(patchBuffer); | 299 | patches.append(patchBuffer); |
| 309 | patchBuffer.clear(); | 300 | patchBuffer.clear(); |
| 310 | } | 301 | } |
| 311 | 302 | ||
| 312 | - QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(patches[0].size()), FileList(patches[0].size()))); | 303 | + while (distances.size() < patches.size()) |
| 304 | + distances.append(make(description)); | ||
| 313 | 305 | ||
| 314 | - for (int i=0; i<step; i++) { | ||
| 315 | - distance->compare(patches[i], patches[i], matrixOutput.data()); | ||
| 316 | - QList<float> genuineScores, impostorScores; | ||
| 317 | - genuineScores.reserve(step); | ||
| 318 | - impostorScores.reserve(step); | ||
| 319 | - for (int j=0; j<matrixOutput.data()->data.rows; j++) { | ||
| 320 | - for (int k=0; k<j; k++) { | ||
| 321 | - const float score = matrixOutput.data()->data.at<float>(j, k); | ||
| 322 | - if (score == -std::numeric_limits<float>::max()) continue; | ||
| 323 | - if (crossModality) if(src[j*step].file.get<QString>("MODALITY") == src[k*step].file.get<QString>("MODALITY")) continue; | ||
| 324 | - if (labels[j*step] == labels[k*step]) genuineScores.append(score); | ||
| 325 | - else impostorScores.append(score); | ||
| 326 | - } | ||
| 327 | - } | ||
| 328 | - | ||
| 329 | - mp.append(MP(genuineScores, impostorScores)); | ||
| 330 | - } | 306 | + // Train on a distance for each patch |
| 307 | + for (int i=0; i<distances.size(); i++) | ||
| 308 | + distances[i]->train(patches[i]); | ||
| 331 | } | 309 | } |
| 332 | 310 | ||
| 333 | float compare(const Template &target, const Template &query) const | 311 | float compare(const Template &target, const Template &query) const |
| 334 | { | 312 | { |
| 335 | (void) target; | 313 | (void) target; |
| 336 | (void) query; | 314 | (void) query; |
| 337 | - qFatal("You did this wrong"); | 315 | + qFatal("Heatmap Distance not compatible with Template to Template comparison."); |
| 338 | 316 | ||
| 339 | return 0; | 317 | return 0; |
| 340 | } | 318 | } |
| 341 | 319 | ||
| 342 | void compare(const TemplateList &target, const TemplateList &query, Output *output) const | 320 | void compare(const TemplateList &target, const TemplateList &query, Output *output) const |
| 343 | { | 321 | { |
| 344 | - for (int i=0; i<step; i++) { | ||
| 345 | - float rawScore = distance->compare(target[i],query[i]); | ||
| 346 | - if (rawScore == -std::numeric_limits<float>::max()) output->setRelative(rawScore, i, 0); | ||
| 347 | - else output->setRelative(mp[i](rawScore, gaussian), i, 0); | 322 | + for (int i=0; i<target.size(); i++) { |
| 323 | + if (target[i].size() != step || query[i].size() != step) qFatal("Heatmap step not equal to the number of patches."); | ||
| 324 | + for (int j=0; j<step; j++) | ||
| 325 | + output->setRelative(distances[j]->compare(target[i][j],query[i][j]), j, 0); | ||
| 348 | } | 326 | } |
| 349 | } | 327 | } |
| 350 | 328 | ||
| 351 | void store(QDataStream &stream) const | 329 | void store(QDataStream &stream) const |
| 352 | { | 330 | { |
| 353 | - distance->store(stream); | ||
| 354 | - stream << mp; | 331 | + stream << distances.size(); |
| 332 | + foreach (Distance *distance, distances) | ||
| 333 | + distance->store(stream); | ||
| 355 | } | 334 | } |
| 356 | 335 | ||
| 357 | void load(QDataStream &stream) | 336 | void load(QDataStream &stream) |
| 358 | { | 337 | { |
| 359 | - distance->load(stream); | ||
| 360 | - stream >> mp; | 338 | + int numDistances; |
| 339 | + stream >> numDistances; | ||
| 340 | + while (distances.size() < numDistances) | ||
| 341 | + distances.append(make(description)); | ||
| 342 | + foreach (Distance *distance, distances) | ||
| 343 | + distance->load(stream); | ||
| 361 | } | 344 | } |
| 362 | }; | 345 | }; |
| 363 | 346 |
openbr/plugins/segmentation.cpp
0 โ 100644
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | +#include "openbr_internal.h" | ||
| 3 | +#include "openbr/core/opencvutils.h" | ||
| 4 | + | ||
| 5 | +using namespace cv; | ||
| 6 | + | ||
| 7 | +namespace br | ||
| 8 | +{ | ||
| 9 | + | ||
| 10 | +/*! | ||
| 11 | + * \ingroup transforms | ||
| 12 | + * \brief Applies watershed segmentation. | ||
| 13 | + * \author Austin Blanton \cite imaus10 | ||
| 14 | + */ | ||
| 15 | +class WatershedSegmentationTransform : public UntrainableTransform | ||
| 16 | +{ | ||
| 17 | + Q_OBJECT | ||
| 18 | + void project(const Template &src, Template &dst) const | ||
| 19 | + { | ||
| 20 | + dst = src; | ||
| 21 | + | ||
| 22 | + Mat mod; | ||
| 23 | +// adaptiveThreshold(src.m(), src.m(), 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 33, 5); | ||
| 24 | + threshold(src.m(), mod, 0, 255, THRESH_BINARY+THRESH_OTSU); | ||
| 25 | + | ||
| 26 | + // findContours requires an 8-bit 1-channel image | ||
| 27 | + // and modifies its source image | ||
| 28 | + if (mod.depth() != CV_8U) OpenCVUtils::cvtUChar(mod, mod); | ||
| 29 | + if (mod.channels() != 1) OpenCVUtils::cvtGray(mod, mod); | ||
| 30 | + vector<vector<Point> > contours; | ||
| 31 | + vector<Vec4i> hierarchy; | ||
| 32 | + findContours(mod, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); | ||
| 33 | + | ||
| 34 | + // draw the contour delineations as 1,2,3... for input to watershed | ||
| 35 | + Mat markers = Mat::zeros(mod.size(), CV_32S); | ||
| 36 | + int compCount=0; | ||
| 37 | + for (int idx=0; idx>=0; idx=hierarchy[idx][0], compCount++) { | ||
| 38 | + drawContours(markers, contours, idx, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + Mat orig = src.m(); | ||
| 42 | + // watershed requires a 3-channel 8-bit image | ||
| 43 | + if (orig.channels() == 1) cvtColor(orig, orig, CV_GRAY2BGR); | ||
| 44 | + watershed(orig, markers); | ||
| 45 | + dst.file.set("SegmentsMask", QVariant::fromValue(markers)); | ||
| 46 | + dst.file.set("NumSegments", compCount); | ||
| 47 | + } | ||
| 48 | +}; | ||
| 49 | +BR_REGISTER(Transform, WatershedSegmentationTransform) | ||
| 50 | + | ||
| 51 | +} // namespace br | ||
| 52 | + | ||
| 53 | +#include "segmentation.moc" |
openbr/plugins/stasm4.cpp
| @@ -35,7 +35,7 @@ class StasmInitializer : public Initializer | @@ -35,7 +35,7 @@ class StasmInitializer : public Initializer | ||
| 35 | 35 | ||
| 36 | void initialize() const | 36 | void initialize() const |
| 37 | { | 37 | { |
| 38 | - Globals->abbreviations.insert("RectFromStasmEyes","RectFromPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47],0.15,5.3)"); | 38 | + Globals->abbreviations.insert("RectFromStasmEyes","RectFromPoints([28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47],0.3,5.3)"); |
| 39 | Globals->abbreviations.insert("RectFromStasmBrow","RectFromPoints([16,17,18,19,20,21,22,23,24,25,26,27],0.15,5)"); | 39 | Globals->abbreviations.insert("RectFromStasmBrow","RectFromPoints([16,17,18,19,20,21,22,23,24,25,26,27],0.15,5)"); |
| 40 | Globals->abbreviations.insert("RectFromStasmNose","RectFromPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],0.15,1.15)"); | 40 | Globals->abbreviations.insert("RectFromStasmNose","RectFromPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],0.15,1.15)"); |
| 41 | Globals->abbreviations.insert("RectFromStasmMouth","RectFromPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76],0.3,2)"); | 41 | Globals->abbreviations.insert("RectFromStasmMouth","RectFromPoints([59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76],0.3,2)"); |
openbr/plugins/stream.cpp
| 1 | +#include <fstream> | ||
| 1 | #include <QReadWriteLock> | 2 | #include <QReadWriteLock> |
| 2 | #include <QWaitCondition> | 3 | #include <QWaitCondition> |
| 3 | #include <QThreadPool> | 4 | #include <QThreadPool> |
| 4 | #include <QSemaphore> | 5 | #include <QSemaphore> |
| 5 | #include <QMap> | 6 | #include <QMap> |
| 6 | -#include <opencv/highgui.h> | 7 | +#include <QQueue> |
| 7 | #include <QtConcurrent> | 8 | #include <QtConcurrent> |
| 9 | +#include <opencv/highgui.h> | ||
| 10 | +#include <opencv2/highgui/highgui.hpp> | ||
| 8 | #include "openbr_internal.h" | 11 | #include "openbr_internal.h" |
| 9 | - | ||
| 10 | #include "openbr/core/common.h" | 12 | #include "openbr/core/common.h" |
| 11 | #include "openbr/core/opencvutils.h" | 13 | #include "openbr/core/opencvutils.h" |
| 12 | #include "openbr/core/qtutils.h" | 14 | #include "openbr/core/qtutils.h" |
| 13 | 15 | ||
| 14 | using namespace cv; | 16 | using namespace cv; |
| 17 | +using namespace std; | ||
| 15 | 18 | ||
| 16 | namespace br | 19 | namespace br |
| 17 | { | 20 | { |
| @@ -203,6 +206,13 @@ public: | @@ -203,6 +206,13 @@ public: | ||
| 203 | virtual bool getNextTemplate(Template & output)=0; | 206 | virtual bool getNextTemplate(Template & output)=0; |
| 204 | protected: | 207 | protected: |
| 205 | Template basis; | 208 | Template basis; |
| 209 | + string getAbsolutePath(QString filename) | ||
| 210 | + { | ||
| 211 | + // Yes, we should specify absolute path: | ||
| 212 | + // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python | ||
| 213 | + QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + filename; | ||
| 214 | + return QFileInfo(fileName).absoluteFilePath().toStdString(); | ||
| 215 | + } | ||
| 206 | }; | 216 | }; |
| 207 | 217 | ||
| 208 | static QMutex openLock; | 218 | static QMutex openLock; |
| @@ -236,12 +246,9 @@ public: | @@ -236,12 +246,9 @@ public: | ||
| 236 | qDebug("Video not open!"); | 246 | qDebug("Video not open!"); |
| 237 | } | 247 | } |
| 238 | } else { | 248 | } else { |
| 239 | - // Yes, we should specify absolute path: | ||
| 240 | - // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python | ||
| 241 | - QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + input.file.name; | ||
| 242 | // On windows, this appears to not be thread-safe | 249 | // On windows, this appears to not be thread-safe |
| 243 | QMutexLocker lock(&openLock); | 250 | QMutexLocker lock(&openLock); |
| 244 | - video.open(QFileInfo(fileName).absoluteFilePath().toStdString()); | 251 | + video.open(getAbsolutePath(input.file.name)); |
| 245 | } | 252 | } |
| 246 | 253 | ||
| 247 | return video.isOpened(); | 254 | return video.isOpened(); |
| @@ -319,6 +326,198 @@ protected: | @@ -319,6 +326,198 @@ protected: | ||
| 319 | bool data_ok; | 326 | bool data_ok; |
| 320 | }; | 327 | }; |
| 321 | 328 | ||
| 329 | +class SeqReader : public TemplateProcessor | ||
| 330 | +{ | ||
| 331 | +public: | ||
| 332 | + SeqReader() {} | ||
| 333 | + | ||
| 334 | + bool open(Template &input) | ||
| 335 | + { | ||
| 336 | + basis = input; | ||
| 337 | + | ||
| 338 | + seqFile.open(getAbsolutePath(input.file.name).c_str(), ios::in | ios::binary | ios::ate); | ||
| 339 | + if (!isOpen()) return false; | ||
| 340 | + | ||
| 341 | + int headSize = 1024; | ||
| 342 | + // start at end of file to get full size | ||
| 343 | + int fileSize = seqFile.tellg(); | ||
| 344 | + if (fileSize < headSize) { | ||
| 345 | + qDebug("No header in seq file"); | ||
| 346 | + return false; | ||
| 347 | + } | ||
| 348 | + | ||
| 349 | + // first 4 bytes store 0xEDFE, next 24 store 'Norpix seq ' | ||
| 350 | + char firstFour[4]; | ||
| 351 | + seqFile.seekg(0, ios::beg); | ||
| 352 | + seqFile.read(firstFour, 4); | ||
| 353 | + char nextTwentyFour[24]; | ||
| 354 | + readText(24, nextTwentyFour); | ||
| 355 | + if (firstFour[0] != (char)0xED || firstFour[1] != (char)0xFE || strncmp(nextTwentyFour, "Norpix seq", 10) != 0) { | ||
| 356 | + qDebug("Invalid header in seq file"); | ||
| 357 | + return false; | ||
| 358 | + } | ||
| 359 | + | ||
| 360 | + // next 8 bytes for version (skipped below) and header size (1024), then 512 for descr | ||
| 361 | + seqFile.seekg(4, ios::cur); | ||
| 362 | + int hSize = readInt(); | ||
| 363 | + if (hSize != headSize) { | ||
| 364 | + qDebug("Invalid header size"); | ||
| 365 | + return false; | ||
| 366 | + } | ||
| 367 | + char desc[512]; | ||
| 368 | + readText(512, desc); | ||
| 369 | + basis.file.set("Description", QString(desc)); | ||
| 370 | + | ||
| 371 | + width = readInt(); | ||
| 372 | + height = readInt(); | ||
| 373 | + // get # channels from bit depth | ||
| 374 | + numChan = readInt()/8; | ||
| 375 | + int imageBitDepthReal = readInt(); | ||
| 376 | + if (imageBitDepthReal != 8) { | ||
| 377 | + qDebug("Invalid bit depth"); | ||
| 378 | + return false; | ||
| 379 | + } | ||
| 380 | + // the size of just the image part of a raw img | ||
| 381 | + imgSizeBytes = readInt(); | ||
| 382 | + | ||
| 383 | + int imgFormatInt = readInt(); | ||
| 384 | + if (imgFormatInt == 100 || imgFormatInt == 200 || imgFormatInt == 101) { | ||
| 385 | + imgFormat = "raw"; | ||
| 386 | + } else if (imgFormatInt == 102 || imgFormatInt == 201 || imgFormatInt == 103 || | ||
| 387 | + imgFormatInt == 1 || imgFormatInt == 2) { | ||
| 388 | + imgFormat = "compressed"; | ||
| 389 | + } else { | ||
| 390 | + qFatal("unsupported image format"); | ||
| 391 | + } | ||
| 392 | + | ||
| 393 | + numFrames = readInt(); | ||
| 394 | + // skip empty int | ||
| 395 | + seqFile.seekg(4, ios::cur); | ||
| 396 | + // the size of a full raw file, with extra crap after img data | ||
| 397 | + trueImgSizeBytes = readInt(); | ||
| 398 | + | ||
| 399 | + // gather all the frame positions in an array | ||
| 400 | + seekPos.reserve(numFrames); | ||
| 401 | + // start at end of header | ||
| 402 | + seekPos.append(headSize); | ||
| 403 | + // extra 8 bytes at end of img | ||
| 404 | + int extra = 8; | ||
| 405 | + for (int i=1; i<numFrames; i++) { | ||
| 406 | + int s; | ||
| 407 | + // compressed images have different sizes | ||
| 408 | + // the first byte at the beginning of the file | ||
| 409 | + // says how big the current img is | ||
| 410 | + if (imgFormat == "compressed") { | ||
| 411 | + int lastPos = seekPos[i-1]; | ||
| 412 | + seqFile.seekg(lastPos, ios::beg); | ||
| 413 | + int currSize = readInt(); | ||
| 414 | + s = lastPos + currSize + extra; | ||
| 415 | + | ||
| 416 | + // but there might be 16 extra bytes instead of 8... | ||
| 417 | + if (i == 1) { | ||
| 418 | + seqFile.seekg(s, ios::beg); | ||
| 419 | + char zero; | ||
| 420 | + seqFile.read(&zero, 1); | ||
| 421 | + if (zero == 0) { | ||
| 422 | + s += 8; | ||
| 423 | + extra += 8; | ||
| 424 | + } | ||
| 425 | + } | ||
| 426 | + } | ||
| 427 | + // raw images are all the same size | ||
| 428 | + else { | ||
| 429 | + s = headSize + (i*trueImgSizeBytes); | ||
| 430 | + } | ||
| 431 | + | ||
| 432 | + seekPos.enqueue(s); | ||
| 433 | + } | ||
| 434 | + | ||
| 435 | +#ifdef CVMATIO | ||
| 436 | + if (basis.file.contains("vbb")) { | ||
| 437 | + QString vbb = basis.file.get<QString>("vbb"); | ||
| 438 | + annotations = TemplateList::fromGallery(File(vbb)); | ||
| 439 | + } | ||
| 440 | +#else | ||
| 441 | + qWarning("cvmatio not installed, bounding boxes will not be available. Add -DBR_WITH_CVMATIO cmake flag to install."); | ||
| 442 | +#endif | ||
| 443 | + | ||
| 444 | + return true; | ||
| 445 | + } | ||
| 446 | + | ||
| 447 | + bool isOpen() | ||
| 448 | + { | ||
| 449 | + return seqFile.is_open(); | ||
| 450 | + } | ||
| 451 | + | ||
| 452 | + void close() | ||
| 453 | + { | ||
| 454 | + seqFile.close(); | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + bool getNextTemplate(Template &output) | ||
| 458 | + { | ||
| 459 | + if (!isOpen()) { | ||
| 460 | + qDebug("Seq not open"); | ||
| 461 | + return false; | ||
| 462 | + } | ||
| 463 | + // if we've reached the last frame, we're done | ||
| 464 | + if (seekPos.size() == 0) return false; | ||
| 465 | + | ||
| 466 | + seqFile.seekg(seekPos.dequeue(), ios::beg); | ||
| 467 | + | ||
| 468 | + Mat temp; | ||
| 469 | + // let imdecode do all the work to decode the compressed img | ||
| 470 | + if (imgFormat == "compressed") { | ||
| 471 | + int imgSize = readInt() - 4; | ||
| 472 | + vector<char> imgBuf(imgSize); | ||
| 473 | + seqFile.read(&imgBuf[0], imgSize); | ||
| 474 | + // flags < 0 means load image as-is (keep color info if available) | ||
| 475 | + imdecode(imgBuf, -1, &temp); | ||
| 476 | + } | ||
| 477 | + // raw images can be loaded straight into a Mat | ||
| 478 | + else { | ||
| 479 | + char *imgBuf = new char[imgSizeBytes]; | ||
| 480 | + seqFile.read(imgBuf, imgSizeBytes); | ||
| 481 | + int type = (numChan == 1 ? CV_8UC1 : CV_8UC3); | ||
| 482 | + temp = Mat(height, width, type, imgBuf); | ||
| 483 | + } | ||
| 484 | + | ||
| 485 | + output.file = basis.file; | ||
| 486 | + if (!annotations.empty()) { | ||
| 487 | + output.file.setRects(annotations.first().file.rects()); | ||
| 488 | + annotations.removeFirst(); | ||
| 489 | + } | ||
| 490 | + output.m() = temp; | ||
| 491 | + | ||
| 492 | + return true; | ||
| 493 | + } | ||
| 494 | +private: | ||
| 495 | + int readInt() | ||
| 496 | + { | ||
| 497 | + int num; | ||
| 498 | + seqFile.read((char*)&num, 4); | ||
| 499 | + return num; | ||
| 500 | + } | ||
| 501 | + | ||
| 502 | + // apparently the text in seq files is 16 bit characters (UTF-16?) | ||
| 503 | + // since we don't really need the last byte, snad since it gets interpreted as | ||
| 504 | + // a terminating char, let's just grab the first byte for storage | ||
| 505 | + void readText(int bytes, char * buffer) | ||
| 506 | + { | ||
| 507 | + seqFile.read(buffer, bytes); | ||
| 508 | + for (int i=0; i<bytes; i+=2) { | ||
| 509 | + buffer[i/2] = buffer[i]; | ||
| 510 | + } | ||
| 511 | + buffer[bytes/2] = '\0'; | ||
| 512 | + } | ||
| 513 | + | ||
| 514 | +protected: | ||
| 515 | + ifstream seqFile; | ||
| 516 | + QQueue<int> seekPos; | ||
| 517 | + int width, height, numChan, imgSizeBytes, trueImgSizeBytes, numFrames; | ||
| 518 | + QString imgFormat; | ||
| 519 | + TemplateList annotations; | ||
| 520 | +}; | ||
| 322 | 521 | ||
| 323 | // Interface for sequentially getting data from some data source. | 522 | // Interface for sequentially getting data from some data source. |
| 324 | // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor | 523 | // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor |
| @@ -514,11 +713,16 @@ protected: | @@ -514,11 +713,16 @@ protected: | ||
| 514 | if (frameSource) | 713 | if (frameSource) |
| 515 | frameSource->close(); | 714 | frameSource->close(); |
| 516 | 715 | ||
| 716 | + Template curr = this->templates[current_template_idx]; | ||
| 517 | if (mode == br::Idiocy::Auto) | 717 | if (mode == br::Idiocy::Auto) |
| 518 | { | 718 | { |
| 519 | delete frameSource; | 719 | delete frameSource; |
| 520 | - if (this->templates[this->current_template_idx].empty()) | ||
| 521 | - frameSource = new VideoReader(); | 720 | + if (curr.empty()) { |
| 721 | + if (curr.file.name.right(3) == "seq") | ||
| 722 | + frameSource = new SeqReader(); | ||
| 723 | + else | ||
| 724 | + frameSource = new VideoReader(); | ||
| 725 | + } | ||
| 522 | else | 726 | else |
| 523 | frameSource = new DirectReturn(); | 727 | frameSource = new DirectReturn(); |
| 524 | } | 728 | } |
| @@ -529,11 +733,14 @@ protected: | @@ -529,11 +733,14 @@ protected: | ||
| 529 | } | 733 | } |
| 530 | else if (mode == br::Idiocy::StreamVideo) | 734 | else if (mode == br::Idiocy::StreamVideo) |
| 531 | { | 735 | { |
| 532 | - if (!frameSource) | ||
| 533 | - frameSource = new VideoReader(); | 736 | + if (!frameSource) { |
| 737 | + if (curr.file.name.right(3) == "seq") | ||
| 738 | + frameSource = new SeqReader(); | ||
| 739 | + else | ||
| 740 | + frameSource = new VideoReader(); | ||
| 741 | + } | ||
| 534 | } | 742 | } |
| 535 | - | ||
| 536 | - open_res = frameSource->open(this->templates[current_template_idx]); | 743 | + open_res = frameSource->open(curr); |
| 537 | if (!open_res) | 744 | if (!open_res) |
| 538 | { | 745 | { |
| 539 | current_template_idx++; | 746 | current_template_idx++; |
| @@ -1079,8 +1286,7 @@ public: | @@ -1079,8 +1286,7 @@ public: | ||
| 1079 | 1286 | ||
| 1080 | // Wait for the stream to process the last frame available from | 1287 | // Wait for the stream to process the last frame available from |
| 1081 | // the data source. | 1288 | // the data source. |
| 1082 | - bool wait_res = false; | ||
| 1083 | - wait_res = readStage->dataSource.waitLast(); | 1289 | + readStage->dataSource.waitLast(); |
| 1084 | 1290 | ||
| 1085 | // Now that there are no more incoming frames, call finalize | 1291 | // Now that there are no more incoming frames, call finalize |
| 1086 | // on each transform in turn to collect any last templates | 1292 | // on each transform in turn to collect any last templates |
| @@ -1217,6 +1423,7 @@ public: | @@ -1217,6 +1423,7 @@ public: | ||
| 1217 | { | 1423 | { |
| 1218 | // Delete all the stages | 1424 | // Delete all the stages |
| 1219 | for (int i = 0; i < processingStages.size(); i++) { | 1425 | for (int i = 0; i < processingStages.size(); i++) { |
| 1426 | +// TODO: Are we releasing memory which is already freed? | ||
| 1220 | delete processingStages[i]; | 1427 | delete processingStages[i]; |
| 1221 | } | 1428 | } |
| 1222 | processingStages.clear(); | 1429 | processingStages.clear(); |
scripts/downloadDatasets.sh
| @@ -35,6 +35,35 @@ if [ ! -d ../data/BioID/img ]; then | @@ -35,6 +35,35 @@ if [ ! -d ../data/BioID/img ]; then | ||
| 35 | rm *.eye description.txt BioID-FaceDatabase-V1.2.zip | 35 | rm *.eye description.txt BioID-FaceDatabase-V1.2.zip |
| 36 | fi | 36 | fi |
| 37 | 37 | ||
| 38 | +# Caltech Pedestrian | ||
| 39 | +if [ ! -d ../data/CaltechPedestrians/vid ]; then | ||
| 40 | + mkdir ../data/CaltechPedestrians/vid | ||
| 41 | + echo "Downloading Caltech Pedestrians dataset..." | ||
| 42 | + prefix="http://www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/datasets/USA" | ||
| 43 | + for seq in {0..10}; do | ||
| 44 | + fname=`printf "set%02d.tar" $seq` | ||
| 45 | + dlpath="$prefix/$fname" | ||
| 46 | + if hash curl 2>/dev/null; then | ||
| 47 | + curl -OL $dlpath | ||
| 48 | + else | ||
| 49 | + wget $dlpath | ||
| 50 | + fi | ||
| 51 | + tar -xf $fname | ||
| 52 | + done | ||
| 53 | + rm *.tar | ||
| 54 | + ./writeCaltechPedestrianSigset.sh 0 5 train > ../data/CaltechPedestrians/train.xml | ||
| 55 | + ./writeCaltechPedestrianSigset.sh 6 10 test > ../data/CaltechPedestrians/test.xml | ||
| 56 | + mv set* ../data/CaltechPedestrians/vid | ||
| 57 | + if hash curl 2>/dev/null; then | ||
| 58 | + curl -OL "$prefix/annotations.zip" | ||
| 59 | + else | ||
| 60 | + wget "$prefix/annotations.zip" | ||
| 61 | + fi | ||
| 62 | + unzip annotations.zip | ||
| 63 | + rm annotations.zip | ||
| 64 | + mv annotations ../data/CaltechPedestrians | ||
| 65 | +fi | ||
| 66 | + | ||
| 38 | # INRIA person | 67 | # INRIA person |
| 39 | if [ ! -d ../data/INRIAPerson/img ]; then | 68 | if [ ! -d ../data/INRIAPerson/img ]; then |
| 40 | echo "Downloading INRIA person dataset..." | 69 | echo "Downloading INRIA person dataset..." |
| @@ -66,7 +95,7 @@ if [ ! -d ../data/KTH/vid ]; then | @@ -66,7 +95,7 @@ if [ ! -d ../data/KTH/vid ]; then | ||
| 66 | fi | 95 | fi |
| 67 | mkdir ../data/KTH/vid/${vidclass} | 96 | mkdir ../data/KTH/vid/${vidclass} |
| 68 | unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass} | 97 | unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass} |
| 69 | - rm ${vidclass}.zip | 98 | + rm ${vidclass}.zip |
| 70 | done | 99 | done |
| 71 | # this file is corrupted | 100 | # this file is corrupted |
| 72 | rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi | 101 | rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi |
scripts/evalAgeRegression-PCSO.sh
| @@ -4,7 +4,7 @@ if [ ! -f evalAgeRegression-PCSO.sh ]; then | @@ -4,7 +4,7 @@ if [ ! -f evalAgeRegression-PCSO.sh ]; then | ||
| 4 | exit | 4 | exit |
| 5 | fi | 5 | fi |
| 6 | 6 | ||
| 7 | -export BR="../build/app/br/br -useGui 0" | 7 | +export BR=../build/app/br/br |
| 8 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ | 8 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ |
| 9 | export ageAlg=AgeRegression | 9 | export ageAlg=AgeRegression |
| 10 | 10 |
scripts/evalFaceRecognition-LFW.sh
| @@ -20,7 +20,7 @@ if [ ! -e Algorithm_Dataset ]; then | @@ -20,7 +20,7 @@ if [ ! -e Algorithm_Dataset ]; then | ||
| 20 | fi | 20 | fi |
| 21 | 21 | ||
| 22 | # Run the LFW test protocol | 22 | # Run the LFW test protocol |
| 23 | -br -useGui 0 -algorithm $ALGORITHM -path ../data/LFW/img/ -crossValidate 10 -pairwiseCompare ../data/LFW/sigset/test_image_restricted_target.xml ../data/LFW/sigset/test_image_restricted_query.xml ${ALGORITHM}_LFW.mtx -convert Output ${ALGORITHM}_lfw.mtx Algorithm_Dataset/${ALGORITHM}_LFW%1.eval | 23 | +br -algorithm $ALGORITHM -path ../data/LFW/img/ -crossValidate 10 -pairwiseCompare ../data/LFW/sigset/test_image_restricted_target.xml ../data/LFW/sigset/test_image_restricted_query.xml ${ALGORITHM}_LFW.mtx -convert Output ${ALGORITHM}_lfw.mtx Algorithm_Dataset/${ALGORITHM}_LFW%1.eval |
| 24 | 24 | ||
| 25 | # Plot results | 25 | # Plot results |
| 26 | -br -useGui 0 -plot Algorithm_Dataset/* 'lfw_results.pdf[smooth=Dataset,rocOptions[yLimits=(0,1)]]' | 26 | +br -plot Algorithm_Dataset/* 'lfw_results.pdf[smooth=Dataset,rocOptions[yLimits=(0,1)]]' |
scripts/evalFaceRecognition-MEDS.sh
| @@ -20,11 +20,11 @@ if [ ! -e Algorithm_Dataset ]; then | @@ -20,11 +20,11 @@ if [ ! -e Algorithm_Dataset ]; then | ||
| 20 | fi | 20 | fi |
| 21 | 21 | ||
| 22 | if [ ! -e MEDS.mask ]; then | 22 | if [ ! -e MEDS.mask ]; then |
| 23 | - br -useGui 0 -makeMask ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml MEDS.mask | 23 | + br -makeMask ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml MEDS.mask |
| 24 | fi | 24 | fi |
| 25 | 25 | ||
| 26 | # Run Algorithm on MEDS | 26 | # Run Algorithm on MEDS |
| 27 | -br -useGui 0 -algorithm ${ALGORITHM} -path ../data/MEDS/img -compare ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml ${ALGORITHM}_MEDS.mtx -eval ${ALGORITHM}_MEDS.mtx MEDS.mask Algorithm_Dataset/${ALGORITHM}_MEDS.csv | 27 | +br -algorithm ${ALGORITHM} -path ../data/MEDS/img -compare ../data/MEDS/sigset/MEDS_frontal_target.xml ../data/MEDS/sigset/MEDS_frontal_query.xml ${ALGORITHM}_MEDS.mtx -eval ${ALGORITHM}_MEDS.mtx MEDS.mask Algorithm_Dataset/${ALGORITHM}_MEDS.csv |
| 28 | 28 | ||
| 29 | # Plot results | 29 | # Plot results |
| 30 | -br -useGui 0 -plot Algorithm_Dataset/*_MEDS.csv MEDS | 30 | +br -plot Algorithm_Dataset/*_MEDS.csv MEDS |
scripts/evalGenderClassification-PCSO.sh
| @@ -9,7 +9,7 @@ export ALGORITHM=GenderClassification | @@ -9,7 +9,7 @@ export ALGORITHM=GenderClassification | ||
| 9 | export PCSO_DIR=../data/PCSO/img | 9 | export PCSO_DIR=../data/PCSO/img |
| 10 | 10 | ||
| 11 | # Create a file list by querying the database | 11 | # Create a file list by querying the database |
| 12 | -$BR -useGui 0 -quiet -algorithm Identity -enroll "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=1:8000]" terminal.txt > Input.txt | 12 | +$BR -quiet -algorithm Identity -enroll "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=1:8000]" terminal.txt > Input.txt |
| 13 | 13 | ||
| 14 | # Enroll the file list and evaluate performance | 14 | # Enroll the file list and evaluate performance |
| 15 | -$BR -useGui 0 -algorithm $ALGORITHM -path $PCSO_DIR -enroll Input.txt Output.txt -evalClassification Output.txt Input.txt Gender | ||
| 16 | \ No newline at end of file | 15 | \ No newline at end of file |
| 16 | +$BR -algorithm $ALGORITHM -path $PCSO_DIR -enroll Input.txt Output.txt -evalClassification Output.txt Input.txt Gender | ||
| 17 | \ No newline at end of file | 17 | \ No newline at end of file |
scripts/pedestrianBaselineLBP.sh
| @@ -27,8 +27,7 @@ else | @@ -27,8 +27,7 @@ else | ||
| 27 | TEST=testSmall.xml | 27 | TEST=testSmall.xml |
| 28 | fi | 28 | fi |
| 29 | 29 | ||
| 30 | -br -useGui 0 \ | ||
| 31 | - -algorithm "${ALG}" \ | 30 | +br -algorithm "${ALG}" \ |
| 32 | -path $INRIA_PATH/img \ | 31 | -path $INRIA_PATH/img \ |
| 33 | -train $INRIA_PATH/sigset/train.xml pedModel \ | 32 | -train $INRIA_PATH/sigset/train.xml pedModel \ |
| 34 | -enroll $INRIA_PATH/sigset/$TEST pedResults.xml | 33 | -enroll $INRIA_PATH/sigset/$TEST pedResults.xml |
scripts/trainAgeRegression-PCSO.sh
| @@ -13,4 +13,4 @@ export ageAlg=AgeRegression | @@ -13,4 +13,4 @@ export ageAlg=AgeRegression | ||
| 13 | 13 | ||
| 14 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ | 14 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ |
| 15 | 15 | ||
| 16 | -$BR -useGui 0 -algorithm $ageAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Age,PersonID FROM PCSO WHERE Age >= 17 AND AGE <= 68', subset=0:200]" ../share/openbr/models/algorithms/AgeRegression | 16 | +$BR -algorithm $ageAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Age,PersonID FROM PCSO WHERE Age >= 17 AND AGE <= 68', subset=0:200]" ../share/openbr/models/algorithms/AgeRegression |
scripts/trainFaceRecognition-PCSO.sh
| @@ -14,7 +14,5 @@ export BR=../build/app/br/br | @@ -14,7 +14,5 @@ export BR=../build/app/br/br | ||
| 14 | 14 | ||
| 15 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ | 15 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ |
| 16 | 16 | ||
| 17 | - | ||
| 18 | - | ||
| 19 | -$BR -useGui 0 -algorithm FaceRecognition -path "$PCSO_DIR/Images/" -train "$PCSO_DIR/PCSO.db[query='SELECT File,PersonID as Label,PersonID FROM PCSO', subset=0:5:6000]" ../share/openbr/models/algorithms/FaceRecognition | 17 | +$BR -algorithm FaceRecognition -path "$PCSO_DIR/Images/" -train "$PCSO_DIR/PCSO.db[query='SELECT File,PersonID as Label,PersonID FROM PCSO', subset=0:5:6000]" ../share/openbr/models/algorithms/FaceRecognition |
| 20 | 18 |
scripts/trainGenderClassification-PCSO.sh
| @@ -13,4 +13,4 @@ export genderAlg=GenderClassification | @@ -13,4 +13,4 @@ export genderAlg=GenderClassification | ||
| 13 | 13 | ||
| 14 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ | 14 | export PCSO_DIR=/user/pripshare/Databases/FaceDatabases/PCSO/PCSO/ |
| 15 | 15 | ||
| 16 | -$BR -useGui 0 -algorithm $genderAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=0:8000]" ../share/openbr/models/algorithms/GenderClassification | 16 | +$BR -algorithm $genderAlg -path $PCSO_DIR/Images -train "$PCSO_DIR/PCSO.db[query='SELECT File,Gender,PersonID FROM PCSO', subset=0:8000]" ../share/openbr/models/algorithms/GenderClassification |
scripts/writeCaltechPedestrianSigset.sh
0 โ 100755
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +echo '<?xml version="1.0" encoding="UTF-8"?>' | ||
| 4 | +echo '<biometric-signature-set>' | ||
| 5 | +for ((set=$1; set <= $2; set++)); do | ||
| 6 | + echo -e "\t<biometric-signature name=\"\">" | ||
| 7 | + for vid in `printf "set%02d/*.seq" $set`; do | ||
| 8 | + if [ $3 == "train" ]; then | ||
| 9 | + vbb=`echo "vbb=\"annotations/$vid\"" | sed s/seq/vbb/` | ||
| 10 | + fi | ||
| 11 | + printf "\t\t<presentation file-name=\"vid/$vid\" $vbb />\n" | ||
| 12 | + done | ||
| 13 | + echo -e "\t</biometric-signature>" | ||
| 14 | +done | ||
| 15 | +echo '</biometric-signature-set>' |
scripts/writeKTHSigset.sh
100644 โ 100755
share/openbr/cmake/Findcvmatio.cmake
0 โ 100644
| 1 | +set(CVMATIO_DIR "${BR_THIRDPARTY_DIR}/cvmatio") | ||
| 2 | +if(NOT EXISTS ${CVMATIO_DIR}) | ||
| 3 | + # download source from github | ||
| 4 | + execute_process(COMMAND "git" "clone" "https://github.com/hbristow/cvmatio.git" WORKING_DIRECTORY ${BR_THIRDPARTY_DIR}) | ||
| 5 | +else() | ||
| 6 | + # update the source | ||
| 7 | + execute_process(COMMAND "git" "pull" WORKING_DIRECTORY ${CVMATIO_DIR}) | ||
| 8 | +endif() | ||
| 9 | +set(CVMATIO_LIB_DIR ${CMAKE_BINARY_DIR}/3rdparty/cvmatio/src) |
share/openbr/cmake/OpenBRConfig.cmake
| @@ -8,6 +8,7 @@ | @@ -8,6 +8,7 @@ | ||
| 8 | # target_link_libraries(MY_TARGET_NAME ${OPENBR_LIBS}) | 8 | # target_link_libraries(MY_TARGET_NAME ${OPENBR_LIBS}) |
| 9 | # ================================================================ | 9 | # ================================================================ |
| 10 | 10 | ||
| 11 | +find_path(OPENBR_DIR include/openbr/openbr.h) | ||
| 11 | include_directories(${OPENBR_DIR}/include) | 12 | include_directories(${OPENBR_DIR}/include) |
| 12 | link_directories(${OPENBR_DIR}/lib) | 13 | link_directories(${OPENBR_DIR}/lib) |
| 13 | set(OPENBR_LIBS "openbr") | 14 | set(OPENBR_LIBS "openbr") |