Commit e465e02e43c1610e59a1df09c4a6c5a5639402c2
1 parent
fe72ae12
API changes in support of adding a stream based processing model
Allow inherited properties to be set via a transforms argument list at the command line, but exclude properties of classes that directly inherit from br::Object (this excludes e.g. Transform's properties which should be set during training). Properties are set in the same order that is currently used (the order of their property declarations), but all superclass properties are set before base class properties. Changes to the Transform API: add a set of methods supporting non-const project operations. Since overloading with a non-const version of the same function name won't work, the methods are called projectUpdate, since they perform the expected project operation, but also allow the transform to update its internal state. This can be used to support tracking operations, as well as online learning methods. All current classes can implement projectUpdate by calling their const project method. To handle variable input/output situations (e.g. a tracking function may only wish to emit a single template per unique detected object), a "finalize" method is also added to Transform, to be called to indicate that no further calls to projectUpdate will be made, and allow the transform to emit any final templates This is only relevant for non-const project since a time-invariant transform has no way to manage an internal list of templates it is waiting to emit. Add a "timeVarying" method to Transform, which returns a bool indicate whether or not the transform is time-invariant (only projectUpdate should be called for a time-varying transform). Refactor Transforms that maintain a list of subclasses (pipe transform, expand transform, fork transform, random transform) to inherit from a common subclass (CompositeTransform). Time variance for composite transforms is set based on their child transforms -- a composite transform with any time-varying children is time-varying. Some code consolidation via the shared subclass.
Showing
4 changed files
with
388 additions
and
91 deletions
sdk/openbr_plugin.cpp
| @@ -494,7 +494,8 @@ TemplateList TemplateList::relabel(const TemplateList &tl) | @@ -494,7 +494,8 @@ TemplateList TemplateList::relabel(const TemplateList &tl) | ||
| 494 | QStringList Object::parameters() const | 494 | QStringList Object::parameters() const |
| 495 | { | 495 | { |
| 496 | QStringList parameters; | 496 | QStringList parameters; |
| 497 | - for (int i=metaObject()->propertyOffset(); i<metaObject()->propertyCount(); i++) { | 497 | + |
| 498 | + for (int i = first_available_property_idx; i < metaObject()->propertyCount();i++) { | ||
| 498 | QMetaProperty property = metaObject()->property(i); | 499 | QMetaProperty property = metaObject()->property(i); |
| 499 | if (property.isStored(this)) continue; | 500 | if (property.isStored(this)) continue; |
| 500 | parameters.append(QString("%1 %2 = %3").arg(property.typeName(), property.name(), property.read(this).toString())); | 501 | parameters.append(QString("%1 %2 = %3").arg(property.typeName(), property.name(), property.read(this).toString())); |
| @@ -713,18 +714,37 @@ void Object::init(const File &file_) | @@ -713,18 +714,37 @@ void Object::init(const File &file_) | ||
| 713 | // Set name | 714 | // Set name |
| 714 | QString name = metaObject()->className(); | 715 | QString name = metaObject()->className(); |
| 715 | if (name.startsWith("br::")) name = name.right(name.size()-4); | 716 | if (name.startsWith("br::")) name = name.right(name.size()-4); |
| 716 | - const QMetaObject *superClass = metaObject()->superClass(); | 717 | + |
| 718 | + first_available_property_idx = metaObject()->propertyCount(); | ||
| 719 | + | ||
| 720 | + const QMetaObject * baseClass = metaObject(); | ||
| 721 | + const QMetaObject * superClass = metaObject()->superClass(); | ||
| 722 | + | ||
| 717 | while (superClass != NULL) { | 723 | while (superClass != NULL) { |
| 724 | + const QMetaObject * nextClass = superClass->superClass(); | ||
| 725 | + | ||
| 726 | + // baseClass <- something <- br::Object | ||
| 727 | + // baseClass is the highest class whose properties we can set via positional arguments | ||
| 728 | + if (nextClass && !strcmp(nextClass->className(),"br::Object")) { | ||
| 729 | + first_available_property_idx = baseClass->propertyOffset(); | ||
| 730 | + } | ||
| 731 | + | ||
| 718 | QString superClassName = superClass->className(); | 732 | QString superClassName = superClass->className(); |
| 733 | + | ||
| 734 | + // strip br:: prefix from superclass name | ||
| 719 | if (superClassName.startsWith("br::")) | 735 | if (superClassName.startsWith("br::")) |
| 720 | superClassName = superClassName.right(superClassName.size()-4); | 736 | superClassName = superClassName.right(superClassName.size()-4); |
| 737 | + | ||
| 738 | + // Strip superclass name from base class name (e.g. PipeTransform -> Pipe) | ||
| 721 | if (name.endsWith(superClassName)) | 739 | if (name.endsWith(superClassName)) |
| 722 | name = name.left(name.size() - superClassName.size()); | 740 | name = name.left(name.size() - superClassName.size()); |
| 741 | + baseClass = superClass; | ||
| 723 | superClass = superClass->superClass(); | 742 | superClass = superClass->superClass(); |
| 743 | + | ||
| 724 | } | 744 | } |
| 725 | setObjectName(name); | 745 | setObjectName(name); |
| 726 | 746 | ||
| 727 | - // Set properties | 747 | + // Reset all properties |
| 728 | for (int i=0; i<metaObject()->propertyCount(); i++) { | 748 | for (int i=0; i<metaObject()->propertyCount(); i++) { |
| 729 | QMetaProperty property = metaObject()->property(i); | 749 | QMetaProperty property = metaObject()->property(i); |
| 730 | if (property.isResettable()) | 750 | if (property.isResettable()) |
| @@ -734,8 +754,17 @@ void Object::init(const File &file_) | @@ -734,8 +754,17 @@ void Object::init(const File &file_) | ||
| 734 | 754 | ||
| 735 | foreach (QString key, file.localKeys()) { | 755 | foreach (QString key, file.localKeys()) { |
| 736 | const QString value = file.value(key).toString(); | 756 | const QString value = file.value(key).toString(); |
| 737 | - if (key.startsWith("_Arg")) | ||
| 738 | - key = metaObject()->property(metaObject()->propertyOffset()+key.mid(4).toInt()).name(); | 757 | + |
| 758 | + if (key.startsWith(("_Arg"))) { | ||
| 759 | + int argument_number = key.mid(4).toInt(); | ||
| 760 | + int target_idx = argument_number + first_available_property_idx; | ||
| 761 | + | ||
| 762 | + if (target_idx >= metaObject()->propertyCount()) { | ||
| 763 | + qWarning("too many arguments for transform, ignoring %s\n", qPrintable(value)); | ||
| 764 | + continue; | ||
| 765 | + } | ||
| 766 | + key = metaObject()->property(target_idx).name(); | ||
| 767 | + } | ||
| 739 | setProperty(key, value); | 768 | setProperty(key, value); |
| 740 | } | 769 | } |
| 741 | 770 |
sdk/openbr_plugin.h
| @@ -421,6 +421,9 @@ class BR_EXPORT Object : public QObject | @@ -421,6 +421,9 @@ class BR_EXPORT Object : public QObject | ||
| 421 | { | 421 | { |
| 422 | Q_OBJECT | 422 | Q_OBJECT |
| 423 | 423 | ||
| 424 | + // Index of the first property that can be set via command line arguments | ||
| 425 | + int first_available_property_idx; | ||
| 426 | + | ||
| 424 | public: | 427 | public: |
| 425 | File file; /*!< \brief The file used to construct the plugin. */ | 428 | File file; /*!< \brief The file used to construct the plugin. */ |
| 426 | 429 | ||
| @@ -989,6 +992,48 @@ public: | @@ -989,6 +992,48 @@ public: | ||
| 989 | virtual void backProject(const Template &dst, Template &src) const; /*!< \brief Invert the transform. */ | 992 | virtual void backProject(const Template &dst, Template &src) const; /*!< \brief Invert the transform. */ |
| 990 | virtual void backProject(const TemplateList &dst, TemplateList &src) const; /*!< \brief Invert the transform. */ | 993 | virtual void backProject(const TemplateList &dst, TemplateList &src) const; /*!< \brief Invert the transform. */ |
| 991 | 994 | ||
| 995 | + /*!< \brief Apply the transform, may update the transform's internal state */ | ||
| 996 | + virtual void projectUpdate(const Template &src, Template &dst) | ||
| 997 | + { | ||
| 998 | + project(src, dst); | ||
| 999 | + } | ||
| 1000 | + | ||
| 1001 | + /*!< \brief Apply the transform, may update the transform's internal state */ | ||
| 1002 | + virtual void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 1003 | + { | ||
| 1004 | + project(src,dst); | ||
| 1005 | + } | ||
| 1006 | + | ||
| 1007 | + // inplace project/update | ||
| 1008 | + void projectUpdate(Template & src) | ||
| 1009 | + { | ||
| 1010 | + Template dst = src; | ||
| 1011 | + projectUpdate(src, dst); | ||
| 1012 | + src = dst; | ||
| 1013 | + } | ||
| 1014 | + void projectUpdate(TemplateList & src) | ||
| 1015 | + { | ||
| 1016 | + TemplateList dst = src; | ||
| 1017 | + projectUpdate(src, dst); | ||
| 1018 | + src = dst; | ||
| 1019 | + } | ||
| 1020 | + | ||
| 1021 | + // Time-varying transforms may move away from a single input->single output model, and only emit | ||
| 1022 | + // templates under some conditions (e.g. a tracking thing may emit a template for each detected | ||
| 1023 | + // unique object), in this case finalize indicates that no further calls to project will be made | ||
| 1024 | + // and the transform can emit a final set if templates if it wants. Time-invariant transforms | ||
| 1025 | + // don't have to do anything. | ||
| 1026 | + virtual void finalize(TemplateList & output) | ||
| 1027 | + { | ||
| 1028 | + output = TemplateList(); | ||
| 1029 | + } | ||
| 1030 | + | ||
| 1031 | + /*! | ||
| 1032 | + * \brief Does the transform require the non-const version of project? Can vary for aggregation type transforms | ||
| 1033 | + * (if their children are time varying, they are also time varying, otherwise probably not) | ||
| 1034 | + */ | ||
| 1035 | + virtual bool timeVarying() const {return false;} | ||
| 1036 | + | ||
| 992 | /*! | 1037 | /*! |
| 993 | * \brief Convenience function equivalent to project(). | 1038 | * \brief Convenience function equivalent to project(). |
| 994 | */ | 1039 | */ |
| @@ -1051,6 +1096,33 @@ inline QDataStream &operator>>(QDataStream &stream, Transform &f) | @@ -1051,6 +1096,33 @@ inline QDataStream &operator>>(QDataStream &stream, Transform &f) | ||
| 1051 | return stream; | 1096 | return stream; |
| 1052 | } | 1097 | } |
| 1053 | 1098 | ||
| 1099 | + | ||
| 1100 | +/*! | ||
| 1101 | + * \brief A br::Transform for which the results of project may change due to prior calls to project | ||
| 1102 | + */ | ||
| 1103 | +class BR_EXPORT TimeVaryingTransform : public Transform | ||
| 1104 | +{ | ||
| 1105 | + Q_OBJECT | ||
| 1106 | + | ||
| 1107 | + virtual bool timeVarying() const {return true;} | ||
| 1108 | + virtual void project(const Template &src, Template &dst) const | ||
| 1109 | + { | ||
| 1110 | + qFatal("No const project defined for time-varying transform"); | ||
| 1111 | + // shut up unused param warning? probably a better way to handle this | ||
| 1112 | + dst = src; | ||
| 1113 | + } | ||
| 1114 | + virtual void project(const TemplateList &src, TemplateList &dst) const | ||
| 1115 | + { | ||
| 1116 | + qFatal("No const project defined for time-varying transform"); | ||
| 1117 | + dst = src; | ||
| 1118 | + } | ||
| 1119 | + | ||
| 1120 | + | ||
| 1121 | +protected: | ||
| 1122 | + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {} | ||
| 1123 | +}; | ||
| 1124 | + | ||
| 1125 | + | ||
| 1054 | /*! | 1126 | /*! |
| 1055 | * \brief A br::Transform expecting multiple matrices per template. | 1127 | * \brief A br::Transform expecting multiple matrices per template. |
| 1056 | */ | 1128 | */ |
| @@ -1063,6 +1135,137 @@ protected: | @@ -1063,6 +1135,137 @@ protected: | ||
| 1063 | }; | 1135 | }; |
| 1064 | 1136 | ||
| 1065 | /*! | 1137 | /*! |
| 1138 | + * \brief A MetaTransform that aggregates some sub-transforms | ||
| 1139 | + */ | ||
| 1140 | +class BR_EXPORT CompositeTransform : public TimeVaryingTransform | ||
| 1141 | +{ | ||
| 1142 | + Q_OBJECT | ||
| 1143 | +public: | ||
| 1144 | + Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 1145 | + BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 1146 | + | ||
| 1147 | + virtual void train(const TemplateList &data); | ||
| 1148 | + | ||
| 1149 | + virtual void project(const Template &src, Template &dst) const | ||
| 1150 | + { | ||
| 1151 | + if (timeVarying()) qFatal("No const project defined for time-varying transform"); | ||
| 1152 | + _project(src, dst); | ||
| 1153 | + } | ||
| 1154 | + | ||
| 1155 | + virtual void project(const TemplateList &src, TemplateList &dst) const | ||
| 1156 | + { | ||
| 1157 | + if (timeVarying()) qFatal("No const project defined for time-varying transform"); | ||
| 1158 | + _project(src, dst); | ||
| 1159 | + } | ||
| 1160 | + | ||
| 1161 | + void backProject(const Template &dst, Template &src) const | ||
| 1162 | + { | ||
| 1163 | + // Backprojecting a time-varying transform is probably not going to work. | ||
| 1164 | + if (timeVarying()) qFatal("No backProject defined for time-varying transform"); | ||
| 1165 | + | ||
| 1166 | + src = dst; | ||
| 1167 | + // Reverse order in which transforms are processed | ||
| 1168 | + int length = transforms.length(); | ||
| 1169 | + for (int i=length-1; i>=0; i--) { | ||
| 1170 | + Transform *f = transforms.at(i); | ||
| 1171 | + try { | ||
| 1172 | + src >> *f; | ||
| 1173 | + } catch (...) { | ||
| 1174 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(dst.file.flat()), qPrintable(f->objectName())); | ||
| 1175 | + src = Template(src.file); | ||
| 1176 | + src.file.setBool("FTE"); | ||
| 1177 | + } | ||
| 1178 | + } | ||
| 1179 | + } | ||
| 1180 | + | ||
| 1181 | + void projectUpdate(const Template &src, Template &dst) | ||
| 1182 | + { | ||
| 1183 | + dst = src; | ||
| 1184 | + foreach (Transform *f, transforms) { | ||
| 1185 | + try { | ||
| 1186 | + f->projectUpdate(dst); | ||
| 1187 | + } catch (...) { | ||
| 1188 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 1189 | + dst = Template(src.file); | ||
| 1190 | + dst.file.setBool("FTE"); | ||
| 1191 | + } | ||
| 1192 | + } | ||
| 1193 | + } | ||
| 1194 | + | ||
| 1195 | + // For time varying transforms, parallel execution over individual templates | ||
| 1196 | + // won't work. | ||
| 1197 | + void projectUpdate(const TemplateList & src, TemplateList & dst) | ||
| 1198 | + { | ||
| 1199 | + dst = src; | ||
| 1200 | + foreach (Transform *f, transforms) | ||
| 1201 | + { | ||
| 1202 | + f->projectUpdate(dst); | ||
| 1203 | + } | ||
| 1204 | + } | ||
| 1205 | + | ||
| 1206 | + bool timeVarying() const | ||
| 1207 | + { | ||
| 1208 | + return time_varying; | ||
| 1209 | + } | ||
| 1210 | + | ||
| 1211 | + void init() | ||
| 1212 | + { | ||
| 1213 | + time_varying = false; | ||
| 1214 | + foreach(const br::Transform * transform, transforms) | ||
| 1215 | + { | ||
| 1216 | + if (transform->timeVarying()) { | ||
| 1217 | + time_varying = true; | ||
| 1218 | + break; | ||
| 1219 | + } | ||
| 1220 | + } | ||
| 1221 | + } | ||
| 1222 | + | ||
| 1223 | + virtual void finalize(TemplateList & output) | ||
| 1224 | + { | ||
| 1225 | + output.clear(); | ||
| 1226 | + // For each transform, | ||
| 1227 | + for (int i = 0; i < transforms.size(); i++) | ||
| 1228 | + { | ||
| 1229 | + | ||
| 1230 | + // Collect any final templates | ||
| 1231 | + TemplateList last_set; | ||
| 1232 | + transforms[i]->finalize(last_set); | ||
| 1233 | + if (last_set.empty()) | ||
| 1234 | + continue; | ||
| 1235 | + // Push any templates received through the remaining transforms in the sequence | ||
| 1236 | + for (int j = (i+1); j < transforms.size();j++) | ||
| 1237 | + { | ||
| 1238 | + transforms[j]->projectUpdate(last_set); | ||
| 1239 | + } | ||
| 1240 | + // append the result to the output set | ||
| 1241 | + output.append(last_set); | ||
| 1242 | + } | ||
| 1243 | + } | ||
| 1244 | + | ||
| 1245 | +protected: | ||
| 1246 | + bool time_varying; | ||
| 1247 | + // Single template const project, default implementation for aggregate transforms--pass the template through each | ||
| 1248 | + // sub-transform, one after the other | ||
| 1249 | + virtual void _project(const Template & src, Template & dst) const | ||
| 1250 | + { | ||
| 1251 | + dst = src; | ||
| 1252 | + foreach (const Transform *f, transforms) { | ||
| 1253 | + try { | ||
| 1254 | + dst >> *f; | ||
| 1255 | + } catch (...) { | ||
| 1256 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 1257 | + dst = Template(src.file); | ||
| 1258 | + dst.file.setBool("FTE"); | ||
| 1259 | + } | ||
| 1260 | + } | ||
| 1261 | + } | ||
| 1262 | + virtual void _project(const TemplateList & src, TemplateList & dst) const = 0; | ||
| 1263 | + | ||
| 1264 | + CompositeTransform() : TimeVaryingTransform(false) {} | ||
| 1265 | +}; | ||
| 1266 | + | ||
| 1267 | + | ||
| 1268 | +/*! | ||
| 1066 | * \brief A br::Transform that does not require training data. | 1269 | * \brief A br::Transform that does not require training data. |
| 1067 | */ | 1270 | */ |
| 1068 | class BR_EXPORT UntrainableTransform : public Transform | 1271 | class BR_EXPORT UntrainableTransform : public Transform |
sdk/plugins/meta.cpp
| @@ -85,6 +85,21 @@ static void incrementStep() | @@ -85,6 +85,21 @@ static void incrementStep() | ||
| 85 | Globals->currentStep += 1.0 / pow(10.0, double(depth)); | 85 | Globals->currentStep += 1.0 / pow(10.0, double(depth)); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | +// CompositeTransform::train placed here to pick up acquireStep and incrementStep | ||
| 89 | +void CompositeTransform::train(const TemplateList &data) | ||
| 90 | +{ | ||
| 91 | + acquireStep(); | ||
| 92 | + | ||
| 93 | + TemplateList copy(data); | ||
| 94 | + for (int i=0; i<transforms.size(); i++) { | ||
| 95 | + transforms[i]->train(copy); | ||
| 96 | + copy >> *transforms[i]; | ||
| 97 | + incrementStep(); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + releaseStep(); | ||
| 101 | +} | ||
| 102 | + | ||
| 88 | /*! | 103 | /*! |
| 89 | * \ingroup Transforms | 104 | * \ingroup Transforms |
| 90 | * \brief Transforms in series. | 105 | * \brief Transforms in series. |
| @@ -95,41 +110,15 @@ static void incrementStep() | @@ -95,41 +110,15 @@ static void incrementStep() | ||
| 95 | * \see ExpandTransform | 110 | * \see ExpandTransform |
| 96 | * \see ForkTransform | 111 | * \see ForkTransform |
| 97 | */ | 112 | */ |
| 98 | -class PipeTransform : public MetaTransform | 113 | +class PipeTransform : public CompositeTransform |
| 99 | { | 114 | { |
| 100 | Q_OBJECT | 115 | Q_OBJECT |
| 101 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 102 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 103 | 116 | ||
| 104 | - void train(const TemplateList &data) | ||
| 105 | - { | ||
| 106 | - acquireStep(); | ||
| 107 | 117 | ||
| 108 | - TemplateList copy(data); | ||
| 109 | - for (int i=0; i<transforms.size(); i++) { | ||
| 110 | - transforms[i]->train(copy); | ||
| 111 | - copy >> *transforms[i]; | ||
| 112 | - incrementStep(); | ||
| 113 | - } | ||
| 114 | - | ||
| 115 | - releaseStep(); | ||
| 116 | - } | ||
| 117 | - | ||
| 118 | - void project(const Template &src, Template &dst) const | ||
| 119 | - { | ||
| 120 | - dst = src; | ||
| 121 | - foreach (const Transform *f, transforms) { | ||
| 122 | - try { | ||
| 123 | - dst >> *f; | ||
| 124 | - } catch (...) { | ||
| 125 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 126 | - dst = Template(src.file); | ||
| 127 | - dst.file.setBool("FTE"); | ||
| 128 | - } | ||
| 129 | - } | ||
| 130 | - } | ||
| 131 | - | ||
| 132 | - void project(const TemplateList &src, TemplateList &dst) const | 118 | +protected: |
| 119 | + // Template list project -- process templates in parallel through Transform::project | ||
| 120 | + // or if parallelism is disabled, handle them sequentially | ||
| 121 | + void _project(const TemplateList &src, TemplateList &dst) const | ||
| 133 | { | 122 | { |
| 134 | if (Globals->parallelism < 0) { | 123 | if (Globals->parallelism < 0) { |
| 135 | dst = src; | 124 | dst = src; |
| @@ -139,23 +128,6 @@ class PipeTransform : public MetaTransform | @@ -139,23 +128,6 @@ class PipeTransform : public MetaTransform | ||
| 139 | Transform::project(src, dst); | 128 | Transform::project(src, dst); |
| 140 | } | 129 | } |
| 141 | } | 130 | } |
| 142 | - | ||
| 143 | - void backProject(const Template &dst, Template &src) const | ||
| 144 | - { | ||
| 145 | - src = dst; | ||
| 146 | - // Reverse order in which transforms are processed | ||
| 147 | - int length = transforms.length(); | ||
| 148 | - for (int i=length-1; i>=0; i--) { | ||
| 149 | - Transform *f = transforms.at(i); | ||
| 150 | - try { | ||
| 151 | - src >> *f; | ||
| 152 | - } catch (...) { | ||
| 153 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(dst.file.flat()), qPrintable(f->objectName())); | ||
| 154 | - src = Template(src.file); | ||
| 155 | - src.file.setBool("FTE"); | ||
| 156 | - } | ||
| 157 | - } | ||
| 158 | - } | ||
| 159 | }; | 131 | }; |
| 160 | 132 | ||
| 161 | BR_REGISTER(Transform, PipeTransform) | 133 | BR_REGISTER(Transform, PipeTransform) |
| @@ -170,11 +142,9 @@ BR_REGISTER(Transform, PipeTransform) | @@ -170,11 +142,9 @@ BR_REGISTER(Transform, PipeTransform) | ||
| 170 | * | 142 | * |
| 171 | * \see PipeTransform | 143 | * \see PipeTransform |
| 172 | */ | 144 | */ |
| 173 | -class ExpandTransform : public MetaTransform | 145 | +class ExpandTransform : public CompositeTransform |
| 174 | { | 146 | { |
| 175 | Q_OBJECT | 147 | Q_OBJECT |
| 176 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 177 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 178 | 148 | ||
| 179 | void train(const TemplateList &data) | 149 | void train(const TemplateList &data) |
| 180 | { | 150 | { |
| @@ -191,21 +161,47 @@ class ExpandTransform : public MetaTransform | @@ -191,21 +161,47 @@ class ExpandTransform : public MetaTransform | ||
| 191 | releaseStep(); | 161 | releaseStep(); |
| 192 | } | 162 | } |
| 193 | 163 | ||
| 194 | - void project(const Template &src, Template &dst) const | 164 | + // same as _project, but calling projectUpdate on sub-transforms instead of using |
| 165 | + // operator>> | ||
| 166 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | ||
| 195 | { | 167 | { |
| 196 | dst = src; | 168 | dst = src; |
| 197 | - foreach (const Transform *f, transforms) { | ||
| 198 | - try { | ||
| 199 | - dst >> *f; | ||
| 200 | - } catch (...) { | ||
| 201 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 202 | - dst = Template(src.file); | ||
| 203 | - dst.file.setBool("FTE"); | 169 | + for (int i=0; i<transforms.size(); i++) { |
| 170 | + transforms[i]->projectUpdate(dst); | ||
| 171 | + dst = Expanded(dst); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + virtual void finalize(TemplateList & output) | ||
| 176 | + { | ||
| 177 | + output.clear(); | ||
| 178 | + // For each transform, | ||
| 179 | + for (int i = 0; i < transforms.size(); i++) | ||
| 180 | + { | ||
| 181 | + | ||
| 182 | + // Collect any final templates | ||
| 183 | + TemplateList last_set; | ||
| 184 | + transforms[i]->finalize(last_set); | ||
| 185 | + last_set = Expanded(last_set); | ||
| 186 | + if (last_set.empty()) | ||
| 187 | + continue; | ||
| 188 | + // Push any templates received through the remaining transforms in the sequence | ||
| 189 | + for (int j = (i+1); j < transforms.size();j++) | ||
| 190 | + { | ||
| 191 | + transforms[j]->projectUpdate(last_set); | ||
| 192 | + last_set = Expanded(last_set); | ||
| 204 | } | 193 | } |
| 194 | + // append the result to the output set | ||
| 195 | + output.append(last_set); | ||
| 205 | } | 196 | } |
| 206 | } | 197 | } |
| 207 | 198 | ||
| 208 | - void project(const TemplateList &src, TemplateList &dst) const | 199 | +protected: |
| 200 | + | ||
| 201 | + // Template list project -- project through transforms sequentially, | ||
| 202 | + // then expand the results, can't use Transform::Project(templateList) since | ||
| 203 | + // we need to expand between tranforms | ||
| 204 | + void _project(const TemplateList &src, TemplateList &dst) const | ||
| 209 | { | 205 | { |
| 210 | dst = src; | 206 | dst = src; |
| 211 | for (int i=0; i<transforms.size(); i++) { | 207 | for (int i=0; i<transforms.size(); i++) { |
| @@ -213,23 +209,6 @@ class ExpandTransform : public MetaTransform | @@ -213,23 +209,6 @@ class ExpandTransform : public MetaTransform | ||
| 213 | dst = Expanded(dst); | 209 | dst = Expanded(dst); |
| 214 | } | 210 | } |
| 215 | } | 211 | } |
| 216 | - | ||
| 217 | - void backProject(const Template &dst, Template &src) const | ||
| 218 | - { | ||
| 219 | - src = dst; | ||
| 220 | - // Reverse order in which transforms are processed | ||
| 221 | - int length = transforms.length(); | ||
| 222 | - for (int i=length-1; i>=0; i--) { | ||
| 223 | - Transform *f = transforms.at(i); | ||
| 224 | - try { | ||
| 225 | - src >> *f; | ||
| 226 | - } catch (...) { | ||
| 227 | - qWarning("Exception triggered when processing %s with transform %s", qPrintable(dst.file.flat()), qPrintable(f->objectName())); | ||
| 228 | - src = Template(src.file); | ||
| 229 | - src.file.setBool("FTE"); | ||
| 230 | - } | ||
| 231 | - } | ||
| 232 | - } | ||
| 233 | }; | 212 | }; |
| 234 | 213 | ||
| 235 | BR_REGISTER(Transform, ExpandTransform) | 214 | BR_REGISTER(Transform, ExpandTransform) |
| @@ -243,11 +222,9 @@ BR_REGISTER(Transform, ExpandTransform) | @@ -243,11 +222,9 @@ BR_REGISTER(Transform, ExpandTransform) | ||
| 243 | * | 222 | * |
| 244 | * \see PipeTransform | 223 | * \see PipeTransform |
| 245 | */ | 224 | */ |
| 246 | -class ForkTransform : public MetaTransform | 225 | +class ForkTransform : public CompositeTransform |
| 247 | { | 226 | { |
| 248 | Q_OBJECT | 227 | Q_OBJECT |
| 249 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms) | ||
| 250 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 251 | 228 | ||
| 252 | void train(const TemplateList &data) | 229 | void train(const TemplateList &data) |
| 253 | { | 230 | { |
| @@ -259,8 +236,58 @@ class ForkTransform : public MetaTransform | @@ -259,8 +236,58 @@ class ForkTransform : public MetaTransform | ||
| 259 | } | 236 | } |
| 260 | if (threaded) Globals->trackFutures(futures); | 237 | if (threaded) Globals->trackFutures(futures); |
| 261 | } | 238 | } |
| 239 | + // The implementation of backProject in aggregate transform probably doesn't do anything useful here. | ||
| 240 | + void backProject(const Template &dst, Template &src) const {Transform::backProject(dst, src);} | ||
| 262 | 241 | ||
| 263 | - void project(const Template &src, Template &dst) const | 242 | + // same as _project, but calls projectUpdate on sub-transforms |
| 243 | + void projectupdate(const Template & src, Template & dst) | ||
| 244 | + { | ||
| 245 | + foreach (Transform *f, transforms) { | ||
| 246 | + try { | ||
| 247 | + Template res; | ||
| 248 | + f->projectUpdate(src, res); | ||
| 249 | + dst.merge(res); | ||
| 250 | + } catch (...) { | ||
| 251 | + qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName())); | ||
| 252 | + dst = Template(src.file); | ||
| 253 | + dst.file.setBool("FTE"); | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + | ||
| 259 | + // this is probably going to go bad, fork transform probably won't work well in a variable | ||
| 260 | + // input/output scenario | ||
| 261 | + virtual void finalize(TemplateList & output) | ||
| 262 | + { | ||
| 263 | + output.clear(); | ||
| 264 | + // For each transform, | ||
| 265 | + for (int i = 0; i < transforms.size(); i++) | ||
| 266 | + { | ||
| 267 | + // Collect any final templates | ||
| 268 | + TemplateList last_set; | ||
| 269 | + transforms[i]->finalize(last_set); | ||
| 270 | + if (last_set.empty()) | ||
| 271 | + continue; | ||
| 272 | + | ||
| 273 | + if (output.empty()) output = last_set; | ||
| 274 | + else | ||
| 275 | + { | ||
| 276 | + // is the number of templates received from this transform consistent with the number | ||
| 277 | + // received previously? If not we can't do anything coherent here. | ||
| 278 | + if (last_set.size() != output.size()) | ||
| 279 | + qFatal("mismatched template list sizes in ForkTransform"); | ||
| 280 | + for (int j = 0; j < output.size(); j++) { | ||
| 281 | + output[j].append(last_set[j]); | ||
| 282 | + } | ||
| 283 | + } | ||
| 284 | + } | ||
| 285 | + } | ||
| 286 | + | ||
| 287 | +protected: | ||
| 288 | + | ||
| 289 | + // Apply each transform to src, concatenate the results | ||
| 290 | + void _project(const Template &src, Template &dst) const | ||
| 264 | { | 291 | { |
| 265 | foreach (const Transform *f, transforms) { | 292 | foreach (const Transform *f, transforms) { |
| 266 | try { | 293 | try { |
| @@ -273,7 +300,7 @@ class ForkTransform : public MetaTransform | @@ -273,7 +300,7 @@ class ForkTransform : public MetaTransform | ||
| 273 | } | 300 | } |
| 274 | } | 301 | } |
| 275 | 302 | ||
| 276 | - void project(const TemplateList &src, TemplateList &dst) const | 303 | + void _project(const TemplateList &src, TemplateList &dst) const |
| 277 | { | 304 | { |
| 278 | if (Globals->parallelism < 0) { | 305 | if (Globals->parallelism < 0) { |
| 279 | dst.reserve(src.size()); | 306 | dst.reserve(src.size()); |
| @@ -288,6 +315,20 @@ class ForkTransform : public MetaTransform | @@ -288,6 +315,20 @@ class ForkTransform : public MetaTransform | ||
| 288 | Transform::project(src, dst); | 315 | Transform::project(src, dst); |
| 289 | } | 316 | } |
| 290 | } | 317 | } |
| 318 | + | ||
| 319 | + void projectUpdate(const TemplateList & src, TemplateList & dst) | ||
| 320 | + { | ||
| 321 | + dst = src; | ||
| 322 | + dst.reserve(src.size()); | ||
| 323 | + for (int i=0; i<src.size(); i++) dst.append(Template()); | ||
| 324 | + foreach (Transform *f, transforms) { | ||
| 325 | + TemplateList m; | ||
| 326 | + f->projectUpdate(src, m); | ||
| 327 | + if (m.size() != dst.size()) qFatal("TemplateList is of an unexpected size."); | ||
| 328 | + for (int i=0; i<src.size(); i++) dst[i].append(m[i]); | ||
| 329 | + } | ||
| 330 | + } | ||
| 331 | + | ||
| 291 | }; | 332 | }; |
| 292 | 333 | ||
| 293 | BR_REGISTER(Transform, ForkTransform) | 334 | BR_REGISTER(Transform, ForkTransform) |
sdk/plugins/random.cpp
| @@ -30,11 +30,9 @@ namespace br | @@ -30,11 +30,9 @@ namespace br | ||
| 30 | * \brief Selects a random transform. | 30 | * \brief Selects a random transform. |
| 31 | * \author Josh Klontz \cite jklontz | 31 | * \author Josh Klontz \cite jklontz |
| 32 | */ | 32 | */ |
| 33 | -class RndTransformTransform : public Transform | 33 | +class RndTransformTransform : public CompositeTransform |
| 34 | { | 34 | { |
| 35 | Q_OBJECT | 35 | Q_OBJECT |
| 36 | - Q_PROPERTY(QList<br::Transform*> transforms READ get_transforms WRITE set_transforms RESET reset_transforms STORED false) | ||
| 37 | - BR_PROPERTY(QList<br::Transform*>, transforms, QList<br::Transform*>()) | ||
| 38 | 36 | ||
| 39 | int selectedIndex; | 37 | int selectedIndex; |
| 40 | Transform *selectedTransform; | 38 | Transform *selectedTransform; |
| @@ -46,11 +44,37 @@ class RndTransformTransform : public Transform | @@ -46,11 +44,37 @@ class RndTransformTransform : public Transform | ||
| 46 | selectedTransform->train(data); | 44 | selectedTransform->train(data); |
| 47 | } | 45 | } |
| 48 | 46 | ||
| 49 | - void project(const Template &src, Template &dst) const | 47 | + bool timeVarying() const |
| 48 | + { | ||
| 49 | + // calling on selectedTransform assumes train has already been called. -cao | ||
| 50 | + return selectedTransform->timeVarying(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + void _project(const Template &src, Template &dst) const | ||
| 50 | { | 54 | { |
| 51 | selectedTransform->project(src, dst); | 55 | selectedTransform->project(src, dst); |
| 52 | } | 56 | } |
| 53 | 57 | ||
| 58 | + void _project(const TemplateList &src, TemplateList &dst) const | ||
| 59 | + { | ||
| 60 | + Transform::project(src, dst); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + void projectUpdate(const Template &src, Template &dst) | ||
| 64 | + { | ||
| 65 | + selectedTransform->projectUpdate(src,dst); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + void projectUpdate(const TemplateList & src, TemplateList & dst) | ||
| 69 | + { | ||
| 70 | + selectedTransform->projectUpdate(src, dst); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + void finalize(TemplateList & output) | ||
| 74 | + { | ||
| 75 | + selectedTransform->finalize(output); | ||
| 76 | + } | ||
| 77 | + | ||
| 54 | void store(QDataStream &stream) const | 78 | void store(QDataStream &stream) const |
| 55 | { | 79 | { |
| 56 | stream << selectedIndex << *selectedTransform; | 80 | stream << selectedIndex << *selectedTransform; |