diff --git a/openbr/core/eval.cpp b/openbr/core/eval.cpp index 7772bf2..4ac3e5b 100644 --- a/openbr/core/eval.cpp +++ b/openbr/core/eval.cpp @@ -434,9 +434,16 @@ QList getDetections(QString key, const Template &t, bool isList, bool File f = t.file; QList dets; if (isList) { - // TODO: handle Confidence for multiple detections in a template - foreach (const QRectF &rect, f.rects()) - dets.append(Detection(rect)); + QList rects = f.rects(); + QList confidences = f.getList("Confidences", QList()); + if (!isTruth && rects.size() != confidences.size()) + qFatal("You don't have enough confidence. I mean, your detections don't all have confidence measures."); + for (int i=0; i(key))); diff --git a/openbr/core/qtutils.cpp b/openbr/core/qtutils.cpp index a153853..aaccf0a 100644 --- a/openbr/core/qtutils.cpp +++ b/openbr/core/qtutils.cpp @@ -399,13 +399,33 @@ void showFile(const QString &file) QString toString(const QVariant &variant) { - if (variant.canConvert(QVariant::String)) return variant.toString(); - else if(variant.canConvert(QVariant::PointF)) return QString("(%1,%2)").arg(QString::number(qvariant_cast(variant).x()), - QString::number(qvariant_cast(variant).y())); - else if (variant.canConvert(QVariant::RectF)) return QString("(%1,%2,%3,%4)").arg(QString::number(qvariant_cast(variant).x()), - QString::number(qvariant_cast(variant).y()), - QString::number(qvariant_cast(variant).width()), - QString::number(qvariant_cast(variant).height())); + 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)) { + 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(); } diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index d382184..d551bb0 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -41,6 +41,8 @@ #include #include #include +#include +#include /*! * \defgroup cpp_plugin_sdk C++ Plugin SDK @@ -215,6 +217,14 @@ struct BR_EXPORT File static QVariant parse(const QString &value); /*!< \brief Try to convert the QString to a QPointF or QRectF if possible. */ inline void set(const QString &key, const QVariant &value) { m_metadata.insert(key, value); } /*!< \brief Insert or overwrite the metadata key with the specified value. */ void set(const QString &key, const QString &value); /*!< \brief Insert or overwrite the metadata key with the specified value. */ + + /*!< \brief Specialization for list type. Insert or overwrite the metadata key with the specified value. */ + template + void setList(const QString &key, const QList &value) + { + set(key, QtUtils::toVariantList(value)); + } + inline void remove(const QString &key) { m_metadata.remove(key); } /*!< \brief Remove the metadata key. */ /*!< \brief Returns a value for the key, throwing an error if the key does not exist. */ @@ -253,6 +263,19 @@ struct BR_EXPORT File return list; } + /*!< \brief Specialization for list type. Returns a list of type T for the key, returning \em defaultValue if the key does not exist or can't be converted. */ + template + QList getList(const QString &key, const QList defaultValue) const + { + if (!contains(key)) return defaultValue; + QList list; + foreach (const QVariant &item, m_metadata[key].toList()) { + if (item.canConvert()) list.append(item.value()); + else return defaultValue; + } + return list; + } + /*!< \brief Returns the value for the specified key for every file in the list. */ template static QList values(const QList &fileList, const QString &key) @@ -292,9 +315,12 @@ struct BR_EXPORT File QList namedRects() const; /*!< \brief Returns rects convertible from metadata values. */ QList rects() const; /*!< \brief Returns the file's rects list. */ void appendRect(const QRectF &rect); /*!< \brief Adds a rect to the file's rect list. */ + void appendRect(const cv::Rect &rect) { appendRect(OpenCVUtils::fromRect(rect)); } /*!< \brief Adds a rect to the file's rect list. */ void appendRects(const QList &rects); /*!< \brief Adds rects to the file's rect list. */ + void appendRects(const QList &rects) { appendRects(OpenCVUtils::fromRects(rects)); } /*!< \brief Adds rects to the file's rect list. */ inline void clearRects() { m_metadata["Rects"] = QList(); } /*!< \brief Clears the file's rect list. */ inline void setRects(const QList &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */ + inline void setRects(const QList &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */ private: QMap m_metadata; diff --git a/openbr/plugins/landmarks.cpp b/openbr/plugins/landmarks.cpp index a19439a..0773541 100644 --- a/openbr/plugins/landmarks.cpp +++ b/openbr/plugins/landmarks.cpp @@ -113,7 +113,7 @@ class ProcrustesTransform : public Transform // R(0,0), R(1,0), R(1,1), R(0,1), mean_x, mean_y, norm QList procrustesStats; procrustesStats << R(0,0) << R(1,0) << R(1,1) << R(0,1) << mean[0] << mean[1] << norm; - dst.file.set("ProcrustesStats",QtUtils::toVariantList(procrustesStats)); + dst.file.setList("ProcrustesStats",procrustesStats); if (warp) { Eigen::MatrixXf dstMat = srcMat*R; @@ -273,7 +273,7 @@ class DelaunayTransform : public UntrainableTransform dst.file.setRects(QList() << OpenCVUtils::fromRect(boundingBox)); } else dst = src; - dst.file.set("DelaunayTriangles", QtUtils::toVariantList(validTriangles)); + dst.file.setList("DelaunayTriangles", validTriangles); } }; diff --git a/openbr/plugins/slidingwindow.cpp b/openbr/plugins/slidingwindow.cpp index db60d08..ed5dcb6 100644 --- a/openbr/plugins/slidingwindow.cpp +++ b/openbr/plugins/slidingwindow.cpp @@ -1,6 +1,8 @@ #include "openbr_internal.h" #include "openbr/core/opencvutils.h" #include "openbr/core/common.h" +#include "openbr/core/qtutils.h" +#include using namespace cv; @@ -117,8 +119,12 @@ private: Template detect; transform->project(windowMat, detect); // the result will be in the Label - if (detect.file.get(QString("Label")) == "pos") { + if (detect.file.get("Label") == "pos") { dst.file.appendRect(OpenCVUtils::fromRect(window)); + float confidence = detect.file.get("Dist"); + QList confidences = dst.file.getList("Confidences", QList()); + confidences.append(confidence); + dst.file.setList("Confidences", confidences); if (takeLargestScale) return; } } @@ -129,6 +135,36 @@ private: BR_REGISTER(Transform, SlidingWindowTransform) +/*! + * \ingroup transforms + * \brief Detects objects with OpenCV's built-in HOG detection. + * \author Austin Blanton \cite imaus10 + */ +class HOGDetectTransform : public UntrainableTransform +{ + Q_OBJECT + + HOGDescriptor hog; + + void init() + { + hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector()); + } + + void project(const Template &src, Template &dst) const + { + dst = src; + std::vector objLocs; + QList rects; + hog.detectMultiScale(src, objLocs); + foreach (const Rect &obj, objLocs) + rects.append(obj); + dst.file.setRects(rects); + } +}; + +BR_REGISTER(Transform, HOGDetectTransform) + } // namespace br #include "slidingwindow.moc" diff --git a/openbr/plugins/svm.cpp b/openbr/plugins/svm.cpp index d4e2aad..a30fe9b 100644 --- a/openbr/plugins/svm.cpp +++ b/openbr/plugins/svm.cpp @@ -103,6 +103,7 @@ class SVMTransform : public Transform Q_PROPERTY(float gamma READ get_gamma WRITE set_gamma RESET reset_gamma STORED false) Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false) + Q_PROPERTY(bool returnDFVal READ get_returnDFVal WRITE set_returnDFVal RESET reset_returnDFVal STORED false) public: enum Kernel { Linear = CvSVM::LINEAR, @@ -123,6 +124,7 @@ private: BR_PROPERTY(float, gamma, -1) BR_PROPERTY(QString, inputVariable, "") BR_PROPERTY(QString, outputVariable, "") + BR_PROPERTY(bool, returnDFVal, false) SVM svm; @@ -149,8 +151,17 @@ private: void project(const Template &src, Template &dst) const { + if (returnDFVal && reverseLookup.size() > 2) + qFatal("Decision function for multiclass classification not implemented."); + dst = src; - float prediction = svm.predict(src.m().reshape(1, 1)); + float prediction = svm.predict(src.m().reshape(1, 1), returnDFVal); + if (returnDFVal) { + dst.file.set("Dist", prediction); + // positive values ==> first class + // negative values ==> second class + prediction = prediction > 0 ? 0 : 1; + } if (type == EPS_SVR || type == NU_SVR) dst.file.set(outputVariable, prediction); else