Commit be996aacdff87778e92e38f33ffe46357798c83f

Authored by Brendan Klare
2 parents f0af46eb e34a4ded

Merge branch 'master' of https://github.com/biometrics/openbr

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 &amp;targetGallery, const File &amp;queryGallery, const File @@ -430,6 +428,13 @@ void br::Compare(const File &amp;targetGallery, const File &amp;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 &amp;fileType, const File &amp;inputFile, const File &amp;output @@ -456,7 +461,7 @@ void br::Convert(const File &amp;fileType, const File &amp;inputFile, const File &amp;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
1 -Subproject commit b79bdf71d86b1d5967fa636c6727bebf898cf2ed 1 +Subproject commit 0eaa00f19256fee2f24033ff68b526ea6320624d
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&lt;Template&gt; @@ -469,7 +483,7 @@ struct TemplateList : public QList&lt;Template&gt;
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 &amp;tmpl); @@ -1329,6 +1343,11 @@ BR_EXPORT void Enroll(TemplateList &amp;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 &amp;data, const float as @@ -216,7 +216,7 @@ static TemplateList cropTrainingSamples(const TemplateList &amp;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