Commit 6c39964869c22dfbc3f7251fd128ceeb4ea5c017
Merge pull request #229 from biometrics/AffineRestore
Transform to map stasm points back into original coordinate space
Showing
5 changed files
with
92 additions
and
9 deletions
openbr/core/eigenutils.cpp
| @@ -77,7 +77,7 @@ float eigStd(const Eigen::MatrixXf& x) { | @@ -77,7 +77,7 @@ float eigStd(const Eigen::MatrixXf& x) { | ||
| 77 | return sqrt((x.array() - mean).pow(2).sum() / (x.cols() * x.rows())); | 77 | return sqrt((x.array() - mean).pow(2).sum() / (x.cols() * x.rows())); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | -MatrixXf removeRowCol(MatrixXf X, int row, int col) { | 80 | +MatrixXf removeRowCol(const MatrixXf X, int row, int col) { |
| 81 | MatrixXf Y(X.rows() - 1,X.cols() - 1); | 81 | MatrixXf Y(X.rows() - 1,X.cols() - 1); |
| 82 | 82 | ||
| 83 | for (int i1 = 0, i2 = 0; i1 < X.rows(); i1++) { | 83 | for (int i1 = 0, i2 = 0; i1 < X.rows(); i1++) { |
| @@ -96,11 +96,44 @@ MatrixXf removeRowCol(MatrixXf X, int row, int col) { | @@ -96,11 +96,44 @@ MatrixXf removeRowCol(MatrixXf X, int row, int col) { | ||
| 96 | return Y; | 96 | return Y; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | -MatrixXf pointsToMatrix(QList<QPointF> points) { | ||
| 100 | - MatrixXf P(points.size(), 2); | 99 | +MatrixXf pointsToMatrix(const QList<QPointF> points, bool isAffine) { |
| 100 | + MatrixXf P(points.size(), isAffine ? 3 : 2); | ||
| 101 | for (int i = 0; i < points.size(); i++) { | 101 | for (int i = 0; i < points.size(); i++) { |
| 102 | P(i, 0) = points[i].x(); | 102 | P(i, 0) = points[i].x(); |
| 103 | P(i, 1) = points[i].y(); | 103 | P(i, 1) = points[i].y(); |
| 104 | + if (isAffine) | ||
| 105 | + P(i, 2) = 1; | ||
| 104 | } | 106 | } |
| 105 | return P; | 107 | return P; |
| 106 | } | 108 | } |
| 109 | + | ||
| 110 | +QList<QPointF> matrixToPoints(const Eigen::MatrixXf P) { | ||
| 111 | + QList<QPointF> points; | ||
| 112 | + for (int i = 0; i < P.rows(); i++) | ||
| 113 | + points.append(QPointF(P(i, 0), P(i, 1))); | ||
| 114 | + return points; | ||
| 115 | +} | ||
| 116 | + | ||
| 117 | +//Converts x y points in a single vector to two column matrix | ||
| 118 | +Eigen::MatrixXf vectorToMatrix(const Eigen::MatrixXf vector) { | ||
| 119 | + int n = vector.rows(); | ||
| 120 | + Eigen::MatrixXf matrix(n / 2, 2); | ||
| 121 | + for (int i = 0; i < n / 2; i++) { | ||
| 122 | + for (int j = 0; j < 2; j++) { | ||
| 123 | + matrix(i, j) = vector(i * 2 + j); | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + return matrix; | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +Eigen::MatrixXf matrixToVector(const Eigen::MatrixXf matrix) { | ||
| 130 | + int n2 = matrix.rows(); | ||
| 131 | + Eigen::MatrixXf vector(n2 * 2, 1); | ||
| 132 | + for (int i = 0; i < n2; i++) { | ||
| 133 | + for (int j = 0; j < 2; j++) { | ||
| 134 | + vector(i * 2 + j) = matrix(i, j); | ||
| 135 | + } | ||
| 136 | + } | ||
| 137 | + return vector; | ||
| 138 | +} | ||
| 139 | + |
openbr/core/eigenutils.h
| @@ -29,12 +29,16 @@ void printEigen(Eigen::MatrixXd X); | @@ -29,12 +29,16 @@ void printEigen(Eigen::MatrixXd X); | ||
| 29 | void printEigen(Eigen::MatrixXf X); | 29 | void printEigen(Eigen::MatrixXf X); |
| 30 | void printSize(Eigen::MatrixXf X); | 30 | void printSize(Eigen::MatrixXf X); |
| 31 | 31 | ||
| 32 | +//Converts x y points in a single vector to two column matrix | ||
| 33 | +Eigen::MatrixXf vectorToMatrix(const Eigen::MatrixXf vector); | ||
| 34 | +Eigen::MatrixXf matrixToVector(const Eigen::MatrixXf matrix); | ||
| 35 | + | ||
| 32 | //Remove row and column from the matrix: | 36 | //Remove row and column from the matrix: |
| 33 | -Eigen::MatrixXf removeRowCol(Eigen::MatrixXf X, int row, int col); | 37 | +Eigen::MatrixXf removeRowCol(const Eigen::MatrixXf X, int row, int col); |
| 34 | 38 | ||
| 35 | //Convert a point list into a matrix: | 39 | //Convert a point list into a matrix: |
| 36 | -Eigen::MatrixXf pointsToMatrix(QList<QPointF> points); | ||
| 37 | - | 40 | +Eigen::MatrixXf pointsToMatrix(const QList<QPointF> points, bool isAffine=false); |
| 41 | +QList<QPointF> matrixToPoints(const Eigen::MatrixXf P); | ||
| 38 | 42 | ||
| 39 | template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> | 43 | template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> |
| 40 | inline QDataStream &operator<<(QDataStream &stream, const Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > &mat) | 44 | inline QDataStream &operator<<(QDataStream &stream, const Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > &mat) |
openbr/plugins/draw.cpp
| @@ -553,7 +553,7 @@ class WriteImageTransform : public TimeVaryingTransform | @@ -553,7 +553,7 @@ class WriteImageTransform : public TimeVaryingTransform | ||
| 553 | void projectUpdate(const Template &src, Template &dst) | 553 | void projectUpdate(const Template &src, Template &dst) |
| 554 | { | 554 | { |
| 555 | dst = src; | 555 | dst = src; |
| 556 | - OpenCVUtils::saveImage(dst.m(), QString("%1/%2_%3.%4").arg(outputDirectory).arg(imageName).arg(cnt++, 5, QChar('0')).arg(imgExtension)); | 556 | + OpenCVUtils::saveImage(dst.m(), QString("%1/%2_%3.%4").arg(outputDirectory).arg(imageName).arg(cnt++, 5, 10, QChar('0')).arg(imgExtension)); |
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | }; | 559 | }; |
openbr/plugins/register.cpp
| @@ -53,6 +53,7 @@ private: | @@ -53,6 +53,7 @@ private: | ||
| 53 | Q_PROPERTY(float x3 READ get_x3 WRITE set_x3 RESET reset_x3 STORED false) | 53 | Q_PROPERTY(float x3 READ get_x3 WRITE set_x3 RESET reset_x3 STORED false) |
| 54 | Q_PROPERTY(float y3 READ get_y3 WRITE set_y3 RESET reset_y3 STORED false) | 54 | Q_PROPERTY(float y3 READ get_y3 WRITE set_y3 RESET reset_y3 STORED false) |
| 55 | Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) | 55 | Q_PROPERTY(Method method READ get_method WRITE set_method RESET reset_method STORED false) |
| 56 | + Q_PROPERTY(bool storeAffine READ get_storeAffine WRITE set_storeAffine RESET reset_storeAffine STORED false) | ||
| 56 | BR_PROPERTY(int, width, 64) | 57 | BR_PROPERTY(int, width, 64) |
| 57 | BR_PROPERTY(int, height, 64) | 58 | BR_PROPERTY(int, height, 64) |
| 58 | BR_PROPERTY(float, x1, 0) | 59 | BR_PROPERTY(float, x1, 0) |
| @@ -62,6 +63,7 @@ private: | @@ -62,6 +63,7 @@ private: | ||
| 62 | BR_PROPERTY(float, x3, -1) | 63 | BR_PROPERTY(float, x3, -1) |
| 63 | BR_PROPERTY(float, y3, -1) | 64 | BR_PROPERTY(float, y3, -1) |
| 64 | BR_PROPERTY(Method, method, Bilin) | 65 | BR_PROPERTY(Method, method, Bilin) |
| 66 | + BR_PROPERTY(bool, storeAffine, false) | ||
| 65 | 67 | ||
| 66 | static Point2f getThirdAffinePoint(const Point2f &a, const Point2f &b) | 68 | static Point2f getThirdAffinePoint(const Point2f &a, const Point2f &b) |
| 67 | { | 69 | { |
| @@ -105,10 +107,17 @@ private: | @@ -105,10 +107,17 @@ private: | ||
| 105 | } | 107 | } |
| 106 | if (twoPoints) srcPoints[2] = getThirdAffinePoint(srcPoints[0], srcPoints[1]); | 108 | if (twoPoints) srcPoints[2] = getThirdAffinePoint(srcPoints[0], srcPoints[1]); |
| 107 | 109 | ||
| 108 | - warpAffine(src, dst, getAffineTransform(srcPoints, dstPoints), Size(width, height), method); | 110 | + Mat affineTransform = getAffineTransform(srcPoints, dstPoints); |
| 111 | + warpAffine(src, dst, affineTransform, Size(width, height), method); | ||
| 112 | + if (storeAffine) { | ||
| 113 | + QList<float> affineParams; | ||
| 114 | + for (int i = 0 ; i < 2; i++) | ||
| 115 | + for (int j = 0; j < 3; j++) | ||
| 116 | + affineParams.append(affineTransform.at<double>(i, j)); | ||
| 117 | + dst.file.setList("affineParameters", affineParams); | ||
| 118 | + } | ||
| 109 | } | 119 | } |
| 110 | }; | 120 | }; |
| 111 | - | ||
| 112 | BR_REGISTER(Transform, AffineTransform) | 121 | BR_REGISTER(Transform, AffineTransform) |
| 113 | 122 | ||
| 114 | /*! | 123 | /*! |
openbr/plugins/stasm4.cpp
| 1 | #include <stasm_lib.h> | 1 | #include <stasm_lib.h> |
| 2 | #include <stasmcascadeclassifier.h> | 2 | #include <stasmcascadeclassifier.h> |
| 3 | #include <opencv2/opencv.hpp> | 3 | #include <opencv2/opencv.hpp> |
| 4 | +#include <Eigen/Dense> | ||
| 4 | #include "openbr_internal.h" | 5 | #include "openbr_internal.h" |
| 5 | #include "openbr/core/qtutils.h" | 6 | #include "openbr/core/qtutils.h" |
| 6 | #include "openbr/core/opencvutils.h" | 7 | #include "openbr/core/opencvutils.h" |
| 8 | +#include "openbr/core/eigenutils.h" | ||
| 7 | #include <QString> | 9 | #include <QString> |
| 8 | 10 | ||
| 9 | using namespace std; | 11 | using namespace std; |
| @@ -160,6 +162,41 @@ class StasmTransform : public UntrainableTransform | @@ -160,6 +162,41 @@ class StasmTransform : public UntrainableTransform | ||
| 160 | 162 | ||
| 161 | BR_REGISTER(Transform, StasmTransform) | 163 | BR_REGISTER(Transform, StasmTransform) |
| 162 | 164 | ||
| 165 | +/*! | ||
| 166 | + * \ingroup transforms | ||
| 167 | + * \brief Designed for use after eye detection + Stasm, this will | ||
| 168 | + * revert the detected landmarks to the original coordinate space | ||
| 169 | + * before affine alignment to the stasm mean shape. The storeTransform | ||
| 170 | + * parameter must be set to true when calling AffineTransform before this. | ||
| 171 | + * \author Brendan Klare \cite bklare | ||
| 172 | + */ | ||
| 173 | +class RevertAffineTransform : public UntrainableTransform | ||
| 174 | +{ | ||
| 175 | + Q_OBJECT | ||
| 176 | + | ||
| 177 | +private: | ||
| 178 | + | ||
| 179 | + void project(const Template &src, Template &dst) const | ||
| 180 | + { | ||
| 181 | + QList<float> paramList = src.file.getList<float>("affineParameters"); | ||
| 182 | + Eigen::MatrixXf points = pointsToMatrix(src.file.points(), true); | ||
| 183 | + Eigen::MatrixXf affine = Eigen::MatrixXf::Zero(3, 3); | ||
| 184 | + for (int i = 0, cnt = 0; i < 2; i++) | ||
| 185 | + for (int j = 0; j < 3; j++, cnt++) | ||
| 186 | + affine(i, j) = paramList[cnt]; | ||
| 187 | + affine(2, 2) = 1; | ||
| 188 | + affine = affine.inverse(); | ||
| 189 | + Eigen::MatrixXf affineInv = affine.block(0, 0, 2, 3); | ||
| 190 | + Eigen::MatrixXf pointsT = points.transpose(); | ||
| 191 | + points = affineInv * pointsT; | ||
| 192 | + dst = src; | ||
| 193 | + dst.file.clearPoints(); | ||
| 194 | + dst.file.setPoints(matrixToPoints(points.transpose())); | ||
| 195 | + } | ||
| 196 | +}; | ||
| 197 | + | ||
| 198 | +BR_REGISTER(Transform, RevertAffineTransform) | ||
| 199 | + | ||
| 163 | } // namespace br | 200 | } // namespace br |
| 164 | 201 | ||
| 165 | #include "stasm4.moc" | 202 | #include "stasm4.moc" |