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 | 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 | 81 | MatrixXf Y(X.rows() - 1,X.cols() - 1); |
| 82 | 82 | |
| 83 | 83 | for (int i1 = 0, i2 = 0; i1 < X.rows(); i1++) { |
| ... | ... | @@ -96,11 +96,44 @@ MatrixXf removeRowCol(MatrixXf X, int row, int col) { |
| 96 | 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 | 101 | for (int i = 0; i < points.size(); i++) { |
| 102 | 102 | P(i, 0) = points[i].x(); |
| 103 | 103 | P(i, 1) = points[i].y(); |
| 104 | + if (isAffine) | |
| 105 | + P(i, 2) = 1; | |
| 104 | 106 | } |
| 105 | 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 | 29 | void printEigen(Eigen::MatrixXf X); |
| 30 | 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 | 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 | 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 | 43 | template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols> |
| 40 | 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 | 553 | void projectUpdate(const Template &src, Template &dst) |
| 554 | 554 | { |
| 555 | 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 | 53 | Q_PROPERTY(float x3 READ get_x3 WRITE set_x3 RESET reset_x3 STORED false) |
| 54 | 54 | Q_PROPERTY(float y3 READ get_y3 WRITE set_y3 RESET reset_y3 STORED false) |
| 55 | 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 | 57 | BR_PROPERTY(int, width, 64) |
| 57 | 58 | BR_PROPERTY(int, height, 64) |
| 58 | 59 | BR_PROPERTY(float, x1, 0) |
| ... | ... | @@ -62,6 +63,7 @@ private: |
| 62 | 63 | BR_PROPERTY(float, x3, -1) |
| 63 | 64 | BR_PROPERTY(float, y3, -1) |
| 64 | 65 | BR_PROPERTY(Method, method, Bilin) |
| 66 | + BR_PROPERTY(bool, storeAffine, false) | |
| 65 | 67 | |
| 66 | 68 | static Point2f getThirdAffinePoint(const Point2f &a, const Point2f &b) |
| 67 | 69 | { |
| ... | ... | @@ -105,10 +107,17 @@ private: |
| 105 | 107 | } |
| 106 | 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 | 121 | BR_REGISTER(Transform, AffineTransform) |
| 113 | 122 | |
| 114 | 123 | /*! | ... | ... |
openbr/plugins/stasm4.cpp
| 1 | 1 | #include <stasm_lib.h> |
| 2 | 2 | #include <stasmcascadeclassifier.h> |
| 3 | 3 | #include <opencv2/opencv.hpp> |
| 4 | +#include <Eigen/Dense> | |
| 4 | 5 | #include "openbr_internal.h" |
| 5 | 6 | #include "openbr/core/qtutils.h" |
| 6 | 7 | #include "openbr/core/opencvutils.h" |
| 8 | +#include "openbr/core/eigenutils.h" | |
| 7 | 9 | #include <QString> |
| 8 | 10 | |
| 9 | 11 | using namespace std; |
| ... | ... | @@ -160,6 +162,41 @@ class StasmTransform : public UntrainableTransform |
| 160 | 162 | |
| 161 | 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 | 200 | } // namespace br |
| 164 | 201 | |
| 165 | 202 | #include "stasm4.moc" | ... | ... |