Commit 63596a8c07e442170ff00bbe05eeed4b53a4faf2
Merge pull request #26 from biometrics/variable_output
Structural changes to the basic multi-template enrollment operation
Showing
5 changed files
with
112 additions
and
128 deletions
sdk/core/core.cpp
| @@ -262,6 +262,9 @@ private: | @@ -262,6 +262,9 @@ private: | ||
| 262 | QStringList words = QtUtils::parse(description, ':'); | 262 | QStringList words = QtUtils::parse(description, ':'); |
| 263 | if (words.size() > 2) qFatal("Invalid algorithm format."); | 263 | if (words.size() > 2) qFatal("Invalid algorithm format."); |
| 264 | 264 | ||
| 265 | + words[0].prepend("DistributeTemplate("); | ||
| 266 | + words[0].append(")"); | ||
| 267 | + | ||
| 265 | transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); | 268 | transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); |
| 266 | if (words.size() > 1) distance = QSharedPointer<Distance>(Distance::make(words[1], NULL)); | 269 | if (words.size() > 1) distance = QSharedPointer<Distance>(Distance::make(words[1], NULL)); |
| 267 | } | 270 | } |
sdk/openbr_plugin.cpp
| @@ -1202,10 +1202,8 @@ Transform *Transform::make(QString str, QObject *parent) | @@ -1202,10 +1202,8 @@ Transform *Transform::make(QString str, QObject *parent) | ||
| 1202 | if (Globals->abbreviations.contains(str)) | 1202 | if (Globals->abbreviations.contains(str)) |
| 1203 | return make(Globals->abbreviations[str], parent); | 1203 | return make(Globals->abbreviations[str], parent); |
| 1204 | 1204 | ||
| 1205 | - { // Check for use of '!' as shorthand for Expand(...) | ||
| 1206 | - QStringList words = parse(str, '!'); | ||
| 1207 | - if (words.size() > 1) | ||
| 1208 | - return make("Expand([" + words.join(",") + "])", parent); | 1205 | + { // Check for use of '!' as shorthand for Expand |
| 1206 | + str.replace("!","+Expand+"); | ||
| 1209 | } | 1207 | } |
| 1210 | 1208 | ||
| 1211 | { // Check for use of '+' as shorthand for Pipe(...) | 1209 | { // Check for use of '+' as shorthand for Pipe(...) |
| @@ -1250,17 +1248,6 @@ Transform *Transform::clone() const | @@ -1250,17 +1248,6 @@ Transform *Transform::clone() const | ||
| 1250 | return clone; | 1248 | return clone; |
| 1251 | } | 1249 | } |
| 1252 | 1250 | ||
| 1253 | -static void _project(const Transform *transform, const Template *src, Template *dst) | ||
| 1254 | -{ | ||
| 1255 | - try { | ||
| 1256 | - transform->project(*src, *dst); | ||
| 1257 | - } catch (...) { | ||
| 1258 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName())); | ||
| 1259 | - *dst = Template(src->file); | ||
| 1260 | - dst->file.set("FTE", true); | ||
| 1261 | - } | ||
| 1262 | -} | ||
| 1263 | - | ||
| 1264 | static void _backProject(const Transform *transform, const Template *dst, Template *src) | 1251 | static void _backProject(const Transform *transform, const Template *dst, Template *src) |
| 1265 | { | 1252 | { |
| 1266 | try { | 1253 | try { |
| @@ -1273,17 +1260,25 @@ static void _backProject(const Transform *transform, const Template *dst, Templa | @@ -1273,17 +1260,25 @@ static void _backProject(const Transform *transform, const Template *dst, Templa | ||
| 1273 | } | 1260 | } |
| 1274 | 1261 | ||
| 1275 | 1262 | ||
| 1263 | + | ||
| 1264 | +// Default project(TemplateList) -- call project(template) separately for each input | ||
| 1265 | +// template | ||
| 1276 | void Transform::project(const TemplateList &src, TemplateList &dst) const | 1266 | void Transform::project(const TemplateList &src, TemplateList &dst) const |
| 1277 | { | 1267 | { |
| 1278 | - dst.reserve(src.size()); | ||
| 1279 | - for (int i=0; i<src.size(); i++) dst.append(Template()); | ||
| 1280 | - | ||
| 1281 | - QList< QFuture<void> > futures; | ||
| 1282 | - if (Globals->parallelism) futures.reserve(src.size()); | ||
| 1283 | - for (int i=0; i<src.size(); i++) | ||
| 1284 | - if (Globals->parallelism) futures.append(QtConcurrent::run(_project, this, &src[i], &dst[i])); | ||
| 1285 | - else _project (this, &src[i], &dst[i]); | ||
| 1286 | - if (Globals->parallelism) Globals->trackFutures(futures); | 1268 | + dst.clear(); |
| 1269 | + | ||
| 1270 | + // Project templates derived from a single image, default implementation: project each | ||
| 1271 | + // input template to an ouptut template individually. | ||
| 1272 | + foreach(const Template & src_template, src) { | ||
| 1273 | + dst.append(Template(src_template.file)); | ||
| 1274 | + try { | ||
| 1275 | + project(src_template, dst.back()); | ||
| 1276 | + } catch (...) { | ||
| 1277 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src_template.file.flat()), qPrintable(objectName())); | ||
| 1278 | + dst.back() = Template(src_template.file); | ||
| 1279 | + dst.back().file.set("FTE", true); | ||
| 1280 | + } | ||
| 1281 | + } | ||
| 1287 | } | 1282 | } |
| 1288 | 1283 | ||
| 1289 | void Transform::backProject(const Template &dst, Template &src) const | 1284 | void Transform::backProject(const Template &dst, Template &src) const |
sdk/plugins/gallery.cpp
| @@ -590,10 +590,10 @@ class dbGallery : public Gallery | @@ -590,10 +590,10 @@ class dbGallery : public Gallery | ||
| 590 | } | 590 | } |
| 591 | 591 | ||
| 592 | QStringList labels = entries.keys(); | 592 | QStringList labels = entries.keys(); |
| 593 | + qSort(labels); | ||
| 594 | + | ||
| 593 | if (hasFilter && ((labels.size() > numSubjects) || (numSubjects == std::numeric_limits<int>::max()))) | 595 | if (hasFilter && ((labels.size() > numSubjects) || (numSubjects == std::numeric_limits<int>::max()))) |
| 594 | std::random_shuffle(labels.begin(), labels.end()); | 596 | std::random_shuffle(labels.begin(), labels.end()); |
| 595 | - else | ||
| 596 | - qSort(labels); | ||
| 597 | 597 | ||
| 598 | foreach (const QString &label, labels) { | 598 | foreach (const QString &label, labels) { |
| 599 | QList<Entry> entryList = entries[label]; | 599 | QList<Entry> entryList = entries[label]; |
sdk/plugins/meta.cpp
| @@ -86,66 +86,6 @@ static void incrementStep() | @@ -86,66 +86,6 @@ static void incrementStep() | ||
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /*! | 88 | /*! |
| 89 | - * \brief Use Expanded after basic calls that take a template list, used to implement ExpandTransform | ||
| 90 | - */ | ||
| 91 | -class ExpandDecorator : public Transform | ||
| 92 | -{ | ||
| 93 | - Q_OBJECT | ||
| 94 | - | ||
| 95 | - Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform) | ||
| 96 | - BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 97 | - | ||
| 98 | -public: | ||
| 99 | - ExpandDecorator(Transform * input) | ||
| 100 | - { | ||
| 101 | - transform = input; | ||
| 102 | - transform->setParent(this); | ||
| 103 | - file = transform->file; | ||
| 104 | - setObjectName(transform->objectName()); | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - void train(const TemplateList &data) | ||
| 108 | - { | ||
| 109 | - transform->train(data); | ||
| 110 | - } | ||
| 111 | - | ||
| 112 | - void project(const Template &src, Template &dst) const | ||
| 113 | - { | ||
| 114 | - transform->project(src, dst); | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - void project(const TemplateList &src, TemplateList &dst) const | ||
| 118 | - { | ||
| 119 | - transform->project(src, dst); | ||
| 120 | - dst = Expanded(dst); | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | - | ||
| 124 | - void projectUpdate(const Template &src, Template &dst) | ||
| 125 | - { | ||
| 126 | - transform->projectUpdate(src, dst); | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | - void projectUpdate(const TemplateList & src, TemplateList & dst) | ||
| 130 | - { | ||
| 131 | - transform->projectUpdate(src, dst); | ||
| 132 | - dst = Expanded(dst); | ||
| 133 | - } | ||
| 134 | - | ||
| 135 | - bool timeVarying() const | ||
| 136 | - { | ||
| 137 | - return transform->timeVarying(); | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - void finalize(TemplateList & output) | ||
| 141 | - { | ||
| 142 | - transform->finalize(output); | ||
| 143 | - output = Expanded(output); | ||
| 144 | - } | ||
| 145 | - | ||
| 146 | -}; | ||
| 147 | - | ||
| 148 | -/*! | ||
| 149 | * \brief A MetaTransform that aggregates some sub-transforms | 89 | * \brief A MetaTransform that aggregates some sub-transforms |
| 150 | */ | 90 | */ |
| 151 | class BR_EXPORT CompositeTransform : public TimeVaryingTransform | 91 | class BR_EXPORT CompositeTransform : public TimeVaryingTransform |
| @@ -291,12 +231,9 @@ protected: | @@ -291,12 +231,9 @@ protected: | ||
| 291 | // or if parallelism is disabled, handle them sequentially | 231 | // or if parallelism is disabled, handle them sequentially |
| 292 | void _project(const TemplateList &src, TemplateList &dst) const | 232 | void _project(const TemplateList &src, TemplateList &dst) const |
| 293 | { | 233 | { |
| 294 | - if (Globals->parallelism < 0) { | ||
| 295 | - dst = src; | ||
| 296 | - foreach (const Transform *f, transforms) | ||
| 297 | - dst >> *f; | ||
| 298 | - } else { | ||
| 299 | - Transform::project(src, dst); | 234 | + dst = src; |
| 235 | + foreach (const Transform *f, transforms) { | ||
| 236 | + dst >> *f; | ||
| 300 | } | 237 | } |
| 301 | } | 238 | } |
| 302 | 239 | ||
| @@ -320,40 +257,26 @@ BR_REGISTER(Transform, PipeTransform) | @@ -320,40 +257,26 @@ BR_REGISTER(Transform, PipeTransform) | ||
| 320 | 257 | ||
| 321 | /*! | 258 | /*! |
| 322 | * \ingroup transforms | 259 | * \ingroup transforms |
| 323 | - * \brief Transforms in series with expansion step. | 260 | + * \brief Performs an expansion step on input templatelists |
| 324 | * \author Josh Klontz \cite jklontz | 261 | * \author Josh Klontz \cite jklontz |
| 325 | * | 262 | * |
| 326 | - * The source br::Template is given to the first transform and the resulting br::Template is passed to the next transform, etc. | ||
| 327 | - * Each matrix is expanded into its own template between steps. | 263 | + * Each matrix in an input Template is expanded into its own template. |
| 328 | * | 264 | * |
| 329 | * \see PipeTransform | 265 | * \see PipeTransform |
| 330 | */ | 266 | */ |
| 331 | -class ExpandTransform : public PipeTransform | 267 | +class ExpandTransform : public UntrainableMetaTransform |
| 332 | { | 268 | { |
| 333 | Q_OBJECT | 269 | Q_OBJECT |
| 334 | 270 | ||
| 335 | - void init() | 271 | + virtual void project(const TemplateList &src, TemplateList &dst) const |
| 336 | { | 272 | { |
| 337 | - for (int i = 0; i < transforms.size(); i++) | ||
| 338 | - { | ||
| 339 | - transforms[i] = new ExpandDecorator(transforms[i]); | ||
| 340 | - } | ||
| 341 | - // Need to call this to set up timevariance correctly, and it won't | ||
| 342 | - // be called automatically | ||
| 343 | - CompositeTransform::init(); | 273 | + dst = Expanded(src); |
| 344 | } | 274 | } |
| 345 | 275 | ||
| 346 | -protected: | ||
| 347 | - | ||
| 348 | - // Template list project -- project through transforms sequentially, | ||
| 349 | - // then expand the results, can't use Transform::Project(templateList) since | ||
| 350 | - // we need to expand between tranforms, so actually do need to overload this method | ||
| 351 | - void _project(const TemplateList &src, TemplateList &dst) const | 276 | + virtual void project(const Template & src, Template & dst) const |
| 352 | { | 277 | { |
| 353 | - dst = src; | ||
| 354 | - for (int i=0; i<transforms.size(); i++) { | ||
| 355 | - dst >> *transforms[i]; | ||
| 356 | - } | 278 | + qFatal("this has gone bad"); |
| 279 | + (void) src; (void) dst; | ||
| 357 | } | 280 | } |
| 358 | }; | 281 | }; |
| 359 | 282 | ||
| @@ -405,12 +328,12 @@ class ForkTransform : public CompositeTransform | @@ -405,12 +328,12 @@ class ForkTransform : public CompositeTransform | ||
| 405 | { | 328 | { |
| 406 | dst = src; | 329 | dst = src; |
| 407 | dst.reserve(src.size()); | 330 | dst.reserve(src.size()); |
| 408 | - for (int i=0; i<src.size(); i++) dst.append(Template()); | 331 | + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file)); |
| 409 | foreach (Transform *f, transforms) { | 332 | foreach (Transform *f, transforms) { |
| 410 | TemplateList m; | 333 | TemplateList m; |
| 411 | f->projectUpdate(src, m); | 334 | f->projectUpdate(src, m); |
| 412 | if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); | 335 | if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); |
| 413 | - for (int i=0; i<src.size(); i++) dst[i].append(m[i]); | 336 | + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]); |
| 414 | } | 337 | } |
| 415 | } | 338 | } |
| 416 | 339 | ||
| @@ -460,17 +383,13 @@ protected: | @@ -460,17 +383,13 @@ protected: | ||
| 460 | 383 | ||
| 461 | void _project(const TemplateList &src, TemplateList &dst) const | 384 | void _project(const TemplateList &src, TemplateList &dst) const |
| 462 | { | 385 | { |
| 463 | - if (Globals->parallelism < 0) { | ||
| 464 | - dst.reserve(src.size()); | ||
| 465 | - for (int i=0; i<src.size(); i++) dst.append(Template()); | ||
| 466 | - foreach (const Transform *f, transforms) { | ||
| 467 | - TemplateList m; | ||
| 468 | - f->project(src, m); | ||
| 469 | - if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); | ||
| 470 | - for (int i=0; i<src.size(); i++) dst[i].append(m[i]); | ||
| 471 | - } | ||
| 472 | - } else { | ||
| 473 | - Transform::project(src, dst); | 386 | + dst.reserve(src.size()); |
| 387 | + for (int i=0; i<src.size(); i++) dst.append(Template(src[i].file)); | ||
| 388 | + foreach (const Transform *f, transforms) { | ||
| 389 | + TemplateList m; | ||
| 390 | + f->project(src, m); | ||
| 391 | + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); | ||
| 392 | + for (int i=0; i<src.size(); i++) dst[i].merge(m[i]); | ||
| 474 | } | 393 | } |
| 475 | } | 394 | } |
| 476 | 395 | ||
| @@ -670,6 +589,73 @@ class FTETransform : public Transform | @@ -670,6 +589,73 @@ class FTETransform : public Transform | ||
| 670 | 589 | ||
| 671 | BR_REGISTER(Transform, FTETransform) | 590 | BR_REGISTER(Transform, FTETransform) |
| 672 | 591 | ||
| 592 | + | ||
| 593 | +static void _projectList(const Transform *transform, const TemplateList *src, TemplateList *dst) | ||
| 594 | +{ | ||
| 595 | + transform->project(*src, *dst); | ||
| 596 | +} | ||
| 597 | + | ||
| 598 | + | ||
| 599 | +class DistributeTemplateTransform : public UntrainableMetaTransform | ||
| 600 | +{ | ||
| 601 | + Q_OBJECT | ||
| 602 | + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform RESET reset_transform) | ||
| 603 | + BR_PROPERTY(br::Transform*, transform, NULL) | ||
| 604 | + | ||
| 605 | +public: | ||
| 606 | + | ||
| 607 | + void project(const Template &src, Template &dst) const | ||
| 608 | + { | ||
| 609 | + TemplateList input; | ||
| 610 | + input.append(src); | ||
| 611 | + TemplateList output; | ||
| 612 | + project(input, output); | ||
| 613 | + | ||
| 614 | + if (output.size() != 1) qFatal("output contains more than 1 template"); | ||
| 615 | + else dst = output[0]; | ||
| 616 | + } | ||
| 617 | + | ||
| 618 | + | ||
| 619 | + // For each input template, form a single element TemplateList, push all those | ||
| 620 | + // lists through transform, and form dst by concatenating the results. | ||
| 621 | + // Process the single elemnt templates in parallel if parallelism is enabled. | ||
| 622 | + void project(const TemplateList &src, TemplateList &dst) const | ||
| 623 | + { | ||
| 624 | + // Pre-allocate output for each template | ||
| 625 | + QList<TemplateList> output_buffer; | ||
| 626 | + output_buffer.reserve(src.size()); | ||
| 627 | + | ||
| 628 | + // Can't declare this local to the loop because it would go out of scope | ||
| 629 | + QList<TemplateList> input_buffer; | ||
| 630 | + input_buffer.reserve(src.size()); | ||
| 631 | + | ||
| 632 | + for (int i =0; i < src.size();i++) { | ||
| 633 | + input_buffer.append(TemplateList()); | ||
| 634 | + output_buffer.append(TemplateList()); | ||
| 635 | + } | ||
| 636 | + | ||
| 637 | + QList< QFuture<void> > futures; | ||
| 638 | + futures.reserve(src.size()); | ||
| 639 | + for (int i=0; i<src.size(); i++) { | ||
| 640 | + input_buffer[i].append(src[i]); | ||
| 641 | + if (Globals->parallelism) | ||
| 642 | + futures.append(QtConcurrent::run(_projectList, transform, &input_buffer[i], &output_buffer[i])); | ||
| 643 | + else | ||
| 644 | + _projectList(transform, &input_buffer[i], &output_buffer[i]); | ||
| 645 | + } | ||
| 646 | + | ||
| 647 | + if (Globals->parallelism) | ||
| 648 | + Globals->trackFutures(futures); | ||
| 649 | + | ||
| 650 | + for (int i=0; i<src.size(); i++) dst.append(output_buffer[i]); | ||
| 651 | + } | ||
| 652 | + | ||
| 653 | + | ||
| 654 | + private: | ||
| 655 | + | ||
| 656 | +}; | ||
| 657 | +BR_REGISTER(Transform, DistributeTemplateTransform) | ||
| 658 | + | ||
| 673 | } // namespace br | 659 | } // namespace br |
| 674 | 660 | ||
| 675 | #include "meta.moc" | 661 | #include "meta.moc" |