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 3  
4 4 # Global settings
5 5 set(BR_SHARE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/share/openbr")
  6 +set(BR_SCRIPTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts")
6 7 set(CMAKE_AUTOMOC ON)
7 8 set(CPACK_PACKAGE_NAME "OpenBR")
8 9 set(CPACK_PACKAGE_VENDOR "OpenBiometrics")
... ... @@ -117,7 +118,7 @@ if(BUILD_TESTING)
117 118 endif()
118 119  
119 120 # Build the SDK
120   -include_directories(.)
  121 +include_directories(BEFORE .) # Find the local headers first
121 122 add_subdirectory(openbr)
122 123  
123 124 # Build applications
... ... @@ -138,6 +139,14 @@ install(FILES CHANGELOG.md LICENSE.txt README.md DESTINATION .)
138 139 install(DIRECTORY share DESTINATION .)
139 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 150 # Package
142 151 set(CPACK_PACKAGE_EXECUTABLES "OpenBR" "OpenBR")
143 152 set(CPACK_CREATE_DESKTOP_LINKS "OpenBR")
... ...
openbr/core/core.cpp
... ... @@ -56,11 +56,6 @@ struct AlgorithmCore
56 56  
57 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 59 if (transform.isNull()) qFatal("Null transform.");
65 60 qDebug("%d Training Files", data.size());
66 61  
... ... @@ -153,9 +148,12 @@ struct AlgorithmCore
153 148 if (data.empty())
154 149 return files;
155 150  
  151 + // Store steps for ProgressCounter
  152 + Globals->currentStep = 0;
  153 + Globals->totalSteps = data.length();
  154 +
156 155 // Trust me, this makes complete sense.
157 156 // We're just going to make a pipe with a placeholder first transform
158   - Globals->totalSteps = data.length();
159 157 QString pipeDesc = "Identity+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard";
160 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 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 438 void br::PairwiseCompare(const File &targetGallery, const File &queryGallery, const File &output)
434 439 {
435 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 461  
457 462 if ((targetFiles.size() != m.cols || queryFiles.size() != m.rows)
458 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 466 QSharedPointer<Output> o(Factory<Output>::make(outputFile));
462 467 o->initialize(targetFiles, queryFiles);
... ...
openbr/core/fuse.cpp
... ... @@ -30,6 +30,9 @@ using namespace cv;
30 30  
31 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 36 if (method == "None") return;
34 37  
35 38 QList<float> vals; vals.reserve(matrix.rows*matrix.cols);
... ...
openbr/gui/progress.cpp
... ... @@ -26,7 +26,7 @@ br::Progress::Progress(QWidget *parent)
26 26 void br::Progress::checkProgress()
27 27 {
28 28 const int progress = 100 * br_progress();
29   - const bool visible = progress >= 0;
  29 + const bool visible = progress >= 0 && progress < 100;
30 30  
31 31 if (visible) {
32 32 showMessage(br_most_recent_message());
... ...
openbr/gui/utility.cpp
1   -#include <QImage>
2 1 #include <limits>
3 2 #include <vector>
4 3 #include <opencv2/imgproc/imgproc.hpp>
  4 +#include "utility.h"
5 5  
6 6 using namespace cv;
7 7  
8   -/**** STATIC ****/
9   -QImage toQImage(const Mat &mat)
  8 +QImage br::toQImage(const Mat &mat)
10 9 {
11 10 // Convert to 8U depth
12 11 Mat mat8u;
... ...
openbr/gui/utility.h
... ... @@ -3,7 +3,13 @@
3 3  
4 4 #include <QImage>
5 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 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 80 templateBytes = currentTemplateBytes;
81 81 if (templateBytes != currentTemplateBytes)
82 82 return JANUS_UNKNOWN_ERROR;
83   - if (*bytes + templateBytes > JANUS_MAX_TEMPLATE_SIZE)
  83 + if (*bytes + templateBytes > janus_max_template_size())
84 84 break;
85 85 memcpy(pos, m.data, templateBytes);
86 86 *bytes += templateBytes;
... ... @@ -94,21 +94,49 @@ janus_error janus_finalize_template(janus_incomplete_template incomplete_templat
94 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 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 106 b_templates = *(reinterpret_cast<size_t*>(b)+1);
104   - if (a_bytes != b_bytes)
  107 + if (a_template_bytes != b_template_bytes)
105 108 return JANUS_UNKNOWN_ERROR;
106 109  
107 110 float dist = 0;
108 111 for (size_t i=0; i<a_templates; i++)
109 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 115 *similarity = a_templates * b_templates / dist;
113 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 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 62 void br_pairwise_compare(const char *target_gallery, const char *query_gallery, const char *output)
57 63 {
58 64 PairwiseCompare(File(target_gallery), File(query_gallery), File(output));
... ... @@ -323,6 +329,14 @@ unsigned char *br_unload_img(br_template tmpl)
323 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 340 void br_free_template(br_template tmpl)
327 341 {
328 342 Template *t = reinterpret_cast<Template*>(tmpl);
... ... @@ -335,6 +349,12 @@ void br_free_template_list(br_template_list tl)
335 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 358 int br_img_rows(br_template tmpl)
339 359 {
340 360 Template *t = reinterpret_cast<Template*>(tmpl);
... ... @@ -359,6 +379,12 @@ bool br_img_is_empty(br_template tmpl)
359 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 388 void br_set_filename(br_template tmpl, const char *filename)
363 389 {
364 390 Template *t = reinterpret_cast<Template*>(tmpl);
... ... @@ -391,6 +417,21 @@ void br_enroll_template_list(br_template_list tl)
391 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 435 br_template br_get_template(br_template_list tl, int index)
395 436 {
396 437 TemplateList *realTL = reinterpret_cast<TemplateList*>(tl);
... ... @@ -412,7 +453,7 @@ br_gallery br_make_gallery(const char *gallery)
412 453 br_template_list br_load_from_gallery(br_gallery gallery)
413 454 {
414 455 Gallery *gal = reinterpret_cast<Gallery*>(gallery);
415   - TemplateList *tl = static_cast<TemplateList*>(malloc(sizeof(TemplateList)));
  456 + TemplateList *tl = new TemplateList();
416 457 *tl = gal->read();
417 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 102 */
103 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 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 443 typedef void* br_template;
438 444 typedef void* br_template_list;
439 445 typedef void* br_gallery;
  446 +typedef void* br_matrix_output;
440 447 /*!
441 448 * \brief Load an image from a string buffer.
442 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 459 */
453 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 468 * \brief Free a br::Template's memory.
456 469 */
457 470 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 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 480 * \brief Get the number of rows in an image.
464 481 * \param tmpl Pointer to a br::Template.
465 482 */
... ... @@ -479,7 +496,11 @@ BR_EXPORT int br_img_channels(br_template tmpl);
479 496 */
480 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 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 514 BR_EXPORT br_template_list br_enroll_template(br_template tmpl);
494 515 /*!
495 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 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 530 * \brief Get a pointer to a br::Template at a specified index.
501 531 * \param tl Pointer to a br::TemplateList.
502 532 * \param index The index of the br::Template.
... ...
openbr/openbr_plugin.cpp
... ... @@ -863,7 +863,7 @@ void br::Context::printStatus()
863 863 const float p = progress();
864 864 if (p < 1) {
865 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 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 349 BR_EXPORT QDebug operator<<(QDebug dbg, const File &file); /*!< \brief Prints br::File::flat() to \c stderr. */
336 350 BR_EXPORT QDataStream &operator<<(QDataStream &stream, const File &file); /*!< \brief Serializes the file to a stream. */
337 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 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 488 QList<TemplateList> partition(const QList<int> &partitionSizes) const
475 489 {
... ... @@ -1329,6 +1343,11 @@ BR_EXPORT void Enroll(TemplateList &amp;tmpl);
1329 1343 * \see br_compare
1330 1344 */
1331 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 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 179  
180 180 /*!
181 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 183 * \author Scott Klum \cite sklum
184 184 * \note Operation: Mean, sum, min, max are supported.
185 185 */
186   -class OperationDistance : public Distance
  186 +class FuseDistance : public Distance
187 187 {
188 188 Q_OBJECT
189 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 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 196 public:
194 197 /*!< */
195 198 enum Operation {Mean, Sum, Max, Min};
196 199  
197 200 private:
198   - BR_PROPERTY(br::Distance*, distance, make("Dist(L2)"))
  201 + BR_PROPERTY(QString, description, "IdenticalDistance")
199 202 BR_PROPERTY(Operation, operation, Mean)
  203 + BR_PROPERTY(QList<float>, weights, QList<float>())
200 204  
201 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 221 float compare(const Template &a, const Template &b) const
207 222 {
208 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 232 switch (operation) {
215 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 235 break;
218 236 case Sum:
219   - return std::accumulate(distances.begin(),distances.end(),0.0);
  237 + return std::accumulate(scores.begin(),scores.end(),0.0);
220 238 break;
221 239 case Min:
222   - return *std::min_element(distances.begin(),distances.end());
  240 + return *std::min_element(scores.begin(),scores.end());
223 241 break;
224 242 case Max:
225   - return *std::max_element(distances.begin(),distances.end());
  243 + return *std::max_element(scores.begin(),scores.end());
226 244 break;
227 245 default:
228 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 271 * \ingroup distances
... ...
openbr/plugins/gallery.cpp
... ... @@ -99,12 +99,12 @@ class galGallery : public Gallery
99 99 void init()
100 100 {
101 101 gallery.setFileName(file);
102   - if (file.get<bool>("remove", false))
  102 + if (file.get<bool>("remove"))
103 103 gallery.remove();
104 104 QtUtils::touchDir(gallery);
105 105 QFile::OpenMode mode = QFile::ReadWrite;
106 106  
107   - if (file.contains("append"))
  107 + if (file.get<bool>("append"))
108 108 mode |= QFile::Append;
109 109  
110 110 if (!gallery.open(mode))
... ...
openbr/plugins/gui.cpp
... ... @@ -13,6 +13,7 @@
13 13  
14 14 #include <opencv2/imgproc/imgproc.hpp>
15 15 #include "openbr_internal.h"
  16 +#include "openbr/gui/utility.h"
16 17  
17 18 using namespace cv;
18 19  
... ... @@ -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 125 class DisplayWindow : public QLabel
164 126 {
165 127 Q_OBJECT
... ...
openbr/plugins/independent.cpp
... ... @@ -156,8 +156,8 @@ class IndependentTransform : public MetaTransform
156 156  
157 157 QFutureSynchronizer<void> futures;
158 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 163 void project(const Template &src, Template &dst) const
... ...
openbr/plugins/misc.cpp
... ... @@ -514,28 +514,16 @@ class ProgressCounterTransform : public TimeVaryingTransform
514 514 void projectUpdate(const TemplateList &src, TemplateList &dst)
515 515 {
516 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 523 timer.start();
536   - set_calls = 0;
537 524 }
538 525  
  526 + Globals->currentStep++;
539 527  
540 528 return;
541 529 }
... ... @@ -548,24 +536,18 @@ class ProgressCounterTransform : public TimeVaryingTransform
548 536 void finalize(TemplateList & data)
549 537 {
550 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 543 void init()
556 544 {
557   - calls = 0;
558   - set_calls = 0;
559 545 timer.start();
560 546 }
561 547  
562 548 public:
563 549 ProgressCounterTransform() : TimeVaryingTransform(false,false) {}
564   - bool initialized;
565 550 QElapsedTimer timer;
566   - qint64 calls;
567   - qint64 set_calls;
568   -
569 551 };
570 552  
571 553 BR_REGISTER(Transform, ProgressCounterTransform)
... ...
openbr/plugins/quality.cpp
... ... @@ -173,7 +173,7 @@ class MatchProbabilityDistance : public Distance
173 173 for (int j=0; j<i; j++) {
174 174 const float score = matrixOutput.data()->data.at<float>(i, j);
175 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 177 if (labels[i] == labels[j]) genuineScores.append(score);
178 178 else impostorScores.append(score);
179 179 }
... ... @@ -211,6 +211,65 @@ protected:
211 211  
212 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 274 * \ingroup distances
216 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 216  
217 217 /*!
218 218 * \ingroup transforms
219   - * \brief .
  219 + * \brief Document me
220 220 * \author Austin Blanton \cite imaus10
221 221 */
222 222 class BuildScalesTransform : public Transform
... ...
openbr/plugins/validate.cpp
... ... @@ -104,15 +104,13 @@ class CrossValidateTransform : public MetaTransform
104 104 // since it is assumed that the allPartitions
105 105 // flag is only used during comparison
106 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 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
... ...