Commit 40b8933df3fc1355305961c5bd0d99de8f9eca9d
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
62 changed files
with
1010 additions
and
282 deletions
.gitignore
| 1 | 1 | ### Repository Specific ### |
| 2 | 2 | 3rdparty/LatentSDK* |
| 3 | 3 | 3rdparty/pittpatt* |
| 4 | +3rdparty/cvmatio | |
| 4 | 5 | data/*/img |
| 5 | 6 | data/*/vid |
| 6 | 7 | data/PCSO/* |
| ... | ... | @@ -39,4 +40,10 @@ scripts/results |
| 39 | 40 | ### autogenerated sigsets ### |
| 40 | 41 | data/INRIAPerson/sigset |
| 41 | 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 | 4 | # Global settings |
| 5 | 5 | set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr") |
| 6 | 6 | set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") |
| 7 | +set(BR_THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty") | |
| 7 | 8 | set(CMAKE_AUTOMOC ON) |
| 8 | 9 | set(CPACK_PACKAGE_NAME "OpenBR") |
| 9 | 10 | set(CPACK_PACKAGE_VENDOR "OpenBiometrics") |
| ... | ... | @@ -90,6 +91,18 @@ set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${OpenCV_LIBS}) |
| 90 | 91 | # Find Alphanum |
| 91 | 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 | 106 | # Compiler flags |
| 94 | 107 | if(UNIX) |
| 95 | 108 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-strict-overflow -fvisibility=hidden -fno-omit-frame-pointer") | ... | ... |
README.md
app/CMakeLists.txt
app/br/br.cpp
| ... | ... | @@ -158,12 +158,17 @@ public: |
| 158 | 158 | } else if (!strcmp(fun, "plotMetadata")) { |
| 159 | 159 | check(parc >= 2, "Incorrect parameter count for 'plotMetadata'."); |
| 160 | 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 | 166 | // Miscellaneous |
| 164 | 167 | else if (!strcmp(fun, "help")) { |
| 165 | 168 | check(parc == 0, "No parameters expected for 'help'."); |
| 166 | 169 | help(); |
| 170 | + } else if (!strcmp(fun, "gui")) { | |
| 171 | + // Do nothing because we checked for this flag prior to initialization | |
| 167 | 172 | } else if (!strcmp(fun, "objects")) { |
| 168 | 173 | check(parc <= 2, "Incorrect parameter count for 'objects'."); |
| 169 | 174 | printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*")); |
| ... | ... | @@ -177,11 +182,10 @@ public: |
| 177 | 182 | check(parc == 1, "Incorrect parameter count for 'daemon'."); |
| 178 | 183 | daemon = true; |
| 179 | 184 | daemon_pipe = parv[0]; |
| 180 | - } else if (!strcmp(fun,"slave")) { | |
| 185 | + } else if (!strcmp(fun, "slave")) { | |
| 181 | 186 | check(parc == 1, "Incorrect parameter count for 'slave'"); |
| 182 | 187 | br_slave_process(parv[0]); |
| 183 | - } | |
| 184 | - else if (!strcmp(fun, "exit")) { | |
| 188 | + } else if (!strcmp(fun, "exit")) { | |
| 185 | 189 | check(parc == 0, "No parameters expected for 'exit'."); |
| 186 | 190 | daemon = false; |
| 187 | 191 | } else if (!strcmp(fun, "getHeader")) { |
| ... | ... | @@ -245,6 +249,7 @@ private: |
| 245 | 249 | "\n" |
| 246 | 250 | "==== Miscellaneous ====\n" |
| 247 | 251 | "-help\n" |
| 252 | + "-gui\n" | |
| 248 | 253 | "-objects [abstraction [implementation]]\n" |
| 249 | 254 | "-about\n" |
| 250 | 255 | "-version\n" |
| ... | ... | @@ -255,7 +260,7 @@ private: |
| 255 | 260 | |
| 256 | 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 | 265 | FakeMain *fakeMain = new FakeMain(argc, argv); |
| 261 | 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 | 34 | set(JANUS_BUILD_DOCS ${BR_BUILD_DOCUMENTATION} CACHE BOOL "Build Janus HTML Doxygen documentation") |
| 35 | 35 | mark_as_advanced(JANUS_BUILD_PP5_WRAPPER) |
| 36 | 36 | mark_as_advanced(JANUS_BUILD_DOCS) |
| 37 | -set(JANUS_TEST_IMPLEMENTATION openbr) | |
| 37 | +set(JANUS_IMPLEMENTATION openbr) | |
| 38 | 38 | add_subdirectory(janus) |
| 39 | 39 | |
| 40 | 40 | # Install | ... | ... |
openbr/core/bee.cpp
| ... | ... | @@ -172,6 +172,8 @@ Mat BEE::readMat(const br::File &matrix, QString *targetSigset, QString *querySi |
| 172 | 172 | qint64 read = file.read((char*)m.data, bytesExpected); |
| 173 | 173 | if (read != bytesExpected) |
| 174 | 174 | qFatal("Invalid matrix size."); |
| 175 | + if (!file.atEnd()) | |
| 176 | + qFatal("Expected matrix end of file."); | |
| 175 | 177 | file.close(); |
| 176 | 178 | |
| 177 | 179 | Mat result; | ... | ... |
openbr/core/cluster.cpp
openbr/core/common.cpp
| ... | ... | @@ -63,3 +63,16 @@ QList<int> Common::RandSample(int n, const QSet<int> &values, bool unique) |
| 63 | 63 | } |
| 64 | 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 | 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 | 261 | * \brief See Matlab function unique() for documentation. |
| 257 | 262 | */ |
| 258 | 263 | template <typename T> | ... | ... |
openbr/core/core.cpp
| ... | ... | @@ -254,6 +254,56 @@ struct AlgorithmCore |
| 254 | 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 | 307 | void compare(File targetGallery, File queryGallery, File output) |
| 258 | 308 | { |
| 259 | 309 | qDebug("Comparing %s and %s%s", qPrintable(targetGallery.flat()), |
| ... | ... | @@ -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 | 560 | QSharedPointer<br::Transform> br::Transform::fromAlgorithm(const QString &algorithm, bool preprocess) |
| 503 | 561 | { |
| 504 | 562 | if (!preprocess) | ... | ... |
openbr/core/eigenutils.cpp
| ... | ... | @@ -54,3 +54,16 @@ void printEigen(Eigen::MatrixXd X) { |
| 54 | 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 | 26 | void writeEigen(Eigen::VectorXd X, QString filename); |
| 27 | 27 | void writeEigen(Eigen::VectorXf X, QString filename); |
| 28 | 28 | void printEigen(Eigen::MatrixXd X); |
| 29 | +void printEigen(Eigen::MatrixXf X); | |
| 30 | +void printSize(Eigen::MatrixXf X); | |
| 29 | 31 | |
| 30 | 32 | template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> |
| 31 | 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 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <opencv2/highgui/highgui.hpp> |
| 18 | +#include <opencv2/highgui/highgui_c.h> | |
| 18 | 19 | #include <opencv2/imgproc/imgproc.hpp> |
| 20 | +#include <opencv2/imgproc/imgproc_c.h> | |
| 19 | 21 | #include <openbr/openbr_plugin.h> |
| 20 | 22 | |
| 21 | 23 | #include "opencvutils.h" | ... | ... |
openbr/core/opencvutils.h
openbr/gui/tail.cpp
openbr/gui/utility.cpp
openbr/janus.cpp
| ... | ... | @@ -3,140 +3,138 @@ |
| 3 | 3 | #endif |
| 4 | 4 | |
| 5 | 5 | #include "janus.h" |
| 6 | +#include "janus_io.h" | |
| 6 | 7 | #include "openbr_plugin.h" |
| 7 | 8 | |
| 8 | -// Use the provided default implementation of some functions | |
| 9 | -#include "janus/src/janus.cpp" | |
| 10 | - | |
| 11 | 9 | using namespace br; |
| 12 | 10 | |
| 13 | 11 | static QSharedPointer<Transform> transform; |
| 14 | 12 | static QSharedPointer<Distance> distance; |
| 15 | 13 | |
| 14 | +size_t janus_max_template_size() | |
| 15 | +{ | |
| 16 | + return 33554432; // 32 MB | |
| 17 | +} | |
| 18 | + | |
| 16 | 19 | janus_error janus_initialize(const char *sdk_path, const char *model_file) |
| 17 | 20 | { |
| 18 | 21 | int argc = 1; |
| 19 | 22 | const char *argv[1] = { "janus" }; |
| 20 | 23 | Context::initialize(argc, (char**)argv, sdk_path); |
| 21 | 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 | 35 | return JANUS_SUCCESS; |
| 26 | 36 | } |
| 27 | 37 | |
| 28 | 38 | janus_error janus_finalize() |
| 29 | 39 | { |
| 40 | + transform.reset(); | |
| 41 | + distance.reset(); | |
| 30 | 42 | Context::finalize(); |
| 31 | 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 | 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 | 57 | Template t; |
| 48 | 58 | t.append(cv::Mat(image.height, |
| 49 | 59 | image.width, |
| 50 | - image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC1, | |
| 60 | + image.color_space == JANUS_GRAY8 ? CV_8UC1 : CV_8UC3, | |
| 51 | 61 | image.data)); |
| 52 | 62 | for (size_t i=0; i<attributes.size; i++) |
| 53 | 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 | 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 | 73 | Template u; |
| 64 | 74 | transform->project(t, u); |
| 65 | - incomplete_template->data.append(u); | |
| 75 | + template_->append(u); | |
| 66 | 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 | 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 | 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 | 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 | 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 | 139 | return JANUS_SUCCESS; |
| 142 | 140 | } | ... | ... |
openbr/openbr.cpp
| ... | ... | @@ -24,6 +24,7 @@ |
| 24 | 24 | #include "core/qtutils.h" |
| 25 | 25 | #include "plugins/openbr_internal.h" |
| 26 | 26 | #include <opencv2/highgui/highgui.hpp> |
| 27 | +#include <opencv2/highgui/highgui_c.h> | |
| 27 | 28 | |
| 28 | 29 | using namespace br; |
| 29 | 30 | |
| ... | ... | @@ -121,9 +122,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], |
| 121 | 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 | 130 | void br_initialize_default() |
| ... | ... | @@ -381,8 +382,9 @@ bool br_img_is_empty(br_template tmpl) |
| 381 | 382 | |
| 382 | 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 | 390 | void br_set_filename(br_template tmpl, const char *filename) |
| ... | ... | @@ -470,3 +472,8 @@ void br_close_gallery(br_gallery gallery) |
| 470 | 472 | Gallery *gal = reinterpret_cast<Gallery*>(gallery); |
| 471 | 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 | 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 | 81 | * \brief Clusters one or more similarity matrices into a list of subjects. |
| 71 | 82 | * |
| 72 | 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 | 224 | * \brief Wraps br::Context::initialize() |
| 214 | 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 | 229 | * \brief Wraps br::Context::initialize() with default arguments. |
| 219 | 230 | * \see br_finalize | ... | ... |
openbr/openbr_plugin.cpp
| ... | ... | @@ -44,12 +44,6 @@ using namespace cv; |
| 44 | 44 | |
| 45 | 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 | 47 | /* File - public methods */ |
| 54 | 48 | // Note that the convention for displaying metadata is as follows: |
| 55 | 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 | 842 | |
| 849 | 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 | 848 | void br::Context::printStatus() |
| ... | ... | @@ -907,42 +895,30 @@ bool br::Context::checkSDKPath(const QString &sdkPath) |
| 907 | 895 | // We create our own when the user hasn't |
| 908 | 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 | 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 | 910 | // We take in argc as a reference due to: |
| 925 | 911 | // https://bugreports.qt-project.org/browse/QTBUG-5637 |
| 926 | 912 | // QApplication should be initialized before anything else. |
| 927 | 913 | // Since we can't ensure that it gets deleted last, we never delete it. |
| 928 | 914 | if (QCoreApplication::instance() == NULL) { |
| 929 | 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 | 920 | application = new QCoreApplication(argc, argv); |
| 945 | -#endif | |
| 921 | +#endif // BR_EMBEDDED | |
| 946 | 922 | } |
| 947 | 923 | |
| 948 | 924 | QCoreApplication::setOrganizationName(COMPANY_NAME); |
| ... | ... | @@ -965,14 +941,14 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool use_ |
| 965 | 941 | |
| 966 | 942 | Globals = new Context(); |
| 967 | 943 | Globals->init(File()); |
| 968 | - Globals->useGui = use_gui; | |
| 969 | - | |
| 944 | + Globals->useGui = useGui; | |
| 970 | 945 | |
| 971 | 946 | Common::seedRNG(); |
| 972 | 947 | |
| 973 | 948 | // Search for SDK |
| 974 | 949 | if (sdkPath.isEmpty()) { |
| 975 | 950 | QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); |
| 951 | + checkPaths << QString(getenv("PATH")).split(sep, QString::SkipEmptyParts); | |
| 976 | 952 | |
| 977 | 953 | bool foundSDK = false; |
| 978 | 954 | foreach (const QString &path, checkPaths) { |
| ... | ... | @@ -1035,26 +1011,6 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte |
| 1035 | 1011 | static QMutex generalLock; |
| 1036 | 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 | 1014 | QString txt; |
| 1059 | 1015 | if (type == QtDebugMsg) { |
| 1060 | 1016 | if (Globals->quiet) return; |
| ... | ... | @@ -1076,8 +1032,13 @@ void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &conte |
| 1076 | 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 | 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 | 1044 | Context *br::Globals = NULL; | ... | ... |
openbr/openbr_plugin.h
| ... | ... | @@ -41,6 +41,7 @@ |
| 41 | 41 | #include <QVector> |
| 42 | 42 | #include <opencv2/core/core.hpp> |
| 43 | 43 | #include <openbr/openbr.h> |
| 44 | +#include <assert.h> | |
| 44 | 45 | |
| 45 | 46 | /*! |
| 46 | 47 | * \defgroup cpp_plugin_sdk C++ Plugin SDK |
| ... | ... | @@ -794,12 +795,12 @@ public: |
| 794 | 795 | * By default <tt>share/openbr/openbr.bib</tt> will be searched for relative to: |
| 795 | 796 | * -# The working directory |
| 796 | 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 | 799 | * \note Tiggers \em abort() on failure to locate <tt>share/openbr/openbr.bib</tt>. |
| 799 | 800 | * \note <a href="http://qt-project.org/">Qt</a> users should instead call this <i>after</i> initializing QApplication. |
| 800 | 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 | 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 | 1372 | */ |
| 1372 | 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 | 1385 | } // namespace br | ... | ... |
openbr/plugins/algorithms.cpp
| ... | ... | @@ -50,6 +50,9 @@ class AlgorithmsInitializer : public Initializer |
| 50 | 50 | Globals->abbreviations.insert("DisplayVideo", "Stream(FPSLimit(30)+Show(false,[FrameNumber])+Discard)"); |
| 51 | 51 | Globals->abbreviations.insert("PerFrameDetection", "Stream(SaveMat(original)+Cvt(Gray)+Cascade(FrontalFace)+ASEFEyes+RestoreMat(original)+Draw(inPlace=true)+Show(false,[FrameNumber])+Discard)"); |
| 52 | 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 | 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 | 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 | 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 | 81 | // Transforms |
| 79 | - Globals->abbreviations.insert("FaceDetection", "(Open+Cvt(Gray)+Cascade(FrontalFace))"); | |
| 82 | + Globals->abbreviations.insert("FaceDetection", "Open+Cvt(Gray)+Cascade(FrontalFace)"); | |
| 80 | 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 | 84 | Globals->abbreviations.insert("DenseSIFT", "(Grid(10,10)+SIFTDescriptor(12)+ByRow)"); |
| 82 | 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 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <opencv2/objdetect/objdetect.hpp> |
| 18 | +//#include <opencv2/objdetect/objdetect_c.h> | |
| 18 | 19 | #include "openbr_internal.h" |
| 19 | 20 | #include "openbr/core/opencvutils.h" |
| 20 | 21 | #include "openbr/core/resource.h" |
| ... | ... | @@ -86,11 +87,11 @@ class CascadeTransform : public UntrainableMetaTransform |
| 86 | 87 | |
| 87 | 88 | for (int i=0; i<t.size(); i++) { |
| 88 | 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 | 96 | if (!enrollAll && rects.empty()) |
| 96 | 97 | rects.push_back(Rect(0, 0, m.cols, m.rows)); | ... | ... |
openbr/plugins/cvt.cpp
| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | * limitations under the License. * |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | +#include <opencv2/imgproc/imgproc_c.h> | |
| 17 | 18 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | 19 | #include "openbr_internal.h" |
| 19 | 20 | #include "openbr/core/opencvutils.h" |
| ... | ... | @@ -44,7 +45,8 @@ public: |
| 44 | 45 | Luv = CV_BGR2Luv, |
| 45 | 46 | RGB = CV_BGR2RGB, |
| 46 | 47 | XYZ = CV_BGR2XYZ, |
| 47 | - YCrCb = CV_BGR2YCrCb }; | |
| 48 | + YCrCb = CV_BGR2YCrCb, | |
| 49 | + Color = CV_GRAY2BGR }; | |
| 48 | 50 | |
| 49 | 51 | private: |
| 50 | 52 | BR_PROPERTY(ColorSpace, colorSpace, Gray) |
| ... | ... | @@ -52,8 +54,8 @@ private: |
| 52 | 54 | |
| 53 | 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 | 60 | if (channel != -1) { |
| 59 | 61 | std::vector<Mat> mv; | ... | ... |
openbr/plugins/distance.cpp
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | #include <QtConcurrentRun> |
| 19 | 19 | #include <numeric> |
| 20 | 20 | #include <opencv2/imgproc/imgproc.hpp> |
| 21 | +#include <opencv2/imgproc/imgproc_c.h> | |
| 21 | 22 | #include "openbr_internal.h" |
| 22 | 23 | |
| 23 | 24 | #include "openbr/core/distance_sse.h" |
| ... | ... | @@ -61,6 +62,7 @@ private: |
| 61 | 62 | (a.m().type() != b.m().type())) |
| 62 | 63 | return -std::numeric_limits<float>::max(); |
| 63 | 64 | |
| 65 | +// TODO: this max value is never returned based on the switch / default | |
| 64 | 66 | float result = std::numeric_limits<float>::max(); |
| 65 | 67 | switch (metric) { |
| 66 | 68 | case Correlation: |
| ... | ... | @@ -386,5 +388,67 @@ class OnlineDistance : public Distance |
| 386 | 388 | |
| 387 | 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 | 453 | } // namespace br |
| 390 | 454 | #include "distance.moc" | ... | ... |
openbr/plugins/draw.cpp
| ... | ... | @@ -15,6 +15,7 @@ |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <opencv2/highgui/highgui.hpp> |
| 18 | +#include <opencv2/highgui/highgui_c.h> | |
| 18 | 19 | #include <opencv2/imgproc/imgproc.hpp> |
| 19 | 20 | #include <vector> |
| 20 | 21 | #include "openbr_internal.h" |
| ... | ... | @@ -40,10 +41,12 @@ class DrawTransform : public UntrainableTransform |
| 40 | 41 | Q_PROPERTY(bool points READ get_points WRITE set_points RESET reset_points STORED false) |
| 41 | 42 | Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) |
| 42 | 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 | 45 | BR_PROPERTY(bool, verbose, false) |
| 44 | 46 | BR_PROPERTY(bool, points, true) |
| 45 | 47 | BR_PROPERTY(bool, rects, true) |
| 46 | 48 | BR_PROPERTY(bool, inPlace, false) |
| 49 | + BR_PROPERTY(int, lineThickness, 1) | |
| 47 | 50 | |
| 48 | 51 | void project(const Template &src, Template &dst) const |
| 49 | 52 | { |
| ... | ... | @@ -61,7 +64,7 @@ class DrawTransform : public UntrainableTransform |
| 61 | 64 | } |
| 62 | 65 | if (rects) { |
| 63 | 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 | 346 | |
| 344 | 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 | 418 | // TODO: re-implement EditTransform using Qt |
| 347 | 419 | #if 0 |
| 348 | 420 | /*! | ... | ... |
openbr/plugins/eigen3.cpp
| ... | ... | @@ -302,8 +302,8 @@ class LDATransform : public Transform |
| 302 | 302 | Q_PROPERTY(int directLDA READ get_directLDA WRITE set_directLDA RESET reset_directLDA STORED false) |
| 303 | 303 | Q_PROPERTY(float directDrop READ get_directDrop WRITE set_directDrop RESET reset_directDrop STORED false) |
| 304 | 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 | 307 | BR_PROPERTY(float, pcaKeep, 0.98) |
| 308 | 308 | BR_PROPERTY(bool, pcaWhiten, false) |
| 309 | 309 | BR_PROPERTY(int, directLDA, 0) |
| ... | ... | @@ -316,12 +316,6 @@ class LDATransform : public Transform |
| 316 | 316 | Eigen::VectorXf mean; |
| 317 | 317 | Eigen::MatrixXf projection; |
| 318 | 318 | float stdDev; |
| 319 | - bool trained; | |
| 320 | - | |
| 321 | - void init() | |
| 322 | - { | |
| 323 | - trained = false; | |
| 324 | - } | |
| 325 | 319 | |
| 326 | 320 | void train(const TemplateList &_trainingSet) |
| 327 | 321 | { |
| ... | ... | @@ -461,9 +455,9 @@ class LDATransform : public Transform |
| 461 | 455 | projection = ((space2.eVecs.transpose() * space1.eVecs.transpose()) * pca.eVecs.transpose()).transpose(); |
| 462 | 456 | dimsOut = dim2; |
| 463 | 457 | |
| 458 | + stdDev = 1; // default initialize | |
| 464 | 459 | if (isBinary) { |
| 465 | 460 | assert(dimsOut == 1); |
| 466 | - TemplateList projected; | |
| 467 | 461 | float posVal = 0; |
| 468 | 462 | float negVal = 0; |
| 469 | 463 | Eigen::MatrixXf results(trainingSet.size(),1); |
| ... | ... | @@ -493,8 +487,6 @@ class LDATransform : public Transform |
| 493 | 487 | if (normalize) |
| 494 | 488 | stdDev = sqrt(results.array().square().sum() / trainingSet.size()); |
| 495 | 489 | } |
| 496 | - | |
| 497 | - trained = true; | |
| 498 | 490 | } |
| 499 | 491 | |
| 500 | 492 | void project(const Template &src, Template &dst) const |
| ... | ... | @@ -508,18 +500,22 @@ class LDATransform : public Transform |
| 508 | 500 | // Do projection |
| 509 | 501 | outMap = projection.transpose() * (inMap - mean); |
| 510 | 502 | |
| 511 | - if (normalize && isBinary && trained) | |
| 503 | + if (normalize && isBinary) | |
| 512 | 504 | dst.m().at<float>(0,0) = dst.m().at<float>(0,0) / stdDev; |
| 513 | 505 | } |
| 514 | 506 | |
| 515 | 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 | 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
openbr/plugins/format.cpp
| ... | ... | @@ -16,10 +16,12 @@ |
| 16 | 16 | |
| 17 | 17 | #include <QDate> |
| 18 | 18 | #include <QSize> |
| 19 | +#include <QChar> | |
| 19 | 20 | #ifndef BR_EMBEDDED |
| 20 | 21 | #include <QtXml> |
| 21 | 22 | #endif // BR_EMBEDDED |
| 22 | 23 | #include <opencv2/highgui/highgui.hpp> |
| 24 | +#include <opencv2/highgui/highgui_c.h> | |
| 23 | 25 | #include "openbr_internal.h" |
| 24 | 26 | |
| 25 | 27 | #include "openbr/core/bee.h" |
| ... | ... | @@ -719,7 +721,7 @@ BR_REGISTER(Format, xmlFormat) |
| 719 | 721 | /*! |
| 720 | 722 | * \ingroup formats |
| 721 | 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 | 726 | * Example of the format: |
| 725 | 727 | * \code |
| ... | ... | @@ -768,6 +770,90 @@ class scoresFormat : public Format |
| 768 | 770 | |
| 769 | 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 | 857 | } // namespace br |
| 772 | 858 | |
| 773 | 859 | #include "format.moc" | ... | ... |
openbr/plugins/gallery.cpp
| ... | ... | @@ -32,6 +32,11 @@ |
| 32 | 32 | #include "openbr/core/opencvutils.h" |
| 33 | 33 | #include "openbr/core/qtutils.h" |
| 34 | 34 | |
| 35 | +#ifdef CVMATIO | |
| 36 | +#include "MatlabIO.hpp" | |
| 37 | +#include "MatlabIOContainer.hpp" | |
| 38 | +#endif | |
| 39 | + | |
| 35 | 40 | namespace br |
| 36 | 41 | { |
| 37 | 42 | |
| ... | ... | @@ -969,6 +974,74 @@ class landmarksGallery : public Gallery |
| 969 | 974 | |
| 970 | 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 | 1045 | } // namespace br |
| 973 | 1046 | |
| 974 | 1047 | #include "gallery.moc" | ... | ... |
openbr/plugins/gui.cpp
openbr/plugins/hist.cpp
| ... | ... | @@ -94,7 +94,7 @@ class BinTransform : public UntrainableTransform |
| 94 | 94 | } else if (channels == 2) { |
| 95 | 95 | // If there are two channels, the first is channel is assumed to be a weight vector |
| 96 | 96 | // and the second channel contains the vectors we would like to bin. |
| 97 | - vector<Mat> mv; | |
| 97 | + std::vector<Mat> mv; | |
| 98 | 98 | cv::split(src, mv); |
| 99 | 99 | weights = mv[0]; |
| 100 | 100 | weights.convertTo(weights, CV_32F); | ... | ... |
openbr/plugins/integral.cpp
| 1 | 1 | #include <opencv2/imgproc/imgproc.hpp> |
| 2 | +#include <opencv2/imgproc/imgproc_c.h> | |
| 2 | 3 | #include <Eigen/Core> |
| 3 | 4 | #include "openbr_internal.h" |
| 4 | 5 | |
| ... | ... | @@ -293,7 +294,7 @@ private: |
| 293 | 294 | Sobel(src, dx, CV_32F, 1, 0, CV_SCHARR); |
| 294 | 295 | Sobel(src, dy, CV_32F, 0, 1, CV_SCHARR); |
| 295 | 296 | cartToPolar(dx, dy, magnitude, angle, true); |
| 296 | - vector<Mat> mv; | |
| 297 | + std::vector<Mat> mv; | |
| 297 | 298 | if ((channel == Magnitude) || (channel == MagnitudeAndAngle)) { |
| 298 | 299 | const float theoreticalMaxMagnitude = sqrt(2*pow(float(2*(3+10+3)*255), 2.f)); |
| 299 | 300 | mv.push_back(magnitude / theoreticalMaxMagnitude); | ... | ... |
openbr/plugins/landmarks.cpp
| ... | ... | @@ -290,16 +290,18 @@ class DrawDelaunayTransform : public UntrainableTransform |
| 290 | 290 | |
| 291 | 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 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | |
| 18 | 19 | #include <opencv2/highgui/highgui.hpp> |
| 20 | +#include <opencv2/highgui/highgui_c.h> | |
| 19 | 21 | #include <limits> |
| 20 | 22 | #include "openbr_internal.h" |
| 21 | 23 | ... | ... |
openbr/plugins/ltp.cpp
openbr/plugins/mask.cpp
| ... | ... | @@ -15,6 +15,7 @@ |
| 15 | 15 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 16 | 16 | |
| 17 | 17 | #include <opencv2/imgproc/imgproc.hpp> |
| 18 | +#include <opencv2/imgproc/imgproc_c.h> | |
| 18 | 19 | #include "openbr_internal.h" |
| 19 | 20 | |
| 20 | 21 | using namespace cv; |
| ... | ... | @@ -164,7 +165,7 @@ class LargestConvexAreaTransform : public UntrainableTransform |
| 164 | 165 | void project(const Template &src, Template &dst) const |
| 165 | 166 | { |
| 166 | 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 | 169 | double maxArea = 0; |
| 169 | 170 | foreach (const std::vector<Point> &contour, contours) { |
| 170 | 171 | std::vector<Point> hull; | ... | ... |
openbr/plugins/misc.cpp
| ... | ... | @@ -537,7 +537,7 @@ class ProgressCounterTransform : public TimeVaryingTransform |
| 537 | 537 | { |
| 538 | 538 | (void) data; |
| 539 | 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 | 543 | void init() | ... | ... |
openbr/plugins/motion.cpp
| ... | ... | @@ -23,6 +23,7 @@ class OpticalFlowTransform : public UntrainableMetaTransform |
| 23 | 23 | Q_PROPERTY(int poly_n READ get_poly_n WRITE set_poly_n RESET reset_poly_n STORED false) |
| 24 | 24 | Q_PROPERTY(double poly_sigma READ get_poly_sigma WRITE set_poly_sigma RESET reset_poly_sigma STORED false) |
| 25 | 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 | 27 | // these defaults are optimized for KTH |
| 27 | 28 | BR_PROPERTY(double, pyr_scale, 0.1) |
| 28 | 29 | BR_PROPERTY(int, levels, 1) |
| ... | ... | @@ -31,22 +32,27 @@ class OpticalFlowTransform : public UntrainableMetaTransform |
| 31 | 32 | BR_PROPERTY(int, poly_n, 7) |
| 32 | 33 | BR_PROPERTY(double, poly_sigma, 1.1) |
| 33 | 34 | BR_PROPERTY(int, flags, 0) |
| 35 | + BR_PROPERTY(bool, useMagnitude, true) | |
| 34 | 36 | |
| 35 | 37 | void project(const Template &src, Template &dst) const |
| 36 | 38 | { |
| 37 | 39 | // get the two images put there by AggregateFrames |
| 38 | 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 | 42 | if (src[0].channels() != 1) OpenCVUtils::cvtGray(src[0], prevImg); |
| 41 | 43 | if (src[1].channels() != 1) OpenCVUtils::cvtGray(src[1], nextImg); |
| 42 | 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 | 56 | dst.file = src.file; |
| 51 | 57 | } |
| 52 | 58 | }; |
| ... | ... | @@ -62,7 +68,8 @@ class SubtractBackgroundTransform : public TimeVaryingTransform |
| 62 | 68 | { |
| 63 | 69 | Q_OBJECT |
| 64 | 70 | |
| 65 | - BackgroundSubtractorMOG2 mog; | |
| 71 | + // TODO: This is broken. | |
| 72 | + // BackgroundSubtractorMOG2 mog; | |
| 66 | 73 | |
| 67 | 74 | public: |
| 68 | 75 | SubtractBackgroundTransform() : TimeVaryingTransform(false, false) {} |
| ... | ... | @@ -72,7 +79,8 @@ private: |
| 72 | 79 | { |
| 73 | 80 | dst = src; |
| 74 | 81 | Mat mask; |
| 75 | - mog(src, mask); | |
| 82 | + // TODO: broken | |
| 83 | + // mog(src, mask); | |
| 76 | 84 | erode(mask, mask, Mat()); |
| 77 | 85 | dilate(mask, mask, Mat()); |
| 78 | 86 | dst.file.set("Mask", QVariant::fromValue(mask)); |
| ... | ... | @@ -86,7 +94,8 @@ private: |
| 86 | 94 | void finalize(TemplateList &output) |
| 87 | 95 | { |
| 88 | 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 | 60 | |
| 61 | 61 | Q_PROPERTY(bool ByRow READ get_ByRow WRITE set_ByRow RESET reset_ByRow STORED false) |
| 62 | 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 | 68 | public: |
| 65 | 69 | /*!< */ |
| 66 | 70 | enum NormType { Inf = NORM_INF, |
| 67 | 71 | L1 = NORM_L1, |
| 68 | - L2 = NORM_L2 }; | |
| 72 | + L2 = NORM_L2, | |
| 73 | + Range = NORM_MINMAX }; | |
| 69 | 74 | |
| 70 | 75 | private: |
| 71 | 76 | BR_PROPERTY(NormType, normType, L2) |
| 72 | 77 | |
| 73 | 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 | 81 | else { |
| 77 | 82 | dst = src; |
| 78 | 83 | for (int i=0; i<dst.m().rows; i++) { |
| 79 | 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 | 86 | temp.copyTo(dst.m().row(i)); |
| 82 | 87 | } |
| 83 | 88 | } |
| ... | ... | @@ -132,7 +137,7 @@ private: |
| 132 | 137 | const QList<int> labels = data.indexProperty(inputVariable); |
| 133 | 138 | const int dims = m.cols; |
| 134 | 139 | |
| 135 | - vector<Mat> mv, av, bv; | |
| 140 | + std::vector<Mat> mv, av, bv; | |
| 136 | 141 | split(m, mv); |
| 137 | 142 | for (size_t c = 0; c < mv.size(); c++) { |
| 138 | 143 | av.push_back(Mat(1, dims, CV_64FC1)); | ... | ... |
openbr/plugins/output.cpp
| ... | ... | @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput |
| 268 | 268 | |
| 269 | 269 | for (int i=0; i<queryFiles.size(); i++) { |
| 270 | 270 | QStringList files; |
| 271 | - if (simple) files.append(queryFiles[i]); | |
| 271 | + if (simple) files.append(queryFiles[i].fileName()); | |
| 272 | 272 | |
| 273 | 273 | typedef QPair<float,int> Pair; |
| 274 | 274 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true, limit)) { |
| ... | ... | @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput |
| 276 | 276 | if (pair.first < threshold) break; |
| 277 | 277 | File target = targetFiles[pair.second]; |
| 278 | 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 | 280 | else files.append(target.flat()); |
| 281 | 281 | } |
| 282 | 282 | } |
| ... | ... | @@ -528,7 +528,7 @@ class tailOutput : public Output |
| 528 | 528 | } else { |
| 529 | 529 | // General case |
| 530 | 530 | for (int k=0; k<comparisons.size(); k++) { |
| 531 | - if (comparisons[k].value < value) { | |
| 531 | + if (comparisons[k].value <= value) { | |
| 532 | 532 | comparisons.insert(k, Comparison(queryFiles[i], targetFiles[j], value)); |
| 533 | 533 | break; |
| 534 | 534 | } |
| ... | ... | @@ -539,6 +539,7 @@ class tailOutput : public Output |
| 539 | 539 | comparisons.removeLast(); |
| 540 | 540 | while ((comparisons.size() > atLeast) && (comparisons.last().value < threshold)) |
| 541 | 541 | comparisons.removeLast(); |
| 542 | + | |
| 542 | 543 | lastValue = comparisons.last().value; |
| 543 | 544 | comparisonsLock.unlock(); |
| 544 | 545 | } | ... | ... |
openbr/plugins/process.cpp
| ... | ... | @@ -531,8 +531,6 @@ class ProcessWrapperTransform : public TimeVaryingTransform |
| 531 | 531 | baseKey = id.toString(); |
| 532 | 532 | |
| 533 | 533 | QStringList argumentList; |
| 534 | - argumentList.append("-useGui"); | |
| 535 | - argumentList.append("0"); | |
| 536 | 534 | argumentList.append("-algorithm"); |
| 537 | 535 | argumentList.append(transform); |
| 538 | 536 | if (!Globals->path.isEmpty()) { | ... | ... |
openbr/plugins/quality.cpp
| ... | ... | @@ -272,92 +272,75 @@ BR_REGISTER(Distance, ZScoreDistance) |
| 272 | 272 | |
| 273 | 273 | /*! |
| 274 | 274 | * \ingroup distances |
| 275 | - * \brief Match Probability modification for heat maps \cite klare12 | |
| 275 | + * \brief 1v1 heat map comparison | |
| 276 | 276 | * \author Scott Klum \cite sklum |
| 277 | 277 | */ |
| 278 | 278 | class HeatMapDistance : public Distance |
| 279 | 279 | { |
| 280 | 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 | 282 | Q_PROPERTY(int step READ get_step WRITE set_step RESET reset_step STORED false) |
| 285 | 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 | 285 | BR_PROPERTY(int, step, 1) |
| 290 | 286 | BR_PROPERTY(QString, inputVariable, "Label") |
| 291 | 287 | |
| 292 | - QList<MP> mp; | |
| 288 | + QList<br::Distance*> distances; | |
| 293 | 289 | |
| 294 | 290 | void train(const TemplateList &src) |
| 295 | 291 | { |
| 296 | - distance->train(src); | |
| 297 | - | |
| 298 | - const QList<int> labels = src.indexProperty(inputVariable); | |
| 299 | - | |
| 300 | 292 | QList<TemplateList> patches; |
| 301 | 293 | |
| 302 | 294 | // Split src into list of TemplateLists of corresponding patches across all Templates |
| 303 | 295 | for (int i=0; i<step; i++) { |
| 304 | 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 | 299 | patches.append(patchBuffer); |
| 309 | 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 | 311 | float compare(const Template &target, const Template &query) const |
| 334 | 312 | { |
| 335 | 313 | (void) target; |
| 336 | 314 | (void) query; |
| 337 | - qFatal("You did this wrong"); | |
| 315 | + qFatal("Heatmap Distance not compatible with Template to Template comparison."); | |
| 338 | 316 | |
| 339 | 317 | return 0; |
| 340 | 318 | } |
| 341 | 319 | |
| 342 | 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 | 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 | 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 | 35 | |
| 36 | 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 | 39 | Globals->abbreviations.insert("RectFromStasmBrow","RectFromPoints([16,17,18,19,20,21,22,23,24,25,26,27],0.15,5)"); |
| 40 | 40 | Globals->abbreviations.insert("RectFromStasmNose","RectFromPoints([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58],0.15,1.15)"); |
| 41 | 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 | 2 | #include <QReadWriteLock> |
| 2 | 3 | #include <QWaitCondition> |
| 3 | 4 | #include <QThreadPool> |
| 4 | 5 | #include <QSemaphore> |
| 5 | 6 | #include <QMap> |
| 6 | -#include <opencv/highgui.h> | |
| 7 | +#include <QQueue> | |
| 7 | 8 | #include <QtConcurrent> |
| 9 | +#include <opencv/highgui.h> | |
| 10 | +#include <opencv2/highgui/highgui.hpp> | |
| 8 | 11 | #include "openbr_internal.h" |
| 9 | - | |
| 10 | 12 | #include "openbr/core/common.h" |
| 11 | 13 | #include "openbr/core/opencvutils.h" |
| 12 | 14 | #include "openbr/core/qtutils.h" |
| 13 | 15 | |
| 14 | 16 | using namespace cv; |
| 17 | +using namespace std; | |
| 15 | 18 | |
| 16 | 19 | namespace br |
| 17 | 20 | { |
| ... | ... | @@ -203,6 +206,13 @@ public: |
| 203 | 206 | virtual bool getNextTemplate(Template & output)=0; |
| 204 | 207 | protected: |
| 205 | 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 | 218 | static QMutex openLock; |
| ... | ... | @@ -236,12 +246,9 @@ public: |
| 236 | 246 | qDebug("Video not open!"); |
| 237 | 247 | } |
| 238 | 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 | 249 | // On windows, this appears to not be thread-safe |
| 243 | 250 | QMutexLocker lock(&openLock); |
| 244 | - video.open(QFileInfo(fileName).absoluteFilePath().toStdString()); | |
| 251 | + video.open(getAbsolutePath(input.file.name)); | |
| 245 | 252 | } |
| 246 | 253 | |
| 247 | 254 | return video.isOpened(); |
| ... | ... | @@ -319,6 +326,198 @@ protected: |
| 319 | 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 | 522 | // Interface for sequentially getting data from some data source. |
| 324 | 523 | // Given a TemplateList, return single template frames sequentially by applying a TemplateProcessor |
| ... | ... | @@ -514,11 +713,16 @@ protected: |
| 514 | 713 | if (frameSource) |
| 515 | 714 | frameSource->close(); |
| 516 | 715 | |
| 716 | + Template curr = this->templates[current_template_idx]; | |
| 517 | 717 | if (mode == br::Idiocy::Auto) |
| 518 | 718 | { |
| 519 | 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 | 726 | else |
| 523 | 727 | frameSource = new DirectReturn(); |
| 524 | 728 | } |
| ... | ... | @@ -529,11 +733,14 @@ protected: |
| 529 | 733 | } |
| 530 | 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 | 744 | if (!open_res) |
| 538 | 745 | { |
| 539 | 746 | current_template_idx++; |
| ... | ... | @@ -1079,8 +1286,7 @@ public: |
| 1079 | 1286 | |
| 1080 | 1287 | // Wait for the stream to process the last frame available from |
| 1081 | 1288 | // the data source. |
| 1082 | - bool wait_res = false; | |
| 1083 | - wait_res = readStage->dataSource.waitLast(); | |
| 1289 | + readStage->dataSource.waitLast(); | |
| 1084 | 1290 | |
| 1085 | 1291 | // Now that there are no more incoming frames, call finalize |
| 1086 | 1292 | // on each transform in turn to collect any last templates |
| ... | ... | @@ -1217,6 +1423,7 @@ public: |
| 1217 | 1423 | { |
| 1218 | 1424 | // Delete all the stages |
| 1219 | 1425 | for (int i = 0; i < processingStages.size(); i++) { |
| 1426 | +// TODO: Are we releasing memory which is already freed? | |
| 1220 | 1427 | delete processingStages[i]; |
| 1221 | 1428 | } |
| 1222 | 1429 | processingStages.clear(); | ... | ... |
scripts/downloadDatasets.sh
| ... | ... | @@ -35,6 +35,35 @@ if [ ! -d ../data/BioID/img ]; then |
| 35 | 35 | rm *.eye description.txt BioID-FaceDatabase-V1.2.zip |
| 36 | 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 | 67 | # INRIA person |
| 39 | 68 | if [ ! -d ../data/INRIAPerson/img ]; then |
| 40 | 69 | echo "Downloading INRIA person dataset..." |
| ... | ... | @@ -66,7 +95,7 @@ if [ ! -d ../data/KTH/vid ]; then |
| 66 | 95 | fi |
| 67 | 96 | mkdir ../data/KTH/vid/${vidclass} |
| 68 | 97 | unzip ${vidclass}.zip -d ../data/KTH/vid/${vidclass} |
| 69 | - rm ${vidclass}.zip | |
| 98 | + rm ${vidclass}.zip | |
| 70 | 99 | done |
| 71 | 100 | # this file is corrupted |
| 72 | 101 | rm -f ../data/KTH/vid/boxing/person01_boxing_d4_uncomp.avi | ... | ... |
scripts/evalAgeRegression-PCSO.sh
scripts/evalFaceRecognition-LFW.sh
| ... | ... | @@ -20,7 +20,7 @@ if [ ! -e Algorithm_Dataset ]; then |
| 20 | 20 | fi |
| 21 | 21 | |
| 22 | 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 | 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 | 20 | fi |
| 21 | 21 | |
| 22 | 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 | 24 | fi |
| 25 | 25 | |
| 26 | 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 | 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 | 9 | export PCSO_DIR=../data/PCSO/img |
| 10 | 10 | |
| 11 | 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 | 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 | 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 | 17 | \ No newline at end of file | ... | ... |
scripts/pedestrianBaselineLBP.sh
scripts/trainAgeRegression-PCSO.sh
| ... | ... | @@ -13,4 +13,4 @@ export ageAlg=AgeRegression |
| 13 | 13 | |
| 14 | 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 | 14 | |
| 15 | 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 | 13 | |
| 14 | 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 | 8 | # target_link_libraries(MY_TARGET_NAME ${OPENBR_LIBS}) |
| 9 | 9 | # ================================================================ |
| 10 | 10 | |
| 11 | +find_path(OPENBR_DIR include/openbr/openbr.h) | |
| 11 | 12 | include_directories(${OPENBR_DIR}/include) |
| 12 | 13 | link_directories(${OPENBR_DIR}/lib) |
| 13 | 14 | set(OPENBR_LIBS "openbr") | ... | ... |