diff --git a/openbr/openbr_plugin.cpp b/openbr/openbr_plugin.cpp index 8ae4354..6699b9c 100644 --- a/openbr/openbr_plugin.cpp +++ b/openbr/openbr_plugin.cpp @@ -679,12 +679,17 @@ void Object::setProperty(const QString &name, const QString &value) variant = value; } - if (!QObject::setProperty(qPrintable(name), variant) && !type.isEmpty()) - qFatal("Failed to set %s::%s to: %s %s", - metaObject()->className(), qPrintable(name), qPrintable(value), qPrintable(type)); + setProperty(name, variant, !type.isEmpty()); } -QStringList br::Object::parse(const QString &string, char split) +void Object::setProperty(const QString &name, const QVariant &value, bool failOnError) +{ + if (!QObject::setProperty(qPrintable(name), value) && failOnError) + qFatal("Failed to set %s::%s to: %s", + metaObject()->className(), qPrintable(name), qPrintable(value.toString())); +} + +QStringList Object::parse(const QString &string, char split) { return QtUtils::parse(string, split); } @@ -736,19 +741,21 @@ void Object::init(const File &file_) } foreach (QString key, file.localKeys()) { - const QString value = file.value(key).toString(); + const QVariant value = file.value(key); + const QString valueString = value.toString(); if (key.startsWith(("_Arg"))) { - int argument_number = key.mid(4).toInt(); - int target_idx = argument_number + firstAvailablePropertyIdx; - - if (target_idx >= metaObject()->propertyCount()) { - qWarning("too many arguments for transform, ignoring %s\n", qPrintable(value)); + int argumentNumber = key.mid(4).toInt(); + int targetIdx = argumentNumber + firstAvailablePropertyIdx; + if (targetIdx >= metaObject()->propertyCount()) { + qWarning("too many arguments for transform %s, ignoring %s", qPrintable(objectName()), qPrintable(valueString)); continue; } - key = metaObject()->property(target_idx).name(); + key = metaObject()->property(targetIdx).name(); } - setProperty(key, value); + + if (valueString.isEmpty()) setProperty(key, value); // Set the property directly + else setProperty(key, valueString); // Parse the value first } init(); @@ -1083,153 +1090,6 @@ Gallery *Gallery::make(const File &file) return gallery; } -static TemplateList Downsample(const TemplateList &templates, const Transform *transform) -{ - // Return early when no downsampling is required - if ((transform->classes == std::numeric_limits::max()) && - (transform->instances == std::numeric_limits::max()) && - (transform->fraction >= 1)) - return templates; - - const bool atLeast = transform->instances < 0; - const int instances = abs(transform->instances); - - QList allLabels = templates.labels(); - QList uniqueLabels = allLabels.toSet().toList(); - qSort(uniqueLabels); - - QMap counts = templates.labelCounts(instances != std::numeric_limits::max()); - if ((instances != std::numeric_limits::max()) && (transform->classes != std::numeric_limits::max())) - foreach (int label, counts.keys()) - if (counts[label] < instances) - counts.remove(label); - uniqueLabels = counts.keys(); - if ((transform->classes != std::numeric_limits::max()) && (uniqueLabels.size() < transform->classes)) - qWarning("Downsample requested %d classes but only %d are available.", transform->classes, uniqueLabels.size()); - - Common::seedRNG(); - QList selectedLabels = uniqueLabels; - if (transform->classes < uniqueLabels.size()) { - std::random_shuffle(selectedLabels.begin(), selectedLabels.end()); - selectedLabels = selectedLabels.mid(0, transform->classes); - } - - TemplateList downsample; - for (int i=0; i indices; - for (int j=0; j("FTE", false))) - indices.append(j); - - std::random_shuffle(indices.begin(), indices.end()); - const int max = atLeast ? indices.size() : std::min(indices.size(), instances); - for (int j=0; jfraction < 1) { - std::random_shuffle(downsample.begin(), downsample.end()); - downsample = downsample.mid(0, downsample.size()*transform->fraction); - } - - return downsample; -} - -/*! - * \ingroup transforms - * \brief Clones the transform so that it can be applied independently. - * - * \em Independent transforms expect single-matrix templates. - */ -class Independent : public MetaTransform -{ - Q_PROPERTY(QList transforms READ get_transforms WRITE set_transforms STORED false) - BR_PROPERTY(QList, transforms, QList()) - - public: - /*! - * \brief Independent - * \param transform - */ - Independent(Transform *transform) - { - transform->setParent(this); - transforms.append(transform); - file = transform->file; - trainable = transform->trainable; - setObjectName(transforms.first()->objectName()); - } - -private: - Transform *clone() const - { - return new Independent(transforms.first()->clone()); - } - - static void _train(Transform *transform, const TemplateList *data) - { - transform->train(*data); - } - - void train(const TemplateList &data) - { - // Don't bother if the transform is untrainable - if (!trainable) return; - - QList templatesList; - foreach (const Template &t, data) { - if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) - qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable(t.file.name), t.size(), templatesList.size()); - while (templatesList.size() < t.size()) - templatesList.append(TemplateList()); - for (int i=0; iclone()); - - for (int i=0; i futures; - for (int i=0; i mats; - for (int i=0; iproject(Template(src.file, src[i]), dst); - mats.append(dst); - dst.clear(); - } - dst.append(mats); - } - - void store(QDataStream &stream) const - { - const int size = transforms.size(); - stream << size; - for (int i=0; istore(stream); - } - - void load(QDataStream &stream) - { - int size; - stream >> size; - while (transforms.size() < size) - transforms.append(transforms.first()->clone()); - for (int i=0; iload(stream); - } -}; - /* Transform - public methods */ Transform::Transform(bool _independent, bool _trainable) { @@ -1277,8 +1137,17 @@ Transform *Transform::make(QString str, QObject *parent) File f = "." + str; Transform *transform = Factory::make(f); - if (transform->independent) - transform = new Independent(transform); + if (transform->independent) { +// Transform *independentTransform = Factory::make(".Independent"); +// static_cast(independentTransform)->setProperty("transform", qVariantFromValue(transform)); +// independentTransform->init(); +// transform = independentTransform; + + File independent(".Independent"); + independent.set("transform", qVariantFromValue(transform)); + transform = Factory::make(independent); + } + transform->setParent(parent); return transform; } diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index 2775aee..b262eb7 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -497,6 +497,7 @@ public: QString argument(int index) const; /*!< \brief A string value for the argument at the specified index. */ QString description() const; /*!< \brief Returns a string description of the object. */ void setProperty(const QString &name, const QString &value); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */ + void setProperty(const QString &name, const QVariant &value, bool failOnError = false); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */ static QStringList parse(const QString &string, char split = ','); /*!< \brief Splits the string while respecting lexical scoping of (), [], \<\>, and {}. */ private: diff --git a/openbr/plugins/independent.cpp b/openbr/plugins/independent.cpp new file mode 100644 index 0000000..f221f51 --- /dev/null +++ b/openbr/plugins/independent.cpp @@ -0,0 +1,187 @@ +#include +#include + +#include "openbr_internal.h" +#include "openbr/core/common.h" + +using namespace cv; + +namespace br +{ + +static TemplateList Downsample(const TemplateList &templates, const Transform *transform) +{ + // Return early when no downsampling is required + if ((transform->classes == std::numeric_limits::max()) && + (transform->instances == std::numeric_limits::max()) && + (transform->fraction >= 1)) + return templates; + + const bool atLeast = transform->instances < 0; + const int instances = abs(transform->instances); + + QList allLabels = templates.labels(); + QList uniqueLabels = allLabels.toSet().toList(); + qSort(uniqueLabels); + + QMap counts = templates.labelCounts(instances != std::numeric_limits::max()); + if ((instances != std::numeric_limits::max()) && (transform->classes != std::numeric_limits::max())) + foreach (int label, counts.keys()) + if (counts[label] < instances) + counts.remove(label); + uniqueLabels = counts.keys(); + if ((transform->classes != std::numeric_limits::max()) && (uniqueLabels.size() < transform->classes)) + qWarning("Downsample requested %d classes but only %d are available.", transform->classes, uniqueLabels.size()); + + Common::seedRNG(); + QList selectedLabels = uniqueLabels; + if (transform->classes < uniqueLabels.size()) { + std::random_shuffle(selectedLabels.begin(), selectedLabels.end()); + selectedLabels = selectedLabels.mid(0, transform->classes); + } + + TemplateList downsample; + for (int i=0; i indices; + for (int j=0; j("FTE", false))) + indices.append(j); + + std::random_shuffle(indices.begin(), indices.end()); + const int max = atLeast ? indices.size() : std::min(indices.size(), instances); + for (int j=0; jfraction < 1) { + std::random_shuffle(downsample.begin(), downsample.end()); + downsample = downsample.mid(0, downsample.size()*transform->fraction); + } + + return downsample; +} + +/*! + * \ingroup transforms + * \brief Clones the transform so that it can be applied independently. + * \author Josh Klontz \cite jklontz + * \em Independent transforms expect single-matrix templates. + */ +class IndependentTransform : public MetaTransform +{ + Q_OBJECT + Q_PROPERTY(br::Transform* transform READ get_transform WRITE set_transform STORED false) + BR_PROPERTY(br::Transform*, transform, NULL) + + QList transforms; + + void init() + { + transforms.clear(); + if (transform == NULL) + return; + + transform->setParent(this); + transforms.append(transform); + file = transform->file; + trainable = transform->trainable; + setObjectName(transform->objectName()); + } + + Transform *clone() const + { + IndependentTransform *independentTransform = new IndependentTransform(); + independentTransform->transform = transform->clone(); + independentTransform->init(); + return independentTransform; + } + + static void _train(Transform *transform, const TemplateList *data) + { + transform->train(*data); + } + + void train(const TemplateList &data) + { + // Don't bother if the transform is untrainable + if (!trainable) return; + + QList templatesList; + foreach (const Template &t, data) { + if ((templatesList.size() != t.size()) && !templatesList.isEmpty()) + qWarning("Independent::train template %s of size %d differs from expected size %d.", qPrintable(t.file.name), t.size(), templatesList.size()); + while (templatesList.size() < t.size()) + templatesList.append(TemplateList()); + for (int i=0; iclone()); + + for (int i=0; i futures; + for (int i=0; i mats; + for (int i=0; iproject(Template(src.file, src[i]), dst); + mats.append(dst); + dst.clear(); + } + dst.append(mats); + } + + void store(QDataStream &stream) const + { + const int size = transforms.size(); + stream << size; + for (int i=0; istore(stream); + } + + void load(QDataStream &stream) + { + int size; + stream >> size; + while (transforms.size() < size) + transforms.append(transform->clone()); + for (int i=0; iload(stream); + } +}; + +BR_REGISTER(Transform, IndependentTransform) + +// File independent(".Independent"); +// independent.set("transform", qVariantFromValue(transform)); +// transform = Factory::make(independent); + +// void setProperty(const QString &name, const QVariant &value, bool errorOnFailure = false); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */ + +//if (key.startsWith(("_Arg"))) { +// const int argumentNumber = key.mid(4).toInt(); +// const int targetIdx = argumentNumber + firstAvailablePropertyIdx; +// if (targetIdx >= metaObject()->propertyCount()) { +// qWarning("Too many arguments for transform %s, ignoring %s", qPrintable(objectName()), qPrintable(key)); +// continue; +// } +// key = metaObject()->property(targetIdx).name(); +//} + +//const QVariant value = file.value(key); +//if (value.canConvert()) setProperty(key, value.toString()); // Parse the value first +//else setProperty(key, value); // Set the property directly + +} // namespace br + +#include "independent.moc"