Commit bc16c3ddb3a63e30da08cdf8324531126a90937f
1 parent
b48eeb8b
Give Distribute better support for handling timevarying transforms
Introduce 'pseudocopy' operation which, which if called on a time-invariant transform, returns the transform, but if called on a time-varying transform returns a copy of the current state of the time-varying transform. Composite transforms apply pseudocopy to their children (if they contain any time-varying transforms). Introduce a wrapper class that uses Resource to let time-varying transforms act like time-invariant transforms, currently only used by distribute (it is assumed that any work that is being distributed is in fact independent).
Showing
2 changed files
with
108 additions
and
16 deletions
openbr/openbr_plugin.h
| @@ -1085,6 +1085,8 @@ public: | @@ -1085,6 +1085,8 @@ public: | ||
| 1085 | return dst; | 1085 | return dst; |
| 1086 | } | 1086 | } |
| 1087 | 1087 | ||
| 1088 | + virtual Transform * pseudoCopy() { return this;} | ||
| 1089 | + | ||
| 1088 | protected: | 1090 | protected: |
| 1089 | Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */ | 1091 | Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */ |
| 1090 | inline Transform *make(const QString &description) { return make(description, this); } /*!< \brief Make a subtransform. */ | 1092 | inline Transform *make(const QString &description) { return make(description, this); } /*!< \brief Make a subtransform. */ |
| @@ -1165,6 +1167,12 @@ public: | @@ -1165,6 +1167,12 @@ public: | ||
| 1165 | } | 1167 | } |
| 1166 | } | 1168 | } |
| 1167 | 1169 | ||
| 1170 | + virtual Transform * pseudoCopy() | ||
| 1171 | + { | ||
| 1172 | + return this->clone(); | ||
| 1173 | + } | ||
| 1174 | + | ||
| 1175 | + | ||
| 1168 | protected: | 1176 | protected: |
| 1169 | TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} | 1177 | TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} |
| 1170 | }; | 1178 | }; |
| @@ -1243,6 +1251,38 @@ public: | @@ -1243,6 +1251,38 @@ public: | ||
| 1243 | } | 1251 | } |
| 1244 | } | 1252 | } |
| 1245 | 1253 | ||
| 1254 | + Transform * pseudoCopy() | ||
| 1255 | + { | ||
| 1256 | + if (!timeVarying()) | ||
| 1257 | + return this; | ||
| 1258 | + | ||
| 1259 | + QString name = metaObject()->className(); | ||
| 1260 | + name.replace("Transform",""); | ||
| 1261 | + name += "([])"; | ||
| 1262 | + name.replace("br::",""); | ||
| 1263 | + CompositeTransform * output = dynamic_cast<CompositeTransform *>(Transform::make(name, NULL)); | ||
| 1264 | + | ||
| 1265 | + if (output == NULL) | ||
| 1266 | + qFatal("Dynamic cast failed!"); | ||
| 1267 | + | ||
| 1268 | + foreach(Transform* t, transforms ) | ||
| 1269 | + { | ||
| 1270 | + Transform * maybe_copy = t->pseudoCopy(); | ||
| 1271 | + if (maybe_copy->parent() == NULL) | ||
| 1272 | + maybe_copy->setParent(output); | ||
| 1273 | + output->transforms.append(t->pseudoCopy()); | ||
| 1274 | + } | ||
| 1275 | + | ||
| 1276 | + output->file = this->file; | ||
| 1277 | + output->classes = classes; | ||
| 1278 | + output->instances = instances; | ||
| 1279 | + output->fraction = fraction; | ||
| 1280 | + | ||
| 1281 | + output->init(); | ||
| 1282 | + | ||
| 1283 | + return output; | ||
| 1284 | + } | ||
| 1285 | + | ||
| 1246 | protected: | 1286 | protected: |
| 1247 | bool isTimeVarying; | 1287 | bool isTimeVarying; |
| 1248 | 1288 |
openbr/plugins/meta.cpp
| @@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
| 21 | #include "openbr/core/common.h" | 21 | #include "openbr/core/common.h" |
| 22 | #include "openbr/core/opencvutils.h" | 22 | #include "openbr/core/opencvutils.h" |
| 23 | #include "openbr/core/qtutils.h" | 23 | #include "openbr/core/qtutils.h" |
| 24 | +#include "openbr/core/resource.h" | ||
| 24 | 25 | ||
| 25 | using namespace cv; | 26 | using namespace cv; |
| 26 | 27 | ||
| @@ -183,7 +184,6 @@ class PipeTransform : public CompositeTransform | @@ -183,7 +184,6 @@ class PipeTransform : public CompositeTransform | ||
| 183 | } | 184 | } |
| 184 | } | 185 | } |
| 185 | 186 | ||
| 186 | - | ||
| 187 | protected: | 187 | protected: |
| 188 | // Template list project -- process templates in parallel through Transform::project | 188 | // Template list project -- process templates in parallel through Transform::project |
| 189 | // or if parallelism is disabled, handle them sequentially | 189 | // or if parallelism is disabled, handle them sequentially |
| @@ -590,6 +590,56 @@ static void _projectList(const Transform *transform, const TemplateList *src, Te | @@ -590,6 +590,56 @@ static void _projectList(const Transform *transform, const TemplateList *src, Te | ||
| 590 | } | 590 | } |
| 591 | 591 | ||
| 592 | 592 | ||
| 593 | +class TransformCopier : public ResourceMaker<Transform> | ||
| 594 | +{ | ||
| 595 | +public: | ||
| 596 | + Transform * basis; | ||
| 597 | + TransformCopier(Transform * _basis) | ||
| 598 | + { | ||
| 599 | + basis = _basis; | ||
| 600 | + } | ||
| 601 | + | ||
| 602 | + virtual Transform *make() const | ||
| 603 | + { | ||
| 604 | + return basis->pseudoCopy(); | ||
| 605 | + } | ||
| 606 | + | ||
| 607 | +}; | ||
| 608 | + | ||
| 609 | +class TimeInvariantWrapperTransform : public MetaTransform | ||
| 610 | +{ | ||
| 611 | +public: | ||
| 612 | + Resource<Transform> transformSource; | ||
| 613 | + | ||
| 614 | + TimeInvariantWrapperTransform(Transform * basis) : transformSource(new TransformCopier(basis)) | ||
| 615 | + { | ||
| 616 | + baseTransform = basis; | ||
| 617 | + } | ||
| 618 | + | ||
| 619 | + virtual void project(const Template &src, Template &dst) const | ||
| 620 | + { | ||
| 621 | + Transform * aTransform = transformSource.acquire(); | ||
| 622 | + aTransform->projectUpdate(src,dst); | ||
| 623 | + transformSource.release(aTransform); | ||
| 624 | + } | ||
| 625 | + | ||
| 626 | + | ||
| 627 | + void project(const TemplateList &src, TemplateList &dst) const | ||
| 628 | + { | ||
| 629 | + Transform * aTransform = transformSource.acquire(); | ||
| 630 | + aTransform->projectUpdate(src,dst); | ||
| 631 | + transformSource.release(aTransform); | ||
| 632 | + } | ||
| 633 | + | ||
| 634 | + void train(const TemplateList &data) | ||
| 635 | + { | ||
| 636 | + baseTransform->train(data); | ||
| 637 | + } | ||
| 638 | + | ||
| 639 | +private: | ||
| 640 | + Transform * baseTransform; | ||
| 641 | +}; | ||
| 642 | + | ||
| 593 | class DistributeTemplateTransform : public MetaTransform | 643 | class DistributeTemplateTransform : public MetaTransform |
| 594 | { | 644 | { |
| 595 | Q_OBJECT | 645 | Q_OBJECT |
| @@ -598,6 +648,16 @@ class DistributeTemplateTransform : public MetaTransform | @@ -598,6 +648,16 @@ class DistributeTemplateTransform : public MetaTransform | ||
| 598 | 648 | ||
| 599 | public: | 649 | public: |
| 600 | 650 | ||
| 651 | + Transform * pseudoCopy() | ||
| 652 | + { | ||
| 653 | + if (!transform->timeVarying()) | ||
| 654 | + return this; | ||
| 655 | + | ||
| 656 | + DistributeTemplateTransform * output = new DistributeTemplateTransform; | ||
| 657 | + output->transform = transform->pseudoCopy(); | ||
| 658 | + return output; | ||
| 659 | + } | ||
| 660 | + | ||
| 601 | void train(const TemplateList &data) | 661 | void train(const TemplateList &data) |
| 602 | { | 662 | { |
| 603 | transform->train(data); | 663 | transform->train(data); |
| @@ -620,15 +680,6 @@ public: | @@ -620,15 +680,6 @@ public: | ||
| 620 | // Process the single elemnt templates in parallel if parallelism is enabled. | 680 | // Process the single elemnt templates in parallel if parallelism is enabled. |
| 621 | void project(const TemplateList &src, TemplateList &dst) const | 681 | void project(const TemplateList &src, TemplateList &dst) const |
| 622 | { | 682 | { |
| 623 | - // Little ugly, but if we own a timeVaryingTransform and this gets called | ||
| 624 | - // cast off the const modifier and use projectUpdate. This allows us to | ||
| 625 | - // act as a single point of entry. | ||
| 626 | - if (transform->timeVarying()) | ||
| 627 | - { | ||
| 628 | - DistributeTemplateTransform * non_const = (DistributeTemplateTransform *) this; | ||
| 629 | - non_const->projectUpdate(src,dst); | ||
| 630 | - return; | ||
| 631 | - } | ||
| 632 | // Pre-allocate output for each template | 683 | // Pre-allocate output for each template |
| 633 | QList<TemplateList> output_buffer; | 684 | QList<TemplateList> output_buffer; |
| 634 | output_buffer.reserve(src.size()); | 685 | output_buffer.reserve(src.size()); |
| @@ -655,15 +706,16 @@ public: | @@ -655,15 +706,16 @@ public: | ||
| 655 | 706 | ||
| 656 | void projectUpdate(const TemplateList &src, TemplateList &dst) | 707 | void projectUpdate(const TemplateList &src, TemplateList &dst) |
| 657 | { | 708 | { |
| 658 | - if (!transform->timeVarying()) { | ||
| 659 | - this->project(src, dst); | ||
| 660 | - return; | ||
| 661 | - } | ||
| 662 | - this->transform->projectUpdate(src, dst); | 709 | + this->project(src, dst); |
| 710 | + return; | ||
| 663 | } | 711 | } |
| 664 | 712 | ||
| 713 | + void init() | ||
| 714 | + { | ||
| 665 | 715 | ||
| 666 | - private: | 716 | + if (transform && transform->timeVarying()) |
| 717 | + transform = new br::TimeInvariantWrapperTransform(transform); | ||
| 718 | + } | ||
| 667 | 719 | ||
| 668 | }; | 720 | }; |
| 669 | BR_REGISTER(Transform, DistributeTemplateTransform) | 721 | BR_REGISTER(Transform, DistributeTemplateTransform) |