diff --git a/openbr/core/core.cpp b/openbr/core/core.cpp index 370cedf..c2601cd 100644 --- a/openbr/core/core.cpp +++ b/openbr/core/core.cpp @@ -139,7 +139,6 @@ struct AlgorithmCore downcast->transforms[0] = this->transform.data(); downcast->init(); - downcast->projectUpdate(i,i); return i.files(); diff --git a/openbr/core/qtutils.cpp b/openbr/core/qtutils.cpp index 1be8b99..0d5b511 100644 --- a/openbr/core/qtutils.cpp +++ b/openbr/core/qtutils.cpp @@ -399,33 +399,31 @@ void showFile(const QString &file) QString toString(const QVariant &variant) { - if (variant.canConvert(QVariant::String)) - return variant.toString(); - else if(variant.canConvert(QVariant::PointF)) { - QPointF pt = qvariant_cast(variant); - return QString("(%1,%2)").arg(QString::number(pt.x()), - QString::number(pt.y())); - } - else if (variant.canConvert(QVariant::RectF)) { + if (variant.canConvert(QVariant::List)) return toString(qvariant_cast(variant)); + else if (variant.canConvert(QVariant::String)) return variant.toString(); + else if (variant.canConvert(QVariant::PointF)) { + QPointF point = qvariant_cast(variant); + return QString("(%1,%2)").arg(QString::number(point.x()),QString::number(point.y())); + } else if (variant.canConvert(QVariant::RectF)) { QRectF rect = qvariant_cast(variant); return QString("(%1,%2,%3,%4)").arg(QString::number(rect.x()), QString::number(rect.y()), QString::number(rect.width()), QString::number(rect.height())); } - else if (variant.canConvert(QVariant::List)) { - QString ret = QString("["); - bool first = true; - foreach (const QVariant &i, variant.toList()) { - if (!first) - ret += ","; - else - first = false; - ret += toString(i); - } - ret += "]"; - return ret; - } + + return QString(); +} + +QString toString(const QVariantList &variantList) +{ + QStringList variants; + + foreach(const QVariant &variant, variantList) + variants.append(toString(variant)); + + if (!variants.isEmpty()) return "[" + variants.join(", ") + "]"; + return QString(); } diff --git a/openbr/core/qtutils.h b/openbr/core/qtutils.h index 649f771..256b968 100644 --- a/openbr/core/qtutils.h +++ b/openbr/core/qtutils.h @@ -74,6 +74,7 @@ namespace QtUtils /**** Variant Utilities ****/ QString toString(const QVariant &variant); + QString toString(const QVariantList &variantList); template QVariantList toVariantList(const QList &list) diff --git a/openbr/openbr_plugin.cpp b/openbr/openbr_plugin.cpp index d5ac481..306dd32 100644 --- a/openbr/openbr_plugin.cpp +++ b/openbr/openbr_plugin.cpp @@ -58,16 +58,7 @@ QString File::flat() const foreach (const QString &key, keys) { const QVariant value = this->value(key); if (value.isNull()) values.append(key); - else { - if (QString(value.typeName()) == "QVariantList") { - QStringList variants; - foreach(const QVariant &variant, qvariant_cast(value)) { - variants.append(QtUtils::toString(variant)); - } - if (!variants.isEmpty()) values.append(key + "=[" + variants.join(", ") + "]"); - } - else values.append(key + "=" + QtUtils::toString(value)); - } + else values.append(key + "=" + QtUtils::toString(value)); } QString flat = name; diff --git a/openbr/plugins/regions.cpp b/openbr/plugins/regions.cpp index 317eb54..9e9e92a 100644 --- a/openbr/plugins/regions.cpp +++ b/openbr/plugins/regions.cpp @@ -345,9 +345,12 @@ class RectFromPointsTransform : public UntrainableTransform dst.file.setPoints(points); - if (crop) dst.m() = src.m()(Rect(std::max(0.0, minX - deltaWidth/2.0), std::max(0.0, minY - deltaHeight/2.0), std::min((double)src.m().cols, width), std::min((double)src.m().rows, height))); + const int x = std::max(0.0, minX - deltaWidth/2.0); + const int y = std::max(0.0, minY - deltaHeight/2.0); + + if (crop) dst.m() = src.m()(Rect(x, y, std::min((double)src.m().cols-x, width), std::min((double)src.m().rows-y, height))); else { - dst.file.appendRect(QRectF(std::max(0.0, minX - deltaWidth/2.0), std::max(0.0, minY - deltaHeight/2.0), std::min((double)src.m().cols, width), std::min((double)src.m().rows, height))); + dst.file.appendRect(QRectF(x, y, std::min((double)src.m().cols-x, width), std::min((double)src.m().rows-y, height))); dst.m() = src.m(); } } diff --git a/openbr/plugins/slidingwindow.cpp b/openbr/plugins/slidingwindow.cpp index 8bb4c83..c66f94b 100644 --- a/openbr/plugins/slidingwindow.cpp +++ b/openbr/plugins/slidingwindow.cpp @@ -8,12 +8,28 @@ using namespace cv; -// Because MSVC doesn't provide a round() function in math.h -static int round(float x) { return (floor(x + 0.5)); } - namespace br { +// Find avg aspect ratio +static float getAspectRatio(const TemplateList &data) +{ + double tempRatio = 0; + int ratioCnt = 0; + + foreach (const Template &tmpl, data) { + QList posRects = OpenCVUtils::toRects(tmpl.file.rects()); + foreach (const Rect &posRect, posRects) { + if (posRect.x + posRect.width >= tmpl.m().cols || posRect.y + posRect.height >= tmpl.m().rows || posRect.x < 0 || posRect.y < 0) { + continue; + } + tempRatio += (float)posRect.width / (float)posRect.height; + ratioCnt += 1; + } + } + return tempRatio / (double)ratioCnt; +} + /*! * \ingroup transforms * \brief Applies a transform to a sliding window. @@ -25,23 +41,19 @@ class SlidingWindowTransform : public Transform Q_OBJECT Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false) Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) - Q_PROPERTY(double scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) Q_PROPERTY(int stepSize READ get_stepSize WRITE set_stepSize RESET reset_stepSize STORED false) - Q_PROPERTY(bool takeLargestScale READ get_takeLargestScale WRITE set_takeLargestScale RESET reset_takeLargestScale STORED false) + Q_PROPERTY(bool takeFirst READ get_takeFirst WRITE set_takeFirst RESET reset_takeFirst STORED false) Q_PROPERTY(bool negSamples READ get_negSamples WRITE set_negSamples RESET reset_negSamples STORED false) Q_PROPERTY(int negToPosRatio READ get_negToPosRatio WRITE set_negToPosRatio RESET reset_negToPosRatio STORED false) Q_PROPERTY(double maxOverlap READ get_maxOverlap WRITE set_maxOverlap RESET reset_maxOverlap STORED false) - Q_PROPERTY(float aspectRatio READ get_aspectRatio WRITE set_aspectRatio RESET reset_aspectRatio STORED true) Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false) BR_PROPERTY(br::Transform *, transform, NULL) BR_PROPERTY(int, minSize, 8) - BR_PROPERTY(double, scaleFactor, 0.75) BR_PROPERTY(int, stepSize, 1) - BR_PROPERTY(bool, takeLargestScale, true) + BR_PROPERTY(bool, takeFirst, true) BR_PROPERTY(bool, negSamples, true) BR_PROPERTY(int, negToPosRatio, 1) BR_PROPERTY(double, maxOverlap, 0) - BR_PROPERTY(float, aspectRatio, 1) BR_PROPERTY(int, windowWidth, 24) public: @@ -50,24 +62,14 @@ private: void train(const TemplateList &data) { + // only calculate if the work hasn't been done + aspectRatio = data.first().file.get("aspectRatio", -1); + if (aspectRatio == -1) + aspectRatio = getAspectRatio(data); + if (transform->trainable) { - double tempRatio = 0; - int ratioCnt = 0; TemplateList full; - //First find avg aspect ratio - foreach (const Template &tmpl, data) { - QList posRects = OpenCVUtils::toRects(tmpl.file.rects()); - foreach (const Rect &posRect, posRects) { - if (posRect.x + posRect.width >= tmpl.m().cols || posRect.y + posRect.height >= tmpl.m().rows || posRect.x < 0 || posRect.y < 0) { - continue; - } - tempRatio += (float)posRect.width / (float)posRect.height; - ratioCnt += 1; - } - } - aspectRatio = tempRatio / (double)ratioCnt; - foreach (const Template &tmpl, data) { QList posRects = OpenCVUtils::toRects(tmpl.file.rects()); QList negRects; @@ -83,7 +85,7 @@ private: } Mat scaledImg; - resize(Mat(tmpl, posRect), scaledImg, Size(windowWidth,round(windowWidth / aspectRatio))); + resize(Mat(tmpl, posRect), scaledImg, Size(windowWidth,qRound(windowWidth / aspectRatio))); Template pos(tmpl.file, scaledImg); full += pos; @@ -132,43 +134,94 @@ private: if (src.file.getBool("Train", false)) return; dst.file.clearRects(); + int windowHeight = (int) qRound((float) windowWidth / aspectRatio); + int scale = src.file.get("scale", 1); + + for (double y = 0; y + windowHeight < src.m().rows; y += stepSize) { + for (double x = 0; x + windowWidth < src.m().cols; x += stepSize) { + Rect window(x, y, windowWidth, windowHeight); + Template windowMat(src.file, Mat(src, window)); + Template detect; + transform->project(windowMat, detect); + float conf = detect.file.get("conf"); + + // the result will be in the Label + if (conf > 0) { + dst.file.appendRect(QRectF((float) x * scale, (float) y * scale, (float) windowWidth * scale, (float) windowHeight * scale)); + QList confidences = dst.file.getList("Confidences", QList()); + confidences.append(conf); + dst.file.setList("Confidences", confidences); + if (takeFirst) + return; + } + } + } + } + + float aspectRatio; +}; + +BR_REGISTER(Transform, SlidingWindowTransform) + +/*! + * \ingroup transforms + * \brief . + * \author Austin Blanton \cite imaus10 + */ +class BuildScalesTransform : public Transform +{ + Q_OBJECT + Q_PROPERTY(br::Transform *transform READ get_transform WRITE set_transform RESET reset_transform STORED false) + Q_PROPERTY(double scaleFactor READ get_scaleFactor WRITE set_scaleFactor RESET reset_scaleFactor STORED false) + Q_PROPERTY(bool takeLargestScale READ get_takeLargestScale WRITE set_takeLargestScale RESET reset_takeLargestScale STORED false) + Q_PROPERTY(int windowWidth READ get_windowWidth WRITE set_windowWidth RESET reset_windowWidth STORED false) + BR_PROPERTY(br::Transform *, transform, NULL) + BR_PROPERTY(double, scaleFactor, 0.75) + BR_PROPERTY(bool, takeLargestScale, true) + BR_PROPERTY(int, windowWidth, 24) + +public: + BuildScalesTransform() : Transform(false, true) {} +private: + + void train(const TemplateList &data) + { + aspectRatio = getAspectRatio(data); + // have to make a copy b/c data is const + TemplateList cp = data; + cp.first().file.set("aspectRatio", aspectRatio); + if (transform->trainable) + transform->train(cp); + } + + void project(const Template &src, Template &dst) const + { + dst = src; + // do not scale images during training + if (src.file.getBool("Train", false)) return; + int rows = src.m().rows; int cols = src.m().cols; - int windowHeight = (int) round((float) windowWidth / aspectRatio); + int windowHeight = (int) qRound((float) windowWidth / aspectRatio); float startScale; if ((cols / rows) > aspectRatio) - startScale = round((float) rows / (float) windowHeight); + startScale = qRound((float) rows / (float) windowHeight); else - startScale = round((float) cols / (float) windowWidth); - + startScale = qRound((float) cols / (float) windowWidth); for (float scale = startScale; scale >= 1.0; scale -= (1.0 - scaleFactor)) { - Mat scaleImg; - resize(src, scaleImg, Size(round(cols / scale), round(rows / scale))); - - for (double y = 0; y + windowHeight < scaleImg.rows; y += stepSize) { - for (double x = 0; x + windowWidth < scaleImg.cols; x += stepSize) { - Rect window(x, y, windowWidth, windowHeight); - Template windowMat(src.file, Mat(scaleImg, window)); - Template detect; - transform->project(windowMat, detect); - float conf = detect.file.get("conf"); - - // the result will be in the Label - if (conf > 0) { - dst.file.appendRect(QRectF((float) x * scale, (float) y * scale, (float) windowWidth * scale, (float) windowHeight * scale)); - QList confidences = dst.file.getList("Confidences", QList()); - confidences.append(conf); - dst.file.setList("Confidences", confidences); - if (takeLargestScale) - return; - } - } - } + Template scaleImg(src.file, Mat()); + scaleImg.file.set("scale", scale); + resize(src, scaleImg, Size(qRound(cols / scale), qRound(rows / scale))); + transform->project(scaleImg, dst); + if (takeLargestScale && !dst.file.rects().empty()) + return; } } + + float aspectRatio; }; -BR_REGISTER(Transform, SlidingWindowTransform) +BR_REGISTER(Transform, BuildScalesTransform) /*! * \ingroup transforms diff --git a/openbr/plugins/stasm4.cpp b/openbr/plugins/stasm4.cpp index acb7911..4b2edc5 100644 --- a/openbr/plugins/stasm4.cpp +++ b/openbr/plugins/stasm4.cpp @@ -132,13 +132,16 @@ class StasmTransform : public UntrainableTransform if (!foundFace) { qWarning("No face found in %s.", qPrintable(src.file.fileName())); + dst.file.set("FTE",true); } else { + QList points; for (int i = 0; i < nLandmarks; i++) { QPointF point(landmarks[2 * i], landmarks[2 * i + 1]); - dst.file.appendPoint(point); - if (i == 38) dst.file.set("StasmRightEye",point); - else if (i == 39) dst.file.set("StasmLeftEye", point); + points.append(point); } + dst.file.set("StasmRightEye", points[38]); + dst.file.set("StasmLeftEye", points[39]); + dst.file.appendPoints(points); } } }; diff --git a/openbr/plugins/template.cpp b/openbr/plugins/template.cpp index cd68a32..5d92eba 100644 --- a/openbr/plugins/template.cpp +++ b/openbr/plugins/template.cpp @@ -9,7 +9,7 @@ namespace br * \brief Retains only the values for the keys listed, to reduce template size * \author Scott Klum \cite sklum */ -class RetainTransform : public UntrainableTransform +class KeepMetadataTransform : public UntrainableTransform { Q_OBJECT Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) @@ -24,7 +24,7 @@ class RetainTransform : public UntrainableTransform } }; -BR_REGISTER(Transform, RetainTransform) +BR_REGISTER(Transform, KeepMetadataTransform) /*! * \ingroup transforms diff --git a/openbr/plugins/validate.cpp b/openbr/plugins/validate.cpp index 0774565..280b969 100644 --- a/openbr/plugins/validate.cpp +++ b/openbr/plugins/validate.cpp @@ -255,7 +255,7 @@ class RejectDistance : public Distance { // We don't look at the query (void) b; - + foreach (const QString &key, keys) if ((rejectIfContains && a.file.contains(key)) || (!rejectIfContains && !a.file.contains(key))) return -std::numeric_limits::max();