diff --git a/openbr/core/eval.cpp b/openbr/core/eval.cpp index 4db31c7..c2f94ea 100755 --- a/openbr/core/eval.cpp +++ b/openbr/core/eval.cpp @@ -1044,12 +1044,14 @@ void EvalRegression(const QString &predictedGallery, const QString &truthGallery if (predicted[i].file.name != truth[i].file.name) qFatal("Input order mismatch."); - float difference = predicted[i].file.get(predictedProperty) - truth[i].file.get(truthProperty); + if (predicted[i].file.contains(predictedProperty) && truth[i].file.contains(truthProperty)) { + float difference = predicted[i].file.get(predictedProperty) - truth[i].file.get(truthProperty); - rmsError += pow(difference, 2.f); - maeError += fabsf(difference); - truthValues.append(QString::number(truth[i].file.get(truthProperty))); - predictedValues.append(QString::number(predicted[i].file.get(predictedProperty))); + rmsError += pow(difference, 2.f); + maeError += fabsf(difference); + truthValues.append(QString::number(truth[i].file.get(truthProperty))); + predictedValues.append(QString::number(predicted[i].file.get(predictedProperty))); + } } QStringList rSource; diff --git a/openbr/core/opencvutils.cpp b/openbr/core/opencvutils.cpp index 753daa8..25214b5 100644 --- a/openbr/core/opencvutils.cpp +++ b/openbr/core/opencvutils.cpp @@ -121,6 +121,17 @@ Mat OpenCVUtils::toMat(const QList &src, int rows) return dst; } +Mat OpenCVUtils::pointsToMatrix(const QList &qPoints) +{ + QList points; + foreach(const QPointF &point, qPoints) { + points.append(point.x()); + points.append(point.y()); + } + + return toMat(points); +} + Mat OpenCVUtils::toMat(const QList > &srcs, int rows) { QList flat; diff --git a/openbr/core/opencvutils.h b/openbr/core/opencvutils.h index 572e214..8632d39 100644 --- a/openbr/core/opencvutils.h +++ b/openbr/core/opencvutils.h @@ -84,6 +84,7 @@ namespace OpenCVUtils QPointF fromPoint(const cv::Point2f &cvPoint); QList toPoints(const QList &qPoints); QList fromPoints(const QList &cvPoints); + cv::Mat pointsToMatrix(const QList &qPoints); cv::Rect toRect(const QRectF &qRect); QRectF fromRect(const cv::Rect &cvRect); QList toRects(const QList &qRects); diff --git a/openbr/plugins/landmarks.cpp b/openbr/plugins/landmarks.cpp index a64dba8..a76dc57 100644 --- a/openbr/plugins/landmarks.cpp +++ b/openbr/plugins/landmarks.cpp @@ -369,12 +369,14 @@ BR_REGISTER(Transform, ReadLandmarksTransform) /*! * \ingroup transforms - * \brief Name a point + * \brief Name a point/rect * \author Scott Klum \cite sklum */ -class NamePointsTransform : public UntrainableMetadataTransform +class NameLandmarksTransform : public UntrainableMetadataTransform { Q_OBJECT + Q_PROPERTY(bool point READ get_point WRITE set_point RESET reset_point STORED false) + BR_PROPERTY(bool, point, true) Q_PROPERTY(QList indices READ get_indices WRITE set_indices RESET reset_indices STORED false) Q_PROPERTY(QStringList names READ get_names WRITE set_names RESET reset_names STORED false) BR_PROPERTY(QList, indices, QList()) @@ -382,27 +384,36 @@ class NamePointsTransform : public UntrainableMetadataTransform void projectMetadata(const File &src, File &dst) const { - if (indices.size() != names.size()) qFatal("Point/name size mismatch"); + if (indices.size() != names.size()) qFatal("Index/name size mismatch"); dst = src; - QList points = src.points(); + if (point) { + QList points = src.points(); - for (int i=0; i rects = src.rects(); + + for (int i=0; i(name)); + foreach (const QString &name, names) { + if (src.contains(name)) { + QVariant variant = src.value(name); + if (variant.canConvert(QMetaType::QPointF)) { + dst.appendPoint(variant.toPointF()); + } else if (variant.canConvert(QMetaType::QRectF)) { + dst.appendRect(variant.toRectF()); + } else { + qFatal("Cannot convert landmark to point or rect."); + } + } + } + } +}; + +BR_REGISTER(Transform, AnonymizeLandmarksTransform) + +/*! + * \ingroup transforms + * \brief Converts either the file::points() list or a QList metadata item to be the template's matrix + * \author Scott Klum \cite sklum + */ +class PointsToMatrixTransform : public UntrainableTransform +{ + Q_OBJECT + + Q_PROPERTY(QString inputVariable READ get_inputVariable WRITE set_inputVariable RESET reset_inputVariable STORED false) + BR_PROPERTY(QString, inputVariable, QString()) + + void project(const Template &src, Template &dst) const + { + dst = src; + + if (inputVariable.isEmpty()) { + dst.m() = OpenCVUtils::pointsToMatrix(dst.file.points()); + } else { + if (src.file.contains(inputVariable)) + dst.m() = OpenCVUtils::pointsToMatrix(dst.file.get >(inputVariable)); + } + } +}; + +BR_REGISTER(Transform, PointsToMatrixTransform) + +/*! + * \ingroup transforms + * \brief Normalize points to be relative to a single point + * \author Scott Klum \cite sklum + */ +class NormalizePointsTransform : public UntrainableTransform +{ + Q_OBJECT + + Q_PROPERTY(int index READ get_index WRITE set_index RESET reset_index STORED false) + BR_PROPERTY(int, index, 0) + + void project(const Template &src, Template &dst) const + { + dst = src; + + QList points = dst.file.points(); + QPointF normPoint = points.at(index); + + QList normalizedPoints; + + for (int i=0; i points = dst.file.points(); + QList normalizedPoints; + + for (int i=0; i + +#include "openbr_internal.h" +#include "openbr/core/qtutils.h" +#include "openbr/core/opencvutils.h" +#include "openbr/core/eigenutils.h" +#include +#include + +using namespace std; +using namespace cv; + +namespace br +{ + +static void storeMLP(const CvANN_MLP &mlp, QDataStream &stream) +{ + // Create local file + QTemporaryFile tempFile; + tempFile.open(); + tempFile.close(); + + // Save MLP to local file + mlp.save(qPrintable(tempFile.fileName())); + + // Copy local file contents to stream + tempFile.open(); + QByteArray data = tempFile.readAll(); + tempFile.close(); + stream << data; +} + +static void loadMLP(CvANN_MLP &mlp, QDataStream &stream) +{ + // Copy local file contents from stream + QByteArray data; + stream >> data; + + // Create local file + QTemporaryFile tempFile(QDir::tempPath()+"/MLP"); + tempFile.open(); + tempFile.write(data); + tempFile.close(); + + // Load MLP from local file + mlp.load(qPrintable(tempFile.fileName())); +} + +/*! + * \ingroup transforms + * \brief Wraps OpenCV's multi-layer perceptron framework + * \author Scott Klum \cite sklum + * \brief http://docs.opencv.org/modules/ml/doc/neural_networks.html + */ +class MLPTransform : public MetaTransform +{ + Q_OBJECT + + Q_ENUMS(Kernel) + Q_PROPERTY(Kernel kernel READ get_kernel WRITE set_kernel RESET reset_kernel STORED false) + Q_PROPERTY(float alpha READ get_alpha WRITE set_alpha RESET reset_alpha STORED false) + Q_PROPERTY(float beta READ get_beta WRITE set_beta RESET reset_beta STORED false) + Q_PROPERTY(QStringList inputVariables READ get_inputVariables WRITE set_inputVariables RESET reset_inputVariables STORED false) + Q_PROPERTY(QStringList outputVariables READ get_outputVariables WRITE set_outputVariables RESET reset_outputVariables STORED false) + Q_PROPERTY(QList neuronsPerLayer READ get_neuronsPerLayer WRITE set_neuronsPerLayer RESET reset_neuronsPerLayer STORED false) + +public: + + enum Kernel { Identity = CvANN_MLP::IDENTITY, + Sigmoid = CvANN_MLP::SIGMOID_SYM, + Gaussian = CvANN_MLP::GAUSSIAN}; + +private: + BR_PROPERTY(Kernel, kernel, Sigmoid) + BR_PROPERTY(float, alpha, 1) + BR_PROPERTY(float, beta, 1) + BR_PROPERTY(QStringList, inputVariables, QStringList()) + BR_PROPERTY(QStringList, outputVariables, QStringList()) + BR_PROPERTY(QList, neuronsPerLayer, QList() << 1 << 1) + + CvANN_MLP mlp; + + void init() + { + if (kernel == Gaussian) + qWarning("The OpenCV documentation warns that the Gaussian kernel, \"is not completely supported at the moment\""); + + Mat layers = Mat(neuronsPerLayer.size(), 1, CV_32SC1); + for (int i=0; i(data, inputVariables.at(i))); + + mlp.train(_data,labels,Mat()); + + if (Globals->verbose) + for (int i=0; i(0,i)); + } + + void load(QDataStream &stream) + { + loadMLP(mlp,stream); + } + + void store(QDataStream &stream) const + { + storeMLP(mlp,stream); + } +}; + +BR_REGISTER(Transform, MLPTransform) + +} // namespace br + +#include "nn.moc"