Commit 6c39964869c22dfbc3f7251fd128ceeb4ea5c017

Authored by Brendan K
2 parents eb77145e 39a41bb0

Merge pull request #229 from biometrics/AffineRestore

Transform to map stasm points back into original coordinate space
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"