diff --git a/openbr/core/eigenutils.cpp b/openbr/core/eigenutils.cpp index 2bae4cd..e0601d1 100644 --- a/openbr/core/eigenutils.cpp +++ b/openbr/core/eigenutils.cpp @@ -77,7 +77,7 @@ float eigStd(const Eigen::MatrixXf& x) { return sqrt((x.array() - mean).pow(2).sum() / (x.cols() * x.rows())); } -MatrixXf removeRowCol(MatrixXf X, int row, int col) { +MatrixXf removeRowCol(const MatrixXf X, int row, int col) { MatrixXf Y(X.rows() - 1,X.cols() - 1); for (int i1 = 0, i2 = 0; i1 < X.rows(); i1++) { @@ -96,11 +96,44 @@ MatrixXf removeRowCol(MatrixXf X, int row, int col) { return Y; } -MatrixXf pointsToMatrix(QList points) { - MatrixXf P(points.size(), 2); +MatrixXf pointsToMatrix(const QList points, bool isAffine) { + MatrixXf P(points.size(), isAffine ? 3 : 2); for (int i = 0; i < points.size(); i++) { P(i, 0) = points[i].x(); P(i, 1) = points[i].y(); + if (isAffine) + P(i, 2) = 1; } return P; } + +QList matrixToPoints(const Eigen::MatrixXf P) { + QList points; + for (int i = 0; i < P.rows(); i++) + points.append(QPointF(P(i, 0), P(i, 1))); + return points; +} + +//Converts x y points in a single vector to two column matrix +Eigen::MatrixXf vectorToMatrix(const Eigen::MatrixXf vector) { + int n = vector.rows(); + Eigen::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; +} + +Eigen::MatrixXf matrixToVector(const Eigen::MatrixXf matrix) { + int n2 = matrix.rows(); + Eigen::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; +} + diff --git a/openbr/core/eigenutils.h b/openbr/core/eigenutils.h index 50b4b5d..0bbc013 100644 --- a/openbr/core/eigenutils.h +++ b/openbr/core/eigenutils.h @@ -29,12 +29,16 @@ void printEigen(Eigen::MatrixXd X); void printEigen(Eigen::MatrixXf X); void printSize(Eigen::MatrixXf X); +//Converts x y points in a single vector to two column matrix +Eigen::MatrixXf vectorToMatrix(const Eigen::MatrixXf vector); +Eigen::MatrixXf matrixToVector(const Eigen::MatrixXf matrix); + //Remove row and column from the matrix: -Eigen::MatrixXf removeRowCol(Eigen::MatrixXf X, int row, int col); +Eigen::MatrixXf removeRowCol(const Eigen::MatrixXf X, int row, int col); //Convert a point list into a matrix: -Eigen::MatrixXf pointsToMatrix(QList points); - +Eigen::MatrixXf pointsToMatrix(const QList points, bool isAffine=false); +QList matrixToPoints(const Eigen::MatrixXf P); template inline QDataStream &operator<<(QDataStream &stream, const Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > &mat) diff --git a/openbr/plugins/draw.cpp b/openbr/plugins/draw.cpp index bb5f8a9..27b93b6 100644 --- a/openbr/plugins/draw.cpp +++ b/openbr/plugins/draw.cpp @@ -553,7 +553,7 @@ class WriteImageTransform : public TimeVaryingTransform void projectUpdate(const Template &src, Template &dst) { dst = src; - OpenCVUtils::saveImage(dst.m(), QString("%1/%2_%3.%4").arg(outputDirectory).arg(imageName).arg(cnt++, 5, QChar('0')).arg(imgExtension)); + OpenCVUtils::saveImage(dst.m(), QString("%1/%2_%3.%4").arg(outputDirectory).arg(imageName).arg(cnt++, 5, 10, QChar('0')).arg(imgExtension)); } }; diff --git a/openbr/plugins/register.cpp b/openbr/plugins/register.cpp index 9ff9422..485d56c 100644 --- a/openbr/plugins/register.cpp +++ b/openbr/plugins/register.cpp @@ -53,6 +53,7 @@ private: Q_PROPERTY(float x3 READ get_x3 WRITE set_x3 RESET reset_x3 STORED false) Q_PROPERTY(float y3 READ get_y3 WRITE set_y3 RESET reset_y3 STORED false) Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) + Q_PROPERTY(bool storeAffine READ get_storeAffine WRITE set_storeAffine RESET reset_storeAffine STORED false) BR_PROPERTY(int, width, 64) BR_PROPERTY(int, height, 64) BR_PROPERTY(float, x1, 0) @@ -62,6 +63,7 @@ private: BR_PROPERTY(float, x3, -1) BR_PROPERTY(float, y3, -1) BR_PROPERTY(Method, method, Bilin) + BR_PROPERTY(bool, storeAffine, false) static Point2f getThirdAffinePoint(const Point2f &a, const Point2f &b) { @@ -105,10 +107,17 @@ private: } if (twoPoints) srcPoints[2] = getThirdAffinePoint(srcPoints[0], srcPoints[1]); - warpAffine(src, dst, getAffineTransform(srcPoints, dstPoints), Size(width, height), method); + Mat affineTransform = getAffineTransform(srcPoints, dstPoints); + warpAffine(src, dst, affineTransform, Size(width, height), method); + if (storeAffine) { + QList affineParams; + for (int i = 0 ; i < 2; i++) + for (int j = 0; j < 3; j++) + affineParams.append(affineTransform.at(i, j)); + dst.file.setList("affineParameters", affineParams); + } } }; - BR_REGISTER(Transform, AffineTransform) /*! diff --git a/openbr/plugins/stasm4.cpp b/openbr/plugins/stasm4.cpp index d81655f..2c2139c 100644 --- a/openbr/plugins/stasm4.cpp +++ b/openbr/plugins/stasm4.cpp @@ -1,9 +1,11 @@ #include #include #include +#include #include "openbr_internal.h" #include "openbr/core/qtutils.h" #include "openbr/core/opencvutils.h" +#include "openbr/core/eigenutils.h" #include using namespace std; @@ -160,6 +162,41 @@ class StasmTransform : public UntrainableTransform BR_REGISTER(Transform, StasmTransform) +/*! + * \ingroup transforms + * \brief Designed for use after eye detection + Stasm, this will + * revert the detected landmarks to the original coordinate space + * before affine alignment to the stasm mean shape. The storeTransform + * parameter must be set to true when calling AffineTransform before this. + * \author Brendan Klare \cite bklare + */ +class RevertAffineTransform : public UntrainableTransform +{ + Q_OBJECT + +private: + + void project(const Template &src, Template &dst) const + { + QList paramList = src.file.getList("affineParameters"); + Eigen::MatrixXf points = pointsToMatrix(src.file.points(), true); + Eigen::MatrixXf affine = Eigen::MatrixXf::Zero(3, 3); + for (int i = 0, cnt = 0; i < 2; i++) + for (int j = 0; j < 3; j++, cnt++) + affine(i, j) = paramList[cnt]; + affine(2, 2) = 1; + affine = affine.inverse(); + Eigen::MatrixXf affineInv = affine.block(0, 0, 2, 3); + Eigen::MatrixXf pointsT = points.transpose(); + points = affineInv * pointsT; + dst = src; + dst.file.clearPoints(); + dst.file.setPoints(matrixToPoints(points.transpose())); + } +}; + +BR_REGISTER(Transform, RevertAffineTransform) + } // namespace br #include "stasm4.moc"