Commit be996aacdff87778e92e38f33ffe46357798c83f
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
21 changed files
with
410 additions
and
119 deletions
CMakeLists.txt
| @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8.9) | @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8.9) | ||
| 3 | 3 | ||
| 4 | # Global settings | 4 | # Global settings |
| 5 | set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr") | 5 | set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr") |
| 6 | +set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts") | ||
| 6 | set(CMAKE_AUTOMOC ON) | 7 | set(CMAKE_AUTOMOC ON) |
| 7 | set(CPACK_PACKAGE_NAME "OpenBR") | 8 | set(CPACK_PACKAGE_NAME "OpenBR") |
| 8 | set(CPACK_PACKAGE_VENDOR "OpenBiometrics") | 9 | set(CPACK_PACKAGE_VENDOR "OpenBiometrics") |
| @@ -117,7 +118,7 @@ if(BUILD_TESTING) | @@ -117,7 +118,7 @@ if(BUILD_TESTING) | ||
| 117 | endif() | 118 | endif() |
| 118 | 119 | ||
| 119 | # Build the SDK | 120 | # Build the SDK |
| 120 | -include_directories(.) | 121 | +include_directories(BEFORE .) # Find the local headers first |
| 121 | add_subdirectory(openbr) | 122 | add_subdirectory(openbr) |
| 122 | 123 | ||
| 123 | # Build applications | 124 | # Build applications |
| @@ -138,6 +139,14 @@ install(FILES CHANGELOG.md LICENSE.txt README.md DESTINATION .) | @@ -138,6 +139,14 @@ install(FILES CHANGELOG.md LICENSE.txt README.md DESTINATION .) | ||
| 138 | install(DIRECTORY share DESTINATION .) | 139 | install(DIRECTORY share DESTINATION .) |
| 139 | install(DIRECTORY ${BR_THIRDPARTY_SHARE} DESTINATION share) | 140 | install(DIRECTORY ${BR_THIRDPARTY_SHARE} DESTINATION share) |
| 140 | 141 | ||
| 142 | +# install brpy | ||
| 143 | +option(BR_INSTALL_BRPY "Install brpy, the Python wrapper to the C API (requires Python)") | ||
| 144 | +if(${BR_INSTALL_BRPY}) | ||
| 145 | + find_package(PythonInterp REQUIRED) | ||
| 146 | + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import site, sys; sys.stdout.write(site.getsitepackages()[-1])" OUTPUT_VARIABLE PYTHON_SITE_DIR) | ||
| 147 | + install(DIRECTORY ${BR_SCRIPTS_DIR}/brpy DESTINATION ${PYTHON_SITE_DIR}) | ||
| 148 | +endif() | ||
| 149 | + | ||
| 141 | # Package | 150 | # Package |
| 142 | set(CPACK_PACKAGE_EXECUTABLES "OpenBR" "OpenBR") | 151 | set(CPACK_PACKAGE_EXECUTABLES "OpenBR" "OpenBR") |
| 143 | set(CPACK_CREATE_DESKTOP_LINKS "OpenBR") | 152 | set(CPACK_CREATE_DESKTOP_LINKS "OpenBR") |
openbr/core/core.cpp
| @@ -56,11 +56,6 @@ struct AlgorithmCore | @@ -56,11 +56,6 @@ struct AlgorithmCore | ||
| 56 | 56 | ||
| 57 | TemplateList data(TemplateList::fromGallery(input)); | 57 | TemplateList data(TemplateList::fromGallery(input)); |
| 58 | 58 | ||
| 59 | - // set the Train bool metadata, in case a Transform's project | ||
| 60 | - // needs to know if it's called during train or enroll | ||
| 61 | - for (int i=0; i<data.size(); i++) | ||
| 62 | - data[i].file.set("Train", true); | ||
| 63 | - | ||
| 64 | if (transform.isNull()) qFatal("Null transform."); | 59 | if (transform.isNull()) qFatal("Null transform."); |
| 65 | qDebug("%d Training Files", data.size()); | 60 | qDebug("%d Training Files", data.size()); |
| 66 | 61 | ||
| @@ -153,9 +148,12 @@ struct AlgorithmCore | @@ -153,9 +148,12 @@ struct AlgorithmCore | ||
| 153 | if (data.empty()) | 148 | if (data.empty()) |
| 154 | return files; | 149 | return files; |
| 155 | 150 | ||
| 151 | + // Store steps for ProgressCounter | ||
| 152 | + Globals->currentStep = 0; | ||
| 153 | + Globals->totalSteps = data.length(); | ||
| 154 | + | ||
| 156 | // Trust me, this makes complete sense. | 155 | // Trust me, this makes complete sense. |
| 157 | // We're just going to make a pipe with a placeholder first transform | 156 | // We're just going to make a pipe with a placeholder first transform |
| 158 | - Globals->totalSteps = data.length(); | ||
| 159 | QString pipeDesc = "Identity+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard"; | 157 | QString pipeDesc = "Identity+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard"; |
| 160 | QScopedPointer<Transform> basePipe(Transform::make(pipeDesc,NULL)); | 158 | QScopedPointer<Transform> basePipe(Transform::make(pipeDesc,NULL)); |
| 161 | 159 | ||
| @@ -430,6 +428,13 @@ void br::Compare(const File &targetGallery, const File &queryGallery, const File | @@ -430,6 +428,13 @@ void br::Compare(const File &targetGallery, const File &queryGallery, const File | ||
| 430 | AlgorithmManager::getAlgorithm(output.get<QString>("algorithm"))->compare(targetGallery, queryGallery, output); | 428 | AlgorithmManager::getAlgorithm(output.get<QString>("algorithm"))->compare(targetGallery, queryGallery, output); |
| 431 | } | 429 | } |
| 432 | 430 | ||
| 431 | +void br::CompareTemplateLists(const TemplateList &target, const TemplateList &query, Output *output) | ||
| 432 | +{ | ||
| 433 | + QString alg = output->file.get<QString>("algorithm"); | ||
| 434 | + QSharedPointer<Distance> dist = Distance::fromAlgorithm(alg); | ||
| 435 | + dist->compare(target, query, output); | ||
| 436 | +} | ||
| 437 | + | ||
| 433 | void br::PairwiseCompare(const File &targetGallery, const File &queryGallery, const File &output) | 438 | void br::PairwiseCompare(const File &targetGallery, const File &queryGallery, const File &output) |
| 434 | { | 439 | { |
| 435 | AlgorithmManager::getAlgorithm(output.get<QString>("algorithm"))->pairwiseCompare(targetGallery, queryGallery, output); | 440 | AlgorithmManager::getAlgorithm(output.get<QString>("algorithm"))->pairwiseCompare(targetGallery, queryGallery, output); |
| @@ -456,7 +461,7 @@ void br::Convert(const File &fileType, const File &inputFile, const File &output | @@ -456,7 +461,7 @@ void br::Convert(const File &fileType, const File &inputFile, const File &output | ||
| 456 | 461 | ||
| 457 | if ((targetFiles.size() != m.cols || queryFiles.size() != m.rows) | 462 | if ((targetFiles.size() != m.cols || queryFiles.size() != m.rows) |
| 458 | && (m.cols != 1 || targetFiles.size() != m.rows || queryFiles.size() != m.rows)) | 463 | && (m.cols != 1 || targetFiles.size() != m.rows || queryFiles.size() != m.rows)) |
| 459 | - qFatal("Similarity matrix and file size mismatch."); | 464 | + qFatal("Similarity matrix (%d, %d) and header (%d, %d) size mismatch.", m.rows, m.cols, queryFiles.size(), targetFiles.size()); |
| 460 | 465 | ||
| 461 | QSharedPointer<Output> o(Factory<Output>::make(outputFile)); | 466 | QSharedPointer<Output> o(Factory<Output>::make(outputFile)); |
| 462 | o->initialize(targetFiles, queryFiles); | 467 | o->initialize(targetFiles, queryFiles); |
openbr/core/fuse.cpp
| @@ -30,6 +30,9 @@ using namespace cv; | @@ -30,6 +30,9 @@ using namespace cv; | ||
| 30 | 30 | ||
| 31 | static void normalizeMatrix(Mat &matrix, const Mat &mask, const QString &method) | 31 | static void normalizeMatrix(Mat &matrix, const Mat &mask, const QString &method) |
| 32 | { | 32 | { |
| 33 | + if (matrix.rows != mask.rows && matrix.cols != mask.cols) | ||
| 34 | + qFatal("Similarity matrix (%d, %d) and mask (%d, %d) size mismatch.", matrix.rows, matrix.cols, mask.rows, mask.cols); | ||
| 35 | + | ||
| 33 | if (method == "None") return; | 36 | if (method == "None") return; |
| 34 | 37 | ||
| 35 | QList<float> vals; vals.reserve(matrix.rows*matrix.cols); | 38 | QList<float> vals; vals.reserve(matrix.rows*matrix.cols); |
openbr/gui/progress.cpp
| @@ -26,7 +26,7 @@ br::Progress::Progress(QWidget *parent) | @@ -26,7 +26,7 @@ br::Progress::Progress(QWidget *parent) | ||
| 26 | void br::Progress::checkProgress() | 26 | void br::Progress::checkProgress() |
| 27 | { | 27 | { |
| 28 | const int progress = 100 * br_progress(); | 28 | const int progress = 100 * br_progress(); |
| 29 | - const bool visible = progress >= 0; | 29 | + const bool visible = progress >= 0 && progress < 100; |
| 30 | 30 | ||
| 31 | if (visible) { | 31 | if (visible) { |
| 32 | showMessage(br_most_recent_message()); | 32 | showMessage(br_most_recent_message()); |
openbr/gui/utility.cpp
| 1 | -#include <QImage> | ||
| 2 | #include <limits> | 1 | #include <limits> |
| 3 | #include <vector> | 2 | #include <vector> |
| 4 | #include <opencv2/imgproc/imgproc.hpp> | 3 | #include <opencv2/imgproc/imgproc.hpp> |
| 4 | +#include "utility.h" | ||
| 5 | 5 | ||
| 6 | using namespace cv; | 6 | using namespace cv; |
| 7 | 7 | ||
| 8 | -/**** STATIC ****/ | ||
| 9 | -QImage toQImage(const Mat &mat) | 8 | +QImage br::toQImage(const Mat &mat) |
| 10 | { | 9 | { |
| 11 | // Convert to 8U depth | 10 | // Convert to 8U depth |
| 12 | Mat mat8u; | 11 | Mat mat8u; |
openbr/gui/utility.h
| @@ -3,7 +3,13 @@ | @@ -3,7 +3,13 @@ | ||
| 3 | 3 | ||
| 4 | #include <QImage> | 4 | #include <QImage> |
| 5 | #include <opencv2/core/core.hpp> | 5 | #include <opencv2/core/core.hpp> |
| 6 | +#include <openbr/openbr_export.h> | ||
| 6 | 7 | ||
| 7 | -QImage toQImage(const cv::Mat &mat); | 8 | +namespace br |
| 9 | +{ | ||
| 10 | + | ||
| 11 | +BR_EXPORT QImage toQImage(const cv::Mat &mat); | ||
| 12 | + | ||
| 13 | +} // namespace br | ||
| 8 | 14 | ||
| 9 | #endif // BR_UTILITY_H | 15 | #endif // BR_UTILITY_H |
openbr/janus.cpp
| @@ -80,7 +80,7 @@ janus_error janus_finalize_template(janus_incomplete_template incomplete_templat | @@ -80,7 +80,7 @@ janus_error janus_finalize_template(janus_incomplete_template incomplete_templat | ||
| 80 | templateBytes = currentTemplateBytes; | 80 | templateBytes = currentTemplateBytes; |
| 81 | if (templateBytes != currentTemplateBytes) | 81 | if (templateBytes != currentTemplateBytes) |
| 82 | return JANUS_UNKNOWN_ERROR; | 82 | return JANUS_UNKNOWN_ERROR; |
| 83 | - if (*bytes + templateBytes > JANUS_MAX_TEMPLATE_SIZE) | 83 | + if (*bytes + templateBytes > janus_max_template_size()) |
| 84 | break; | 84 | break; |
| 85 | memcpy(pos, m.data, templateBytes); | 85 | memcpy(pos, m.data, templateBytes); |
| 86 | *bytes += templateBytes; | 86 | *bytes += templateBytes; |
| @@ -94,21 +94,49 @@ janus_error janus_finalize_template(janus_incomplete_template incomplete_templat | @@ -94,21 +94,49 @@ janus_error janus_finalize_template(janus_incomplete_template incomplete_templat | ||
| 94 | return JANUS_SUCCESS; | 94 | return JANUS_SUCCESS; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | -janus_error janus_verify(const janus_template a, const janus_template b, float *similarity) | 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) |
| 98 | { | 98 | { |
| 99 | - size_t a_bytes, a_templates, b_bytes, b_templates; | ||
| 100 | - a_bytes = *(reinterpret_cast<size_t*>(a)+0); | 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); | ||
| 101 | a_templates = *(reinterpret_cast<size_t*>(a)+1); | 104 | a_templates = *(reinterpret_cast<size_t*>(a)+1); |
| 102 | - b_bytes = *(reinterpret_cast<size_t*>(b)+0); | 105 | + b_template_bytes = *(reinterpret_cast<size_t*>(b)+0); |
| 103 | b_templates = *(reinterpret_cast<size_t*>(b)+1); | 106 | b_templates = *(reinterpret_cast<size_t*>(b)+1); |
| 104 | - if (a_bytes != b_bytes) | 107 | + if (a_template_bytes != b_template_bytes) |
| 105 | return JANUS_UNKNOWN_ERROR; | 108 | return JANUS_UNKNOWN_ERROR; |
| 106 | 109 | ||
| 107 | float dist = 0; | 110 | float dist = 0; |
| 108 | for (size_t i=0; i<a_templates; i++) | 111 | for (size_t i=0; i<a_templates; i++) |
| 109 | for (size_t j=0; j<b_templates; j++) | 112 | for (size_t j=0; j<b_templates; j++) |
| 110 | - dist += distance->compare(cv::Mat(1, a_bytes, CV_8UC1, a+2*sizeof(size_t)+i*a_bytes), | ||
| 111 | - cv::Mat(1, b_bytes, CV_8UC1, b+2*sizeof(size_t)+i*b_bytes)); | 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)); | ||
| 112 | *similarity = a_templates * b_templates / dist; | 115 | *similarity = a_templates * b_templates / dist; |
| 113 | return JANUS_SUCCESS; | 116 | return JANUS_SUCCESS; |
| 114 | } | 117 | } |
| 118 | + | ||
| 119 | +struct janus_incomplete_gallery_type | ||
| 120 | +{ | ||
| 121 | + QList< QPair<janus_template, janus_template_id> > templates; | ||
| 122 | +}; | ||
| 123 | + | ||
| 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 | +} | ||
| 129 | + | ||
| 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)); | ||
| 134 | + return JANUS_SUCCESS; | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +janus_error janus_finalize_gallery(janus_incomplete_gallery incomplete_gallery, const char *gallery_file) | ||
| 138 | +{ | ||
| 139 | + (void) incomplete_gallery; | ||
| 140 | + (void) gallery_file; | ||
| 141 | + return JANUS_SUCCESS; | ||
| 142 | +} |
openbr/openbr.cpp
| @@ -53,6 +53,12 @@ void br_compare(const char *target_gallery, const char *query_gallery, const cha | @@ -53,6 +53,12 @@ void br_compare(const char *target_gallery, const char *query_gallery, const cha | ||
| 53 | Compare(File(target_gallery), File(query_gallery), File(output)); | 53 | Compare(File(target_gallery), File(query_gallery), File(output)); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | +void br_compare_n(int num_targets, const char *target_galleries[], const char *query_gallery, const char *output) | ||
| 57 | +{ | ||
| 58 | + if (num_targets > 1) Compare(QtUtils::toStringList(num_targets, target_galleries).join(";")+"(separator=;)", File(query_gallery), File(output)); | ||
| 59 | + else Compare(File(target_galleries[0]), File(query_gallery), File(output)); | ||
| 60 | +} | ||
| 61 | + | ||
| 56 | void br_pairwise_compare(const char *target_gallery, const char *query_gallery, const char *output) | 62 | void br_pairwise_compare(const char *target_gallery, const char *query_gallery, const char *output) |
| 57 | { | 63 | { |
| 58 | PairwiseCompare(File(target_gallery), File(query_gallery), File(output)); | 64 | PairwiseCompare(File(target_gallery), File(query_gallery), File(output)); |
| @@ -323,6 +329,14 @@ unsigned char *br_unload_img(br_template tmpl) | @@ -323,6 +329,14 @@ unsigned char *br_unload_img(br_template tmpl) | ||
| 323 | return t->m().data; | 329 | return t->m().data; |
| 324 | } | 330 | } |
| 325 | 331 | ||
| 332 | +br_template_list br_template_list_from_buffer(const char *buf, int len) | ||
| 333 | +{ | ||
| 334 | + QByteArray arr(buf, len); | ||
| 335 | + TemplateList *tl = new TemplateList(); | ||
| 336 | + *tl = TemplateList::fromBuffer(arr); | ||
| 337 | + return (br_template_list)tl; | ||
| 338 | +} | ||
| 339 | + | ||
| 326 | void br_free_template(br_template tmpl) | 340 | void br_free_template(br_template tmpl) |
| 327 | { | 341 | { |
| 328 | Template *t = reinterpret_cast<Template*>(tmpl); | 342 | Template *t = reinterpret_cast<Template*>(tmpl); |
| @@ -335,6 +349,12 @@ void br_free_template_list(br_template_list tl) | @@ -335,6 +349,12 @@ void br_free_template_list(br_template_list tl) | ||
| 335 | delete realTL; | 349 | delete realTL; |
| 336 | } | 350 | } |
| 337 | 351 | ||
| 352 | +void br_free_output(br_matrix_output output) | ||
| 353 | +{ | ||
| 354 | + MatrixOutput *matOut = reinterpret_cast<MatrixOutput*>(output); | ||
| 355 | + delete matOut; | ||
| 356 | +} | ||
| 357 | + | ||
| 338 | int br_img_rows(br_template tmpl) | 358 | int br_img_rows(br_template tmpl) |
| 339 | { | 359 | { |
| 340 | Template *t = reinterpret_cast<Template*>(tmpl); | 360 | Template *t = reinterpret_cast<Template*>(tmpl); |
| @@ -359,6 +379,12 @@ bool br_img_is_empty(br_template tmpl) | @@ -359,6 +379,12 @@ bool br_img_is_empty(br_template tmpl) | ||
| 359 | return t->m().empty(); | 379 | return t->m().empty(); |
| 360 | } | 380 | } |
| 361 | 381 | ||
| 382 | +const char* br_get_filename(br_template tmpl) | ||
| 383 | +{ | ||
| 384 | + Template *t = reinterpret_cast<Template*>(tmpl); | ||
| 385 | + return t->file.name.toStdString().c_str(); | ||
| 386 | +} | ||
| 387 | + | ||
| 362 | void br_set_filename(br_template tmpl, const char *filename) | 388 | void br_set_filename(br_template tmpl, const char *filename) |
| 363 | { | 389 | { |
| 364 | Template *t = reinterpret_cast<Template*>(tmpl); | 390 | Template *t = reinterpret_cast<Template*>(tmpl); |
| @@ -391,6 +417,21 @@ void br_enroll_template_list(br_template_list tl) | @@ -391,6 +417,21 @@ void br_enroll_template_list(br_template_list tl) | ||
| 391 | Enroll(*realTL); | 417 | Enroll(*realTL); |
| 392 | } | 418 | } |
| 393 | 419 | ||
| 420 | +br_matrix_output br_compare_template_lists(br_template_list target, br_template_list query) | ||
| 421 | +{ | ||
| 422 | + TemplateList *targetTL = reinterpret_cast<TemplateList*>(target); | ||
| 423 | + TemplateList *queryTL = reinterpret_cast<TemplateList*>(query); | ||
| 424 | + MatrixOutput *output = MatrixOutput::make(targetTL->files(), queryTL->files()); | ||
| 425 | + CompareTemplateLists(*targetTL, *queryTL, output); | ||
| 426 | + return (br_matrix_output)output; | ||
| 427 | +} | ||
| 428 | + | ||
| 429 | +float br_get_matrix_output_at(br_matrix_output output, int row, int col) | ||
| 430 | +{ | ||
| 431 | + MatrixOutput *matOut = reinterpret_cast<MatrixOutput*>(output); | ||
| 432 | + return matOut->data.at<float>(row, col); | ||
| 433 | +} | ||
| 434 | + | ||
| 394 | br_template br_get_template(br_template_list tl, int index) | 435 | br_template br_get_template(br_template_list tl, int index) |
| 395 | { | 436 | { |
| 396 | TemplateList *realTL = reinterpret_cast<TemplateList*>(tl); | 437 | TemplateList *realTL = reinterpret_cast<TemplateList*>(tl); |
| @@ -412,7 +453,7 @@ br_gallery br_make_gallery(const char *gallery) | @@ -412,7 +453,7 @@ br_gallery br_make_gallery(const char *gallery) | ||
| 412 | br_template_list br_load_from_gallery(br_gallery gallery) | 453 | br_template_list br_load_from_gallery(br_gallery gallery) |
| 413 | { | 454 | { |
| 414 | Gallery *gal = reinterpret_cast<Gallery*>(gallery); | 455 | Gallery *gal = reinterpret_cast<Gallery*>(gallery); |
| 415 | - TemplateList *tl = static_cast<TemplateList*>(malloc(sizeof(TemplateList))); | 456 | + TemplateList *tl = new TemplateList(); |
| 416 | *tl = gal->read(); | 457 | *tl = gal->read(); |
| 417 | return (br_template_list)tl; | 458 | return (br_template_list)tl; |
| 418 | } | 459 | } |
openbr/openbr.h
| @@ -102,6 +102,12 @@ BR_EXPORT void br_combine_masks(int num_input_masks, const char *input_masks[], | @@ -102,6 +102,12 @@ BR_EXPORT void br_combine_masks(int num_input_masks, const char *input_masks[], | ||
| 102 | */ | 102 | */ |
| 103 | BR_EXPORT void br_compare(const char *target_gallery, const char *query_gallery, const char *output = ""); | 103 | BR_EXPORT void br_compare(const char *target_gallery, const char *query_gallery, const char *output = ""); |
| 104 | 104 | ||
| 105 | +/*! | ||
| 106 | + * \brief Convenience function for comparing to multiple targets. | ||
| 107 | + * \see br_compare | ||
| 108 | + */ | ||
| 109 | +BR_EXPORT void br_compare_n(int num_targets, const char *target_galleries[], const char *query_gallery, const char *output); | ||
| 110 | + | ||
| 105 | BR_EXPORT void br_pairwise_compare(const char *target_gallery, const char *query_gallery, const char *output = ""); | 111 | BR_EXPORT void br_pairwise_compare(const char *target_gallery, const char *query_gallery, const char *output = ""); |
| 106 | 112 | ||
| 107 | /*! | 113 | /*! |
| @@ -437,6 +443,7 @@ BR_EXPORT void br_slave_process(const char * baseKey); | @@ -437,6 +443,7 @@ BR_EXPORT void br_slave_process(const char * baseKey); | ||
| 437 | typedef void* br_template; | 443 | typedef void* br_template; |
| 438 | typedef void* br_template_list; | 444 | typedef void* br_template_list; |
| 439 | typedef void* br_gallery; | 445 | typedef void* br_gallery; |
| 446 | +typedef void* br_matrix_output; | ||
| 440 | /*! | 447 | /*! |
| 441 | * \brief Load an image from a string buffer. | 448 | * \brief Load an image from a string buffer. |
| 442 | * Easy way to pass an image in memory from another programming language to openbr. | 449 | * Easy way to pass an image in memory from another programming language to openbr. |
| @@ -452,6 +459,12 @@ BR_EXPORT br_template br_load_img(const char *data, int len); | @@ -452,6 +459,12 @@ BR_EXPORT br_template br_load_img(const char *data, int len); | ||
| 452 | */ | 459 | */ |
| 453 | BR_EXPORT unsigned char* br_unload_img(br_template tmpl); | 460 | BR_EXPORT unsigned char* br_unload_img(br_template tmpl); |
| 454 | /*! | 461 | /*! |
| 462 | + * \brief Deserialize a br::TemplateList from a buffer. | ||
| 463 | + * Can be the buffer for a .gal file, | ||
| 464 | + * since they are just a TemplateList serialized to disk. | ||
| 465 | + */ | ||
| 466 | +BR_EXPORT br_template_list br_template_list_from_buffer(const char *buf, int len); | ||
| 467 | +/*! | ||
| 455 | * \brief Free a br::Template's memory. | 468 | * \brief Free a br::Template's memory. |
| 456 | */ | 469 | */ |
| 457 | BR_EXPORT void br_free_template(br_template tmpl); | 470 | BR_EXPORT void br_free_template(br_template tmpl); |
| @@ -460,6 +473,10 @@ BR_EXPORT void br_free_template(br_template tmpl); | @@ -460,6 +473,10 @@ BR_EXPORT void br_free_template(br_template tmpl); | ||
| 460 | */ | 473 | */ |
| 461 | BR_EXPORT void br_free_template_list(br_template_list tl); | 474 | BR_EXPORT void br_free_template_list(br_template_list tl); |
| 462 | /*! | 475 | /*! |
| 476 | + * \brief Free a br::Output's memory. | ||
| 477 | + */ | ||
| 478 | +BR_EXPORT void br_free_output(br_matrix_output output); | ||
| 479 | +/*! | ||
| 463 | * \brief Get the number of rows in an image. | 480 | * \brief Get the number of rows in an image. |
| 464 | * \param tmpl Pointer to a br::Template. | 481 | * \param tmpl Pointer to a br::Template. |
| 465 | */ | 482 | */ |
| @@ -479,7 +496,11 @@ BR_EXPORT int br_img_channels(br_template tmpl); | @@ -479,7 +496,11 @@ BR_EXPORT int br_img_channels(br_template tmpl); | ||
| 479 | */ | 496 | */ |
| 480 | BR_EXPORT bool br_img_is_empty(br_template tmpl); | 497 | BR_EXPORT bool br_img_is_empty(br_template tmpl); |
| 481 | /*! | 498 | /*! |
| 482 | - * \brief Set the filename for a template. | 499 | + * \brief Get the filename for a br::Template |
| 500 | + */ | ||
| 501 | +BR_EXPORT const char* br_get_filename(br_template tmpl); | ||
| 502 | +/*! | ||
| 503 | + * \brief Set the filename for a br::Template. | ||
| 483 | */ | 504 | */ |
| 484 | BR_EXPORT void br_set_filename(br_template tmpl, const char *filename); | 505 | BR_EXPORT void br_set_filename(br_template tmpl, const char *filename); |
| 485 | /*! | 506 | /*! |
| @@ -493,10 +514,19 @@ BR_EXPORT const char* br_get_metadata_string(br_template, const char *key); | @@ -493,10 +514,19 @@ BR_EXPORT const char* br_get_metadata_string(br_template, const char *key); | ||
| 493 | BR_EXPORT br_template_list br_enroll_template(br_template tmpl); | 514 | BR_EXPORT br_template_list br_enroll_template(br_template tmpl); |
| 494 | /*! | 515 | /*! |
| 495 | * \brief Enroll a br::TemplateList from the C API! | 516 | * \brief Enroll a br::TemplateList from the C API! |
| 496 | - * \param tmpl Pointer to a br::TemplateList. | 517 | + * \param tl Pointer to a br::TemplateList. |
| 497 | */ | 518 | */ |
| 498 | BR_EXPORT void br_enroll_template_list(br_template_list tl); | 519 | BR_EXPORT void br_enroll_template_list(br_template_list tl); |
| 499 | /*! | 520 | /*! |
| 521 | + * \brief Compare br::TemplateLists from the C API! | ||
| 522 | + * \return Pointer to a br::MatrixOutput. | ||
| 523 | + */ | ||
| 524 | +BR_EXPORT br_matrix_output br_compare_template_lists(br_template_list target, br_template_list query); | ||
| 525 | +/*! | ||
| 526 | + * \brief Get a value in the br::MatrixOutput. | ||
| 527 | + */ | ||
| 528 | +BR_EXPORT float br_get_matrix_output_at(br_matrix_output output, int row, int col); | ||
| 529 | +/*! | ||
| 500 | * \brief Get a pointer to a br::Template at a specified index. | 530 | * \brief Get a pointer to a br::Template at a specified index. |
| 501 | * \param tl Pointer to a br::TemplateList. | 531 | * \param tl Pointer to a br::TemplateList. |
| 502 | * \param index The index of the br::Template. | 532 | * \param index The index of the br::Template. |
openbr/openbr_plugin.cpp
| @@ -863,7 +863,7 @@ void br::Context::printStatus() | @@ -863,7 +863,7 @@ void br::Context::printStatus() | ||
| 863 | const float p = progress(); | 863 | const float p = progress(); |
| 864 | if (p < 1) { | 864 | if (p < 1) { |
| 865 | int s = timeRemaining(); | 865 | int s = timeRemaining(); |
| 866 | - fprintf(stderr, "%05.2f%% REMAINING=%s COUNT=%g \r", 100 * p, QtUtils::toTime(s/1000.0f).toStdString().c_str(), totalSteps); | 866 | + fprintf(stderr, "%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(s).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); |
| 867 | } | 867 | } |
| 868 | } | 868 | } |
| 869 | 869 |
openbr/openbr_plugin.h
| @@ -332,6 +332,20 @@ private: | @@ -332,6 +332,20 @@ private: | ||
| 332 | void init(const QString &file); | 332 | void init(const QString &file); |
| 333 | }; | 333 | }; |
| 334 | 334 | ||
| 335 | +/*!< \brief Specialization for boolean type. */ | ||
| 336 | +template <> | ||
| 337 | +inline bool File::get<bool>(const QString &key, const bool &defaultValue) const | ||
| 338 | +{ | ||
| 339 | + return getBool(key, defaultValue); | ||
| 340 | +} | ||
| 341 | + | ||
| 342 | +/*!< \brief Specialization for boolean type. */ | ||
| 343 | +template <> | ||
| 344 | +inline bool File::get<bool>(const QString &key) const | ||
| 345 | +{ | ||
| 346 | + return getBool(key); | ||
| 347 | +} | ||
| 348 | + | ||
| 335 | BR_EXPORT QDebug operator<<(QDebug dbg, const File &file); /*!< \brief Prints br::File::flat() to \c stderr. */ | 349 | BR_EXPORT QDebug operator<<(QDebug dbg, const File &file); /*!< \brief Prints br::File::flat() to \c stderr. */ |
| 336 | BR_EXPORT QDataStream &operator<<(QDataStream &stream, const File &file); /*!< \brief Serializes the file to a stream. */ | 350 | BR_EXPORT QDataStream &operator<<(QDataStream &stream, const File &file); /*!< \brief Serializes the file to a stream. */ |
| 337 | BR_EXPORT QDataStream &operator>>(QDataStream &stream, File &file); /*!< \brief Deserializes the file from a stream. */ | 351 | BR_EXPORT QDataStream &operator>>(QDataStream &stream, File &file); /*!< \brief Deserializes the file from a stream. */ |
| @@ -469,7 +483,7 @@ struct TemplateList : public QList<Template> | @@ -469,7 +483,7 @@ struct TemplateList : public QList<Template> | ||
| 469 | } | 483 | } |
| 470 | 484 | ||
| 471 | /*! | 485 | /*! |
| 472 | - * \brief Returns a #br::TemplateList containing templates with one matrix at the specified index \em index. | 486 | + * \brief Returns a list of #br::TemplateList with each #br::Template in a given #br::TemplateList containing the number of matrices specified by \em partitionSizes. |
| 473 | */ | 487 | */ |
| 474 | QList<TemplateList> partition(const QList<int> &partitionSizes) const | 488 | QList<TemplateList> partition(const QList<int> &partitionSizes) const |
| 475 | { | 489 | { |
| @@ -1329,6 +1343,11 @@ BR_EXPORT void Enroll(TemplateList &tmpl); | @@ -1329,6 +1343,11 @@ BR_EXPORT void Enroll(TemplateList &tmpl); | ||
| 1329 | * \see br_compare | 1343 | * \see br_compare |
| 1330 | */ | 1344 | */ |
| 1331 | BR_EXPORT void Compare(const File &targetGallery, const File &queryGallery, const File &output); | 1345 | BR_EXPORT void Compare(const File &targetGallery, const File &queryGallery, const File &output); |
| 1346 | +/*! | ||
| 1347 | + * \brief High-level function for comparing templates. | ||
| 1348 | + */ | ||
| 1349 | +BR_EXPORT void CompareTemplateLists(const TemplateList &target, const TemplateList &query, Output *output); | ||
| 1350 | + | ||
| 1332 | 1351 | ||
| 1333 | /*! | 1352 | /*! |
| 1334 | * \brief High-level function for doing a series of pairwise comparisons. | 1353 | * \brief High-level function for doing a series of pairwise comparisons. |
openbr/plugins/distance.cpp
| @@ -179,58 +179,93 @@ BR_REGISTER(Distance, PipeDistance) | @@ -179,58 +179,93 @@ BR_REGISTER(Distance, PipeDistance) | ||
| 179 | 179 | ||
| 180 | /*! | 180 | /*! |
| 181 | * \ingroup distances | 181 | * \ingroup distances |
| 182 | - * \brief Computes an operation on distances across multiple matrices of compared templates | 182 | + * \brief Fuses similarity scores across multiple matrices of compared templates |
| 183 | * \author Scott Klum \cite sklum | 183 | * \author Scott Klum \cite sklum |
| 184 | * \note Operation: Mean, sum, min, max are supported. | 184 | * \note Operation: Mean, sum, min, max are supported. |
| 185 | */ | 185 | */ |
| 186 | -class OperationDistance : public Distance | 186 | +class FuseDistance : public Distance |
| 187 | { | 187 | { |
| 188 | Q_OBJECT | 188 | Q_OBJECT |
| 189 | Q_ENUMS(Operation) | 189 | Q_ENUMS(Operation) |
| 190 | - Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | 190 | + Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) |
| 191 | Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false) | 191 | Q_PROPERTY(Operation operation READ get_operation WRITE set_operation RESET reset_operation STORED false) |
| 192 | + Q_PROPERTY(QList<float> weights READ get_weights WRITE set_weights RESET reset_weights STORED false) | ||
| 193 | + | ||
| 194 | + QList<br::Distance*> distances; | ||
| 192 | 195 | ||
| 193 | public: | 196 | public: |
| 194 | /*!< */ | 197 | /*!< */ |
| 195 | enum Operation {Mean, Sum, Max, Min}; | 198 | enum Operation {Mean, Sum, Max, Min}; |
| 196 | 199 | ||
| 197 | private: | 200 | private: |
| 198 | - BR_PROPERTY(br::Distance*, distance, make("Dist(L2)")) | 201 | + BR_PROPERTY(QString, description, "IdenticalDistance") |
| 199 | BR_PROPERTY(Operation, operation, Mean) | 202 | BR_PROPERTY(Operation, operation, Mean) |
| 203 | + BR_PROPERTY(QList<float>, weights, QList<float>()) | ||
| 200 | 204 | ||
| 201 | void train(const TemplateList &src) | 205 | void train(const TemplateList &src) |
| 202 | { | 206 | { |
| 203 | - distance->train(src); | 207 | + // Partition the templates by matrix |
| 208 | + QList<int> split; | ||
| 209 | + for (int i=0; i<src.at(0).size(); i++) split.append(1); | ||
| 210 | + | ||
| 211 | + QList<TemplateList> partitionedSrc = src.partition(split); | ||
| 212 | + | ||
| 213 | + while (distances.size() < partitionedSrc.size()) | ||
| 214 | + distances.append(make(description)); | ||
| 215 | + | ||
| 216 | + // Train on each of the partitions | ||
| 217 | + for (int i=0; i<distances.size(); i++) | ||
| 218 | + distances[i]->train(partitionedSrc[i]); | ||
| 204 | } | 219 | } |
| 205 | 220 | ||
| 206 | float compare(const Template &a, const Template &b) const | 221 | float compare(const Template &a, const Template &b) const |
| 207 | { | 222 | { |
| 208 | if (a.size() != b.size()) qFatal("Comparison size mismatch"); | 223 | if (a.size() != b.size()) qFatal("Comparison size mismatch"); |
| 209 | 224 | ||
| 210 | - QList<float> distances; | ||
| 211 | - for (int i = 0; i < a.size(); i++) | ||
| 212 | - distances.append(distance->compare(a[i],b[i])); | 225 | + QList<float> scores; |
| 226 | + for (int i=0; i<distances.size(); i++) { | ||
| 227 | + float weight; | ||
| 228 | + weights.isEmpty() ? weight = 1. : weight = weights[i]; | ||
| 229 | + scores.append(weight*distances[i]->compare(Template(a.file, a[i]),Template(b.file, b[i]))); | ||
| 230 | + } | ||
| 213 | 231 | ||
| 214 | switch (operation) { | 232 | switch (operation) { |
| 215 | case Mean: | 233 | case Mean: |
| 216 | - return std::accumulate(distances.begin(),distances.end(),0.0)/(float)distances.size(); | 234 | + return std::accumulate(scores.begin(),scores.end(),0.0)/(float)scores.size(); |
| 217 | break; | 235 | break; |
| 218 | case Sum: | 236 | case Sum: |
| 219 | - return std::accumulate(distances.begin(),distances.end(),0.0); | 237 | + return std::accumulate(scores.begin(),scores.end(),0.0); |
| 220 | break; | 238 | break; |
| 221 | case Min: | 239 | case Min: |
| 222 | - return *std::min_element(distances.begin(),distances.end()); | 240 | + return *std::min_element(scores.begin(),scores.end()); |
| 223 | break; | 241 | break; |
| 224 | case Max: | 242 | case Max: |
| 225 | - return *std::max_element(distances.begin(),distances.end()); | 243 | + return *std::max_element(scores.begin(),scores.end()); |
| 226 | break; | 244 | break; |
| 227 | default: | 245 | default: |
| 228 | qFatal("Invalid operation."); | 246 | qFatal("Invalid operation."); |
| 229 | } | 247 | } |
| 230 | } | 248 | } |
| 249 | + | ||
| 250 | + void store(QDataStream &stream) const | ||
| 251 | + { | ||
| 252 | + stream << distances.size(); | ||
| 253 | + foreach (Distance *distance, distances) | ||
| 254 | + distance->store(stream); | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + void load(QDataStream &stream) | ||
| 258 | + { | ||
| 259 | + int numDistances; | ||
| 260 | + stream >> numDistances; | ||
| 261 | + while (distances.size() < numDistances) | ||
| 262 | + distances.append(make(description)); | ||
| 263 | + foreach (Distance *distance, distances) | ||
| 264 | + distance->load(stream); | ||
| 265 | + } | ||
| 231 | }; | 266 | }; |
| 232 | 267 | ||
| 233 | -BR_REGISTER(Distance, OperationDistance) | 268 | +BR_REGISTER(Distance, FuseDistance) |
| 234 | 269 | ||
| 235 | /*! | 270 | /*! |
| 236 | * \ingroup distances | 271 | * \ingroup distances |
openbr/plugins/gallery.cpp
| @@ -99,12 +99,12 @@ class galGallery : public Gallery | @@ -99,12 +99,12 @@ class galGallery : public Gallery | ||
| 99 | void init() | 99 | void init() |
| 100 | { | 100 | { |
| 101 | gallery.setFileName(file); | 101 | gallery.setFileName(file); |
| 102 | - if (file.get<bool>("remove", false)) | 102 | + if (file.get<bool>("remove")) |
| 103 | gallery.remove(); | 103 | gallery.remove(); |
| 104 | QtUtils::touchDir(gallery); | 104 | QtUtils::touchDir(gallery); |
| 105 | QFile::OpenMode mode = QFile::ReadWrite; | 105 | QFile::OpenMode mode = QFile::ReadWrite; |
| 106 | 106 | ||
| 107 | - if (file.contains("append")) | 107 | + if (file.get<bool>("append")) |
| 108 | mode |= QFile::Append; | 108 | mode |= QFile::Append; |
| 109 | 109 | ||
| 110 | if (!gallery.open(mode)) | 110 | if (!gallery.open(mode)) |
openbr/plugins/gui.cpp
| @@ -13,6 +13,7 @@ | @@ -13,6 +13,7 @@ | ||
| 13 | 13 | ||
| 14 | #include <opencv2/imgproc/imgproc.hpp> | 14 | #include <opencv2/imgproc/imgproc.hpp> |
| 15 | #include "openbr_internal.h" | 15 | #include "openbr_internal.h" |
| 16 | +#include "openbr/gui/utility.h" | ||
| 16 | 17 | ||
| 17 | using namespace cv; | 18 | using namespace cv; |
| 18 | 19 | ||
| @@ -121,45 +122,6 @@ public slots: | @@ -121,45 +122,6 @@ public slots: | ||
| 121 | } | 122 | } |
| 122 | }; | 123 | }; |
| 123 | 124 | ||
| 124 | -QImage toQImage(const Mat &mat) | ||
| 125 | -{ | ||
| 126 | - // Convert to 8U depth | ||
| 127 | - Mat mat8u; | ||
| 128 | - if (mat.depth() != CV_8U) { | ||
| 129 | - double globalMin = std::numeric_limits<double>::max(); | ||
| 130 | - double globalMax = -std::numeric_limits<double>::max(); | ||
| 131 | - | ||
| 132 | - std::vector<Mat> mv; | ||
| 133 | - split(mat, mv); | ||
| 134 | - for (size_t i=0; i<mv.size(); i++) { | ||
| 135 | - double min, max; | ||
| 136 | - minMaxLoc(mv[i], &min, &max); | ||
| 137 | - globalMin = std::min(globalMin, min); | ||
| 138 | - globalMax = std::max(globalMax, max); | ||
| 139 | - } | ||
| 140 | - assert(globalMax >= globalMin); | ||
| 141 | - | ||
| 142 | - double range = globalMax - globalMin; | ||
| 143 | - if (range != 0) { | ||
| 144 | - double scale = 255 / range; | ||
| 145 | - convertScaleAbs(mat, mat8u, scale, -(globalMin * scale)); | ||
| 146 | - } else { | ||
| 147 | - // Monochromatic | ||
| 148 | - mat8u = Mat(mat.size(), CV_8UC1, Scalar((globalMin+globalMax)/2)); | ||
| 149 | - } | ||
| 150 | - } else { | ||
| 151 | - mat8u = mat; | ||
| 152 | - } | ||
| 153 | - | ||
| 154 | - // Convert to 3 channels | ||
| 155 | - Mat mat8uc3; | ||
| 156 | - if (mat8u.channels() == 4) cvtColor(mat8u, mat8uc3, CV_BGRA2RGB); | ||
| 157 | - else if (mat8u.channels() == 3) cvtColor(mat8u, mat8uc3, CV_BGR2RGB); | ||
| 158 | - else if (mat8u.channels() == 1) cvtColor(mat8u, mat8uc3, CV_GRAY2RGB); | ||
| 159 | - | ||
| 160 | - return QImage(mat8uc3.data, mat8uc3.cols, mat8uc3.rows, 3*mat8uc3.cols, QImage::Format_RGB888).copy(); | ||
| 161 | -} | ||
| 162 | - | ||
| 163 | class DisplayWindow : public QLabel | 125 | class DisplayWindow : public QLabel |
| 164 | { | 126 | { |
| 165 | Q_OBJECT | 127 | Q_OBJECT |
openbr/plugins/independent.cpp
| @@ -156,8 +156,8 @@ class IndependentTransform : public MetaTransform | @@ -156,8 +156,8 @@ class IndependentTransform : public MetaTransform | ||
| 156 | 156 | ||
| 157 | QFutureSynchronizer<void> futures; | 157 | QFutureSynchronizer<void> futures; |
| 158 | for (int i=0; i<templatesList.size(); i++) | 158 | for (int i=0; i<templatesList.size(); i++) |
| 159 | - futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); | ||
| 160 | - futures.waitForFinished(); | 159 | + futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i])); |
| 160 | + futures.waitForFinished(); | ||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | void project(const Template &src, Template &dst) const | 163 | void project(const Template &src, Template &dst) const |
openbr/plugins/misc.cpp
| @@ -514,28 +514,16 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -514,28 +514,16 @@ class ProgressCounterTransform : public TimeVaryingTransform | ||
| 514 | void projectUpdate(const TemplateList &src, TemplateList &dst) | 514 | void projectUpdate(const TemplateList &src, TemplateList &dst) |
| 515 | { | 515 | { |
| 516 | dst = src; | 516 | dst = src; |
| 517 | - qint64 elapsed = timer.elapsed(); | ||
| 518 | - calls++; | ||
| 519 | - set_calls++; | ||
| 520 | - // updated every 10 seconds | ||
| 521 | - if (elapsed > 5 * 1000) { | ||
| 522 | - float f_elapsed = elapsed / 1000.0f; | ||
| 523 | - // remaining calls (according to our input variable) | ||
| 524 | - int remaining = totalTemplates - calls; | ||
| 525 | - // calls / second | ||
| 526 | - float speed = set_calls / f_elapsed; | ||
| 527 | - | ||
| 528 | - float p = 100 * float(calls) / totalTemplates; | ||
| 529 | - | ||
| 530 | - // seconds remaining | ||
| 531 | - int s = float(remaining) / speed; | ||
| 532 | 517 | ||
| 533 | - fprintf(stderr, "%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g \r", p, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(s).toStdString().c_str(), float(calls)); | 518 | + qint64 elapsed = timer.elapsed(); |
| 534 | 519 | ||
| 520 | + // updated every second | ||
| 521 | + if (elapsed > 1000) { | ||
| 522 | + Globals->printStatus(); | ||
| 535 | timer.start(); | 523 | timer.start(); |
| 536 | - set_calls = 0; | ||
| 537 | } | 524 | } |
| 538 | 525 | ||
| 526 | + Globals->currentStep++; | ||
| 539 | 527 | ||
| 540 | return; | 528 | return; |
| 541 | } | 529 | } |
| @@ -548,24 +536,18 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -548,24 +536,18 @@ class ProgressCounterTransform : public TimeVaryingTransform | ||
| 548 | void finalize(TemplateList & data) | 536 | void finalize(TemplateList & data) |
| 549 | { | 537 | { |
| 550 | (void) data; | 538 | (void) data; |
| 551 | - float p = 100 * float(calls) / totalTemplates; | ||
| 552 | - qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g \r", p, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), float(calls)); | 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); | ||
| 553 | } | 541 | } |
| 554 | 542 | ||
| 555 | void init() | 543 | void init() |
| 556 | { | 544 | { |
| 557 | - calls = 0; | ||
| 558 | - set_calls = 0; | ||
| 559 | timer.start(); | 545 | timer.start(); |
| 560 | } | 546 | } |
| 561 | 547 | ||
| 562 | public: | 548 | public: |
| 563 | ProgressCounterTransform() : TimeVaryingTransform(false,false) {} | 549 | ProgressCounterTransform() : TimeVaryingTransform(false,false) {} |
| 564 | - bool initialized; | ||
| 565 | QElapsedTimer timer; | 550 | QElapsedTimer timer; |
| 566 | - qint64 calls; | ||
| 567 | - qint64 set_calls; | ||
| 568 | - | ||
| 569 | }; | 551 | }; |
| 570 | 552 | ||
| 571 | BR_REGISTER(Transform, ProgressCounterTransform) | 553 | BR_REGISTER(Transform, ProgressCounterTransform) |
openbr/plugins/quality.cpp
| @@ -173,7 +173,7 @@ class MatchProbabilityDistance : public Distance | @@ -173,7 +173,7 @@ class MatchProbabilityDistance : public Distance | ||
| 173 | for (int j=0; j<i; j++) { | 173 | for (int j=0; j<i; j++) { |
| 174 | const float score = matrixOutput.data()->data.at<float>(i, j); | 174 | const float score = matrixOutput.data()->data.at<float>(i, j); |
| 175 | if (score == -std::numeric_limits<float>::max()) continue; | 175 | if (score == -std::numeric_limits<float>::max()) continue; |
| 176 | - if (crossModality) if(src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue; | 176 | + if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue; |
| 177 | if (labels[i] == labels[j]) genuineScores.append(score); | 177 | if (labels[i] == labels[j]) genuineScores.append(score); |
| 178 | else impostorScores.append(score); | 178 | else impostorScores.append(score); |
| 179 | } | 179 | } |
| @@ -211,6 +211,65 @@ protected: | @@ -211,6 +211,65 @@ protected: | ||
| 211 | 211 | ||
| 212 | BR_REGISTER(Distance, MatchProbabilityDistance) | 212 | BR_REGISTER(Distance, MatchProbabilityDistance) |
| 213 | 213 | ||
| 214 | +class ZScoreDistance : public Distance | ||
| 215 | +{ | ||
| 216 | + Q_OBJECT | ||
| 217 | + Q_PROPERTY(br::Distance* distance READ get_distance WRITE set_distance RESET reset_distance STORED false) | ||
| 218 | + Q_PROPERTY(bool crossModality READ get_crossModality WRITE set_crossModality RESET reset_crossModality STORED false) | ||
| 219 | + BR_PROPERTY(br::Distance*, distance, make("Dist(L2)")) | ||
| 220 | + BR_PROPERTY(bool, crossModality, false) | ||
| 221 | + | ||
| 222 | + float min, max; | ||
| 223 | + double mean, stddev; | ||
| 224 | + | ||
| 225 | + void train(const TemplateList &src) | ||
| 226 | + { | ||
| 227 | + distance->train(src); | ||
| 228 | + | ||
| 229 | + QScopedPointer<MatrixOutput> matrixOutput(MatrixOutput::make(FileList(src.size()), FileList(src.size()))); | ||
| 230 | + distance->compare(src, src, matrixOutput.data()); | ||
| 231 | + | ||
| 232 | + QList<float> scores; | ||
| 233 | + scores.reserve(src.size()*src.size()); | ||
| 234 | + for (int i=0; i<src.size(); i++) { | ||
| 235 | + for (int j=0; j<i; j++) { | ||
| 236 | + const float score = matrixOutput.data()->data.at<float>(i, j); | ||
| 237 | + if (score == -std::numeric_limits<float>::max()) continue; | ||
| 238 | + if (crossModality && src[i].file.get<QString>("MODALITY") == src[j].file.get<QString>("MODALITY")) continue; | ||
| 239 | + scores.append(score); | ||
| 240 | + } | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + Common::MinMax(scores, &min, &max); | ||
| 244 | + Common::MeanStdDev(scores, &mean, &stddev); | ||
| 245 | + | ||
| 246 | + if (stddev == 0) qFatal("Stddev is 0."); | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + float compare(const Template &target, const Template &query) const | ||
| 250 | + { | ||
| 251 | + float score = distance->compare(target,query); | ||
| 252 | + if (score == -std::numeric_limits<float>::max()) score = (min - mean) / stddev; | ||
| 253 | + else if (score == std::numeric_limits<float>::max()) score = (max - mean) / stddev; | ||
| 254 | + else score = (score - mean) / stddev; | ||
| 255 | + return score; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + void store(QDataStream &stream) const | ||
| 259 | + { | ||
| 260 | + distance->store(stream); | ||
| 261 | + stream << min << max << mean << stddev; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + void load(QDataStream &stream) | ||
| 265 | + { | ||
| 266 | + distance->load(stream); | ||
| 267 | + stream >> min >> max >> mean >> stddev; | ||
| 268 | + } | ||
| 269 | +}; | ||
| 270 | + | ||
| 271 | +BR_REGISTER(Distance, ZScoreDistance) | ||
| 272 | + | ||
| 214 | /*! | 273 | /*! |
| 215 | * \ingroup distances | 274 | * \ingroup distances |
| 216 | * \brief Match Probability modification for heat maps \cite klare12 | 275 | * \brief Match Probability modification for heat maps \cite klare12 |
openbr/plugins/slidingwindow.cpp
| @@ -216,7 +216,7 @@ static TemplateList cropTrainingSamples(const TemplateList &data, const float as | @@ -216,7 +216,7 @@ static TemplateList cropTrainingSamples(const TemplateList &data, const float as | ||
| 216 | 216 | ||
| 217 | /*! | 217 | /*! |
| 218 | * \ingroup transforms | 218 | * \ingroup transforms |
| 219 | - * \brief . | 219 | + * \brief Document me |
| 220 | * \author Austin Blanton \cite imaus10 | 220 | * \author Austin Blanton \cite imaus10 |
| 221 | */ | 221 | */ |
| 222 | class BuildScalesTransform : public Transform | 222 | class BuildScalesTransform : public Transform |
openbr/plugins/validate.cpp
| @@ -104,15 +104,13 @@ class CrossValidateTransform : public MetaTransform | @@ -104,15 +104,13 @@ class CrossValidateTransform : public MetaTransform | ||
| 104 | // since it is assumed that the allPartitions | 104 | // since it is assumed that the allPartitions |
| 105 | // flag is only used during comparison | 105 | // flag is only used during comparison |
| 106 | // (i.e. only used when making a mask) | 106 | // (i.e. only used when making a mask) |
| 107 | - if (src.file.getBool("Train", false)) dst = src; | ||
| 108 | - else { | ||
| 109 | - // If we want to duplicate templates but use the same training data | ||
| 110 | - // for all partitions (i.e. transforms.size() == 1), we need to | ||
| 111 | - // restrict the partition | ||
| 112 | - int partition = src.file.get<int>("Partition", 0); | ||
| 113 | - partition = (partition >= transforms.size()) ? 0 : partition; | ||
| 114 | - transforms[partition]->project(src, dst); | ||
| 115 | - } | 107 | + |
| 108 | + // If we want to duplicate templates but use the same training data | ||
| 109 | + // for all partitions (i.e. transforms.size() == 1), we need to | ||
| 110 | + // restrict the partition | ||
| 111 | + int partition = src.file.get<int>("Partition", 0); | ||
| 112 | + partition = (partition >= transforms.size()) ? 0 : partition; | ||
| 113 | + transforms[partition]->project(src, dst); | ||
| 116 | } | 114 | } |
| 117 | 115 | ||
| 118 | void store(QDataStream &stream) const | 116 | void store(QDataStream &stream) const |
scripts/brpy/__init__.py
0 โ 100644
| 1 | +from ctypes import * | ||
| 2 | +import os | ||
| 3 | + | ||
| 4 | +def _string_args(n): | ||
| 5 | + s = [] | ||
| 6 | + for i in range(n): | ||
| 7 | + s.append(c_char_p) | ||
| 8 | + return s | ||
| 9 | + | ||
| 10 | +def _var_string_args(n): | ||
| 11 | + s = [c_int, POINTER(c_char_p)] | ||
| 12 | + s.extend(_string_args(n)) | ||
| 13 | + return s | ||
| 14 | + | ||
| 15 | +def init_brpy(br_loc='/usr/local/lib'): | ||
| 16 | + """Takes the ctypes lib object for br and initializes all function inputs and outputs""" | ||
| 17 | + br_loc += '/libopenbr.%s' | ||
| 18 | + if os.path.exists(br_loc % 'dylib'): | ||
| 19 | + br = cdll.LoadLibrary(br_loc % 'dylib') | ||
| 20 | + elif os.path.exists(br_loc % 'so'): | ||
| 21 | + br = cdll.LoadLibrary(br_loc % 'so') | ||
| 22 | + else: | ||
| 23 | + raise ValueError('Neither .so nor .dylib libopenbr found in %s' % br_loc) | ||
| 24 | + | ||
| 25 | + plot_args = _var_string_args(1) + [c_bool] | ||
| 26 | + br.br_about.restype = c_char_p | ||
| 27 | + br.br_cat.argtypes = _var_string_args(1) | ||
| 28 | + br.br_cluster.argtypes = [c_int, POINTER(c_char_p), c_float, c_char_p] | ||
| 29 | + br.br_combine_masks.argtypes = _var_string_args(2) | ||
| 30 | + br.br_compare.argtypes = _string_args(3) | ||
| 31 | + br.br_compare_n.argtypes = [c_int, POINTER(c_char_p)] + _string_args(2) | ||
| 32 | + br.br_pairwise_compare.argtypes = _string_args(3) | ||
| 33 | + br.br_convert.argtypes = _string_args(3) | ||
| 34 | + br.br_enroll.argtypes = _string_args(2) | ||
| 35 | + br.br_enroll_n.argtypes = _var_string_args(1) | ||
| 36 | + br.br_eval.argtypes = _string_args(3) | ||
| 37 | + br.br_eval.restype = c_float | ||
| 38 | + br.br_eval_classification.argtypes = _string_args(4) | ||
| 39 | + br.br_eval_clustering.argtypes = _string_args(2) | ||
| 40 | + br.br_eval_detection.argtypes = _string_args(3) | ||
| 41 | + br.br_eval_detection.restype = c_float | ||
| 42 | + br.br_eval_landmarking.argtypes = _string_args(3) + [c_int, c_int] | ||
| 43 | + br.br_eval_landmarking.restype = c_float | ||
| 44 | + br.br_eval_regression.argtypes = _string_args(4) | ||
| 45 | + br.br_fuse.argtypes = _var_string_args(3) | ||
| 46 | + br.br_initialize.argtypes = _var_string_args(1) | ||
| 47 | + br.br_is_classifier.argtypes = [c_char_p] | ||
| 48 | + br.br_is_classifier.restype = c_bool | ||
| 49 | + br.br_make_mask.argtypes = _string_args(3) | ||
| 50 | + br.br_make_pairwise_mask.argtypes = _string_args(3) | ||
| 51 | + br.br_most_recent_message.restype = c_char_p | ||
| 52 | + br.br_objects.argtypes = _string_args(2) + [c_bool] | ||
| 53 | + br.br_objects.restype = c_char_p | ||
| 54 | + br.br_plot.argtypes = plot_args | ||
| 55 | + br.br_plot.restype = c_bool | ||
| 56 | + br.br_plot_detection.argtypes = plot_args | ||
| 57 | + br.br_plot_detection.restype = c_bool | ||
| 58 | + br.br_plot_landmarking.argtypes = plot_args | ||
| 59 | + br.br_plot_landmarking.restype = c_bool | ||
| 60 | + br.br_plot_metadata.argtypes = plot_args | ||
| 61 | + br.br_plot_metadata.restype = c_bool | ||
| 62 | + br.br_progress.restype = c_float | ||
| 63 | + br.br_read_pipe.argtypes = [c_char_p, POINTER(c_int), POINTER(POINTER(c_char_p))] | ||
| 64 | + br.br_scratch_path.restype = c_char_p | ||
| 65 | + br.br_sdk_path.restype = c_char_p | ||
| 66 | + br.br_get_header.argtypes = [c_char_p, POINTER(c_char_p), POINTER(c_char_p)] | ||
| 67 | + br.br_set_header.argtypes = _string_args(3) | ||
| 68 | + br.br_set_property.argtypes = _string_args(2) | ||
| 69 | + br.br_time_remaining.restype = c_int | ||
| 70 | + br.br_train.argtypes = _string_args(2) | ||
| 71 | + br.br_train_n.argtypes = _var_string_args(1) | ||
| 72 | + br.br_version.restype = c_char_p | ||
| 73 | + br.br_slave_process.argtypes = [c_char_p] | ||
| 74 | + br.br_load_img.argtypes = [c_char_p, c_int] | ||
| 75 | + br.br_load_img.restype = c_void_p | ||
| 76 | + br.br_unload_img.argtypes = [c_void_p] | ||
| 77 | + br.br_unload_img.restype = POINTER(c_ubyte) | ||
| 78 | + br.br_template_list_from_buffer.argtypes = [c_char_p, c_int] | ||
| 79 | + br.br_template_list_from_buffer.restype = c_void_p | ||
| 80 | + br.br_free_template.argtypes = [c_void_p] | ||
| 81 | + br.br_free_template_list.argtypes = [c_void_p] | ||
| 82 | + br.br_free_output.argtypes = [c_void_p] | ||
| 83 | + br.br_img_rows.argtypes = [c_void_p] | ||
| 84 | + br.br_img_rows.restype = c_int | ||
| 85 | + br.br_img_cols.argtypes = [c_void_p] | ||
| 86 | + br.br_img_cols.restype = c_int | ||
| 87 | + br.br_img_channels.argtypes = [c_void_p] | ||
| 88 | + br.br_img_channels.restype = c_int | ||
| 89 | + br.br_img_is_empty.argtypes = [c_void_p] | ||
| 90 | + br.br_img_is_empty.restype = c_bool | ||
| 91 | + br.br_get_filename.argtypes = [c_void_p] | ||
| 92 | + br.br_get_filename.restype = c_char_p | ||
| 93 | + br.br_set_filename.argtypes = [c_void_p, c_char_p] | ||
| 94 | + br.br_get_metadata_string.argtypes = [c_void_p, c_char_p] | ||
| 95 | + br.br_get_metadata_string.restype = c_char_p | ||
| 96 | + br.br_enroll_template.argtypes = [c_void_p] | ||
| 97 | + br.br_enroll_template.restype = c_void_p | ||
| 98 | + br.br_enroll_template_list.argtypes = [c_void_p] | ||
| 99 | + br.br_enroll_template_list.restype = c_void_p | ||
| 100 | + br.br_compare_template_lists.argtypes = [c_void_p, c_void_p] | ||
| 101 | + br.br_compare_template_lists.restype = c_void_p | ||
| 102 | + br.br_get_matrix_output_at.argtypes = [c_void_p, c_int, c_int] | ||
| 103 | + br.br_get_matrix_output_at.restype = c_float | ||
| 104 | + br.br_get_template.argtypes = [c_void_p, c_int] | ||
| 105 | + br.br_get_template.restype = c_void_p | ||
| 106 | + br.br_num_templates.argtypes = [c_void_p] | ||
| 107 | + br.br_num_templates.restype = c_int | ||
| 108 | + br.br_make_gallery.argtypes = [c_char_p] | ||
| 109 | + br.br_make_gallery.restype = c_void_p | ||
| 110 | + br.br_load_from_gallery.argtypes = [c_void_p] | ||
| 111 | + br.br_load_from_gallery.restype = c_void_p | ||
| 112 | + br.br_add_to_gallery.argtypes = [c_void_p, c_void_p] | ||
| 113 | + br.br_close_gallery.argtypes = [c_void_p] | ||
| 114 | + | ||
| 115 | + return br |