diff --git a/openbr/plugins/landmarks.cpp b/openbr/plugins/landmarks.cpp index 241570b..07846d5 100644 --- a/openbr/plugins/landmarks.cpp +++ b/openbr/plugins/landmarks.cpp @@ -5,9 +5,11 @@ #include "openbr/core/eigenutils.h" #include #include +#include using namespace std; using namespace cv; +using namespace Eigen; namespace br { @@ -138,6 +140,163 @@ class ProcrustesTransform : public Transform BR_REGISTER(Transform, ProcrustesTransform) /*! + */ +class ProcrustesAlignTransform : public Transform +{ + Q_OBJECT + + Q_PROPERTY(float width READ get_width WRITE set_width RESET reset_width STORED false) + BR_PROPERTY(float, width, true) + + Eigen::MatrixXf referenceShape; + + MatrixXf getRotation(MatrixXf ref, MatrixXf sample) { + MatrixXf R = ref.transpose() * sample; + JacobiSVD svd(R, ComputeFullU | ComputeFullV); + R = svd.matrixU() * svd.matrixV(); + + return R; + } + + //Converts x y points in a single vector to two column matrix + MatrixXf vectorToMatrix(MatrixXf vector) { + int n = vector.rows(); + MatrixXf matrix(n / 2, 2); + for (int i = 0; i < n / 2; i++) { + for (int j = 0; j < 2; j++) { + matrix(i, j) = vector(i * 2 + j); + } + } + return matrix; + } + + MatrixXf matrixToVector(MatrixXf matrix) { + int n2 = matrix.rows(); + MatrixXf vector(n2 * 2, 1); + for (int i = 0; i < n2; i++) { + for (int j = 0; j < 2; j++) { + vector(i * 2 + j) = matrix(i, j); + } + } + return vector; + } + + void train(const TemplateList &data) + { + MatrixXf points(data[0].file.points().size() * 2, data.size()); + + // Normalize all sets of points + for (int j = 0; j < data.size(); j++) { + QList imagePoints = data[j].file.points(); + + float meanX = 0, + meanY = 0; + for (int i = 0; i < imagePoints.size(); i++) { + points(i * 2, j) = imagePoints[i].x(); + points(i * 2 + 1, j) = imagePoints[i].y(); + meanX += imagePoints[i].x(); + meanY += imagePoints[i].y(); + } + meanX /= imagePoints.size(); + meanY /= imagePoints.size(); + + for (int i = 0; i < imagePoints.size(); i++) { + points(i * 2, j) -= meanX; + points(i * 2 + 1, j) -= meanY; + } + } + + + //normalize scale + for (int i = 0; i < points.cols(); i++) + points.col(i) = points.col(i) / points.col(i).norm(); + + //Normalize rotation + MatrixXf refPrev; + referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols()); + float diff = FLT_MAX; + + for (int j = 0; j < points.cols(); j++) { + MatrixXf p = vectorToMatrix(points.col(j)); + MatrixXf R = getRotation(referenceShape, p); + p = p * R.transpose(); + points.col(j) = matrixToVector(p); + } + + referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols()); + } + + void procustesAlgin(const Template &src, Template &dst, MatrixXf p) { + + QList imagePoints = src.file.points(); + MatrixXf p(imagePoints.size() * 2, 1); + for (int i = 0; i < imagePoints.size(); i++) { + + } + } + + void project(const Template &src, Template &dst) const + { + MatrixXf p(src.file.points().size() * 2, 1); + + + // Normalize all sets of points + for (int j = 0; j < data.size(); j++) { + QList imagePoints = data[j].file.points(); + + float meanX = 0, + meanY = 0; + for (int i = 0; i < imagepoints.size(); i++) { + points(i * 2, j) = imagepoints[i].x(); + points(i * 2 + 1, j) = imagepoints[i].y(); + meanX += imagePoints[i].x(); + meanY += imagePoints[i].y(); + } + meanX /= imagePoints.size(); + meanY /= imagePoints.size(); + + for (int i = 0; i < imagePoints.size(); i++) { + points(i * 2, j) -= meanX; + points(i * 2 + 1, j) -= meanY; + } + } + + + //normalize scale + for (int i = 0; i < points.cols(); i++) + points.col(i) = points.col(i) / points.col(i).norm(); + + //Normalize rotation + MatrixXf refPrev; + referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols()); + float diff = FLT_MAX; + + for (int j = 0; j < points.cols(); j++) { + MatrixXf p = vectorToMatrix(points.col(j)); + MatrixXf R = getRotation(referenceShape, p); + p = p * R.transpose(); + points.col(j) = matrixToVector(p); + } + + referenceShape = vectorToMatrix(points.rowwise().sum() / points.cols()); + + } + + void store(QDataStream &stream) const + { + stream << referenceShape; + } + + void load(QDataStream &stream) + { + stream >> referenceShape; + } + +}; + +BR_REGISTER(Transform, ProcrustesAlignTransform) + +/*! * \ingroup transforms * \brief Creates a Delaunay triangulation based on a set of points * \author Scott Klum \cite sklum