#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 = File::get(templates, "Subject"); QList uniqueLabels = allLabels.toSet().toList(); qSort(uniqueLabels); QMap counts = templates.countValues("Subject", instances != std::numeric_limits::max()); if ((instances != std::numeric_limits::max()) && (transform->classes != std::numeric_limits::max())) foreach (const QString & 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 RESET reset_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 (%s) template %s of size %d differs from expected size %d.", qPrintable(objectName()), 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) /*! * \ingroup transforms * \brief A globally shared transform. * \author Josh Klontz \cite jklontz */ class SingletonTransform : public MetaTransform { Q_OBJECT Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) BR_PROPERTY(QString, description, "Identity") static QMutex mutex; static QHash transforms; static QHash trainingReferenceCounts; static QHash trainingData; Transform *transform; void init() { QMutexLocker locker(&mutex); if (!transforms.contains(description)) { transforms.insert(description, make(description)); trainingReferenceCounts.insert(description, 0); } transform = transforms[description]; trainingReferenceCounts[description]++; } void train(const TemplateList &data) { QMutexLocker locker(&mutex); trainingData[description].append(data); trainingReferenceCounts[description]--; if (trainingReferenceCounts[description] > 0) return; transform->train(trainingData[description]); trainingData[description].clear(); } void project(const Template &src, Template &dst) const { transform->project(src, dst); } void store(QDataStream &stream) const { if (transform->parent() == this) transform->store(stream); } void load(QDataStream &stream) { if (transform->parent() == this) transform->load(stream); } }; QMutex SingletonTransform::mutex; QHash SingletonTransform::transforms; QHash SingletonTransform::trainingReferenceCounts; QHash SingletonTransform::trainingData; BR_REGISTER(Transform, SingletonTransform) } // namespace br #include "independent.moc"