Commit 8f3fa09b8f029a6a9490c7bd5cf421882054eb12

Authored by Josh Klontz
1 parent 9a77f8f5

refactored out independent transform to its own file

openbr/openbr_plugin.cpp
... ... @@ -679,12 +679,17 @@ void Object::setProperty(const QString &name, const QString &value)
679 679 variant = value;
680 680 }
681 681  
682   - if (!QObject::setProperty(qPrintable(name), variant) && !type.isEmpty())
683   - qFatal("Failed to set %s::%s to: %s %s",
684   - metaObject()->className(), qPrintable(name), qPrintable(value), qPrintable(type));
  682 + setProperty(name, variant, !type.isEmpty());
685 683 }
686 684  
687   -QStringList br::Object::parse(const QString &string, char split)
  685 +void Object::setProperty(const QString &name, const QVariant &value, bool failOnError)
  686 +{
  687 + if (!QObject::setProperty(qPrintable(name), value) && failOnError)
  688 + qFatal("Failed to set %s::%s to: %s",
  689 + metaObject()->className(), qPrintable(name), qPrintable(value.toString()));
  690 +}
  691 +
  692 +QStringList Object::parse(const QString &string, char split)
688 693 {
689 694 return QtUtils::parse(string, split);
690 695 }
... ... @@ -736,19 +741,21 @@ void Object::init(const File &file_)
736 741 }
737 742  
738 743 foreach (QString key, file.localKeys()) {
739   - const QString value = file.value(key).toString();
  744 + const QVariant value = file.value(key);
  745 + const QString valueString = value.toString();
740 746  
741 747 if (key.startsWith(("_Arg"))) {
742   - int argument_number = key.mid(4).toInt();
743   - int target_idx = argument_number + firstAvailablePropertyIdx;
744   -
745   - if (target_idx >= metaObject()->propertyCount()) {
746   - qWarning("too many arguments for transform, ignoring %s\n", qPrintable(value));
  748 + int argumentNumber = key.mid(4).toInt();
  749 + int targetIdx = argumentNumber + firstAvailablePropertyIdx;
  750 + if (targetIdx >= metaObject()->propertyCount()) {
  751 + qWarning("too many arguments for transform %s, ignoring %s", qPrintable(objectName()), qPrintable(valueString));
747 752 continue;
748 753 }
749   - key = metaObject()->property(target_idx).name();
  754 + key = metaObject()->property(targetIdx).name();
750 755 }
751   - setProperty(key, value);
  756 +
  757 + if (valueString.isEmpty()) setProperty(key, value); // Set the property directly
  758 + else setProperty(key, valueString); // Parse the value first
752 759 }
753 760  
754 761 init();
... ... @@ -1083,153 +1090,6 @@ Gallery *Gallery::make(const File &file)
1083 1090 return gallery;
1084 1091 }
1085 1092  
1086   -static TemplateList Downsample(const TemplateList &templates, const Transform *transform)
1087   -{
1088   - // Return early when no downsampling is required
1089   - if ((transform->classes == std::numeric_limits<int>::max()) &&
1090   - (transform->instances == std::numeric_limits<int>::max()) &&
1091   - (transform->fraction >= 1))
1092   - return templates;
1093   -
1094   - const bool atLeast = transform->instances < 0;
1095   - const int instances = abs(transform->instances);
1096   -
1097   - QList<int> allLabels = templates.labels<int>();
1098   - QList<int> uniqueLabels = allLabels.toSet().toList();
1099   - qSort(uniqueLabels);
1100   -
1101   - QMap<int,int> counts = templates.labelCounts(instances != std::numeric_limits<int>::max());
1102   - if ((instances != std::numeric_limits<int>::max()) && (transform->classes != std::numeric_limits<int>::max()))
1103   - foreach (int label, counts.keys())
1104   - if (counts[label] < instances)
1105   - counts.remove(label);
1106   - uniqueLabels = counts.keys();
1107   - if ((transform->classes != std::numeric_limits<int>::max()) && (uniqueLabels.size() < transform->classes))
1108   - qWarning("Downsample requested %d classes but only %d are available.", transform->classes, uniqueLabels.size());
1109   -
1110   - Common::seedRNG();
1111   - QList<int> selectedLabels = uniqueLabels;
1112   - if (transform->classes < uniqueLabels.size()) {
1113   - std::random_shuffle(selectedLabels.begin(), selectedLabels.end());
1114   - selectedLabels = selectedLabels.mid(0, transform->classes);
1115   - }
1116   -
1117   - TemplateList downsample;
1118   - for (int i=0; i<selectedLabels.size(); i++) {
1119   - const int selectedLabel = selectedLabels[i];
1120   - QList<int> indices;
1121   - for (int j=0; j<allLabels.size(); j++)
1122   - if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.get<bool>("FTE", false)))
1123   - indices.append(j);
1124   -
1125   - std::random_shuffle(indices.begin(), indices.end());
1126   - const int max = atLeast ? indices.size() : std::min(indices.size(), instances);
1127   - for (int j=0; j<max; j++)
1128   - downsample.append(templates.value(indices[j]));
1129   - }
1130   -
1131   - if (transform->fraction < 1) {
1132   - std::random_shuffle(downsample.begin(), downsample.end());
1133   - downsample = downsample.mid(0, downsample.size()*transform->fraction);
1134   - }
1135   -
1136   - return downsample;
1137   -}
1138   -
1139   -/*!
1140   - * \ingroup transforms
1141   - * \brief Clones the transform so that it can be applied independently.
1142   - *
1143   - * \em Independent transforms expect single-matrix templates.
1144   - */
1145   -class Independent : public MetaTransform
1146   -{
1147   - Q_PROPERTY(QList<Transform*> transforms READ get_transforms WRITE set_transforms STORED false)
1148   - BR_PROPERTY(QList<Transform*>, transforms, QList<Transform*>())
1149   -
1150   - public:
1151   - /*!
1152   - * \brief Independent
1153   - * \param transform
1154   - */
1155   - Independent(Transform *transform)
1156   - {
1157   - transform->setParent(this);
1158   - transforms.append(transform);
1159   - file = transform->file;
1160   - trainable = transform->trainable;
1161   - setObjectName(transforms.first()->objectName());
1162   - }
1163   -
1164   -private:
1165   - Transform *clone() const
1166   - {
1167   - return new Independent(transforms.first()->clone());
1168   - }
1169   -
1170   - static void _train(Transform *transform, const TemplateList *data)
1171   - {
1172   - transform->train(*data);
1173   - }
1174   -
1175   - void train(const TemplateList &data)
1176   - {
1177   - // Don't bother if the transform is untrainable
1178   - if (!trainable) return;
1179   -
1180   - QList<TemplateList> templatesList;
1181   - foreach (const Template &t, data) {
1182   - if ((templatesList.size() != t.size()) && !templatesList.isEmpty())
1183   - qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable(t.file.name), t.size(), templatesList.size());
1184   - while (templatesList.size() < t.size())
1185   - templatesList.append(TemplateList());
1186   - for (int i=0; i<t.size(); i++)
1187   - templatesList[i].append(Template(t.file, t[i]));
1188   - }
1189   -
1190   - while (transforms.size() < templatesList.size())
1191   - transforms.append(transforms.first()->clone());
1192   -
1193   - for (int i=0; i<templatesList.size(); i++)
1194   - templatesList[i] = Downsample(templatesList[i], transforms[i]);
1195   -
1196   - QFutureSynchronizer<void> futures;
1197   - for (int i=0; i<templatesList.size(); i++)
1198   - futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i]));
1199   - futures.waitForFinished();
1200   - }
1201   -
1202   - void project(const Template &src, Template &dst) const
1203   - {
1204   - dst.file = src.file;
1205   - QList<Mat> mats;
1206   - for (int i=0; i<src.size(); i++) {
1207   - transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst);
1208   - mats.append(dst);
1209   - dst.clear();
1210   - }
1211   - dst.append(mats);
1212   - }
1213   -
1214   - void store(QDataStream &stream) const
1215   - {
1216   - const int size = transforms.size();
1217   - stream << size;
1218   - for (int i=0; i<size; i++)
1219   - transforms[i]->store(stream);
1220   - }
1221   -
1222   - void load(QDataStream &stream)
1223   - {
1224   - int size;
1225   - stream >> size;
1226   - while (transforms.size() < size)
1227   - transforms.append(transforms.first()->clone());
1228   - for (int i=0; i<size; i++)
1229   - transforms[i]->load(stream);
1230   - }
1231   -};
1232   -
1233 1093 /* Transform - public methods */
1234 1094 Transform::Transform(bool _independent, bool _trainable)
1235 1095 {
... ... @@ -1277,8 +1137,17 @@ Transform *Transform::make(QString str, QObject *parent)
1277 1137 File f = "." + str;
1278 1138 Transform *transform = Factory<Transform>::make(f);
1279 1139  
1280   - if (transform->independent)
1281   - transform = new Independent(transform);
  1140 + if (transform->independent) {
  1141 +// Transform *independentTransform = Factory<Transform>::make(".Independent");
  1142 +// static_cast<QObject*>(independentTransform)->setProperty("transform", qVariantFromValue<void*>(transform));
  1143 +// independentTransform->init();
  1144 +// transform = independentTransform;
  1145 +
  1146 + File independent(".Independent");
  1147 + independent.set("transform", qVariantFromValue<void*>(transform));
  1148 + transform = Factory<Transform>::make(independent);
  1149 + }
  1150 +
1282 1151 transform->setParent(parent);
1283 1152 return transform;
1284 1153 }
... ...
openbr/openbr_plugin.h
... ... @@ -497,6 +497,7 @@ public:
497 497 QString argument(int index) const; /*!< \brief A string value for the argument at the specified index. */
498 498 QString description() const; /*!< \brief Returns a string description of the object. */
499 499 void setProperty(const QString &name, const QString &value); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */
  500 + void setProperty(const QString &name, const QVariant &value, bool failOnError = false); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */
500 501 static QStringList parse(const QString &string, char split = ','); /*!< \brief Splits the string while respecting lexical scoping of <tt>()</tt>, <tt>[]</tt>, <tt>\<\></tt>, and <tt>{}</tt>. */
501 502  
502 503 private:
... ...
openbr/plugins/independent.cpp 0 โ†’ 100644
  1 +#include <QFutureSynchronizer>
  2 +#include <QtConcurrentRun>
  3 +
  4 +#include "openbr_internal.h"
  5 +#include "openbr/core/common.h"
  6 +
  7 +using namespace cv;
  8 +
  9 +namespace br
  10 +{
  11 +
  12 +static TemplateList Downsample(const TemplateList &templates, const Transform *transform)
  13 +{
  14 + // Return early when no downsampling is required
  15 + if ((transform->classes == std::numeric_limits<int>::max()) &&
  16 + (transform->instances == std::numeric_limits<int>::max()) &&
  17 + (transform->fraction >= 1))
  18 + return templates;
  19 +
  20 + const bool atLeast = transform->instances < 0;
  21 + const int instances = abs(transform->instances);
  22 +
  23 + QList<int> allLabels = templates.labels<int>();
  24 + QList<int> uniqueLabels = allLabels.toSet().toList();
  25 + qSort(uniqueLabels);
  26 +
  27 + QMap<int,int> counts = templates.labelCounts(instances != std::numeric_limits<int>::max());
  28 + if ((instances != std::numeric_limits<int>::max()) && (transform->classes != std::numeric_limits<int>::max()))
  29 + foreach (int label, counts.keys())
  30 + if (counts[label] < instances)
  31 + counts.remove(label);
  32 + uniqueLabels = counts.keys();
  33 + if ((transform->classes != std::numeric_limits<int>::max()) && (uniqueLabels.size() < transform->classes))
  34 + qWarning("Downsample requested %d classes but only %d are available.", transform->classes, uniqueLabels.size());
  35 +
  36 + Common::seedRNG();
  37 + QList<int> selectedLabels = uniqueLabels;
  38 + if (transform->classes < uniqueLabels.size()) {
  39 + std::random_shuffle(selectedLabels.begin(), selectedLabels.end());
  40 + selectedLabels = selectedLabels.mid(0, transform->classes);
  41 + }
  42 +
  43 + TemplateList downsample;
  44 + for (int i=0; i<selectedLabels.size(); i++) {
  45 + const int selectedLabel = selectedLabels[i];
  46 + QList<int> indices;
  47 + for (int j=0; j<allLabels.size(); j++)
  48 + if ((allLabels[j] == selectedLabel) && (!templates.value(j).file.get<bool>("FTE", false)))
  49 + indices.append(j);
  50 +
  51 + std::random_shuffle(indices.begin(), indices.end());
  52 + const int max = atLeast ? indices.size() : std::min(indices.size(), instances);
  53 + for (int j=0; j<max; j++)
  54 + downsample.append(templates.value(indices[j]));
  55 + }
  56 +
  57 + if (transform->fraction < 1) {
  58 + std::random_shuffle(downsample.begin(), downsample.end());
  59 + downsample = downsample.mid(0, downsample.size()*transform->fraction);
  60 + }
  61 +
  62 + return downsample;
  63 +}
  64 +
  65 +/*!
  66 + * \ingroup transforms
  67 + * \brief Clones the transform so that it can be applied independently.
  68 + * \author Josh Klontz \cite jklontz
  69 + * \em Independent transforms expect single-matrix templates.
  70 + */
  71 +class IndependentTransform : public MetaTransform
  72 +{
  73 + Q_OBJECT
  74 + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform STORED false)
  75 + BR_PROPERTY(br::Transform*, transform, NULL)
  76 +
  77 + QList<Transform*> transforms;
  78 +
  79 + void init()
  80 + {
  81 + transforms.clear();
  82 + if (transform == NULL)
  83 + return;
  84 +
  85 + transform->setParent(this);
  86 + transforms.append(transform);
  87 + file = transform->file;
  88 + trainable = transform->trainable;
  89 + setObjectName(transform->objectName());
  90 + }
  91 +
  92 + Transform *clone() const
  93 + {
  94 + IndependentTransform *independentTransform = new IndependentTransform();
  95 + independentTransform->transform = transform->clone();
  96 + independentTransform->init();
  97 + return independentTransform;
  98 + }
  99 +
  100 + static void _train(Transform *transform, const TemplateList *data)
  101 + {
  102 + transform->train(*data);
  103 + }
  104 +
  105 + void train(const TemplateList &data)
  106 + {
  107 + // Don't bother if the transform is untrainable
  108 + if (!trainable) return;
  109 +
  110 + QList<TemplateList> templatesList;
  111 + foreach (const Template &t, data) {
  112 + if ((templatesList.size() != t.size()) && !templatesList.isEmpty())
  113 + qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable(t.file.name), t.size(), templatesList.size());
  114 + while (templatesList.size() < t.size())
  115 + templatesList.append(TemplateList());
  116 + for (int i=0; i<t.size(); i++)
  117 + templatesList[i].append(Template(t.file, t[i]));
  118 + }
  119 +
  120 + while (transforms.size() < templatesList.size())
  121 + transforms.append(transform->clone());
  122 +
  123 + for (int i=0; i<templatesList.size(); i++)
  124 + templatesList[i] = Downsample(templatesList[i], transforms[i]);
  125 +
  126 + QFutureSynchronizer<void> futures;
  127 + for (int i=0; i<templatesList.size(); i++)
  128 + futures.addFuture(QtConcurrent::run(_train, transforms[i], &templatesList[i]));
  129 + futures.waitForFinished();
  130 + }
  131 +
  132 + void project(const Template &src, Template &dst) const
  133 + {
  134 + dst.file = src.file;
  135 + QList<Mat> mats;
  136 + for (int i=0; i<src.size(); i++) {
  137 + transforms[i%transforms.size()]->project(Template(src.file, src[i]), dst);
  138 + mats.append(dst);
  139 + dst.clear();
  140 + }
  141 + dst.append(mats);
  142 + }
  143 +
  144 + void store(QDataStream &stream) const
  145 + {
  146 + const int size = transforms.size();
  147 + stream << size;
  148 + for (int i=0; i<size; i++)
  149 + transforms[i]->store(stream);
  150 + }
  151 +
  152 + void load(QDataStream &stream)
  153 + {
  154 + int size;
  155 + stream >> size;
  156 + while (transforms.size() < size)
  157 + transforms.append(transform->clone());
  158 + for (int i=0; i<size; i++)
  159 + transforms[i]->load(stream);
  160 + }
  161 +};
  162 +
  163 +BR_REGISTER(Transform, IndependentTransform)
  164 +
  165 +// File independent(".Independent");
  166 +// independent.set("transform", qVariantFromValue<void*>(transform));
  167 +// transform = Factory<Transform>::make(independent);
  168 +
  169 +// void setProperty(const QString &name, const QVariant &value, bool errorOnFailure = false); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */
  170 +
  171 +//if (key.startsWith(("_Arg"))) {
  172 +// const int argumentNumber = key.mid(4).toInt();
  173 +// const int targetIdx = argumentNumber + firstAvailablePropertyIdx;
  174 +// if (targetIdx >= metaObject()->propertyCount()) {
  175 +// qWarning("Too many arguments for transform %s, ignoring %s", qPrintable(objectName()), qPrintable(key));
  176 +// continue;
  177 +// }
  178 +// key = metaObject()->property(targetIdx).name();
  179 +//}
  180 +
  181 +//const QVariant value = file.value(key);
  182 +//if (value.canConvert<QString>()) setProperty(key, value.toString()); // Parse the value first
  183 +//else setProperty(key, value); // Set the property directly
  184 +
  185 +} // namespace br
  186 +
  187 +#include "independent.moc"
... ...