人脸相关应用的重要预处理,very useful!
// find affine transformation between two pointsets (use least square matching)
bool computeAffine(const vector<Point2f> &srcPoints, const vector<Point2f> &dstPoints, Mat &transf)
{
// sanity check
if ((srcPoints.size() < 3) || (srcPoints.size() != dstPoints.size()))
return false;
// container for output
transf.create(2, 3, CV_32F);
// fill the matrices
const int n = (int)srcPoints.size(), m = 3;
Mat A(n,m,CV_32F), xc(n,1,CV_32F), yc(n,1,CV_32F);
for(int i=0; i<n; i++)
{
float x = srcPoints[i].x, y = srcPoints[i].y;
float rowI[m] = {x, y, 1};
Mat(1,m,CV_32F,rowI).copyTo(A.row(i));
xc.at<float>(i,0) = dstPoints[i].x;
yc.at<float>(i,0) = dstPoints[i].y;
}
// solve linear equations (for x and for y)
Mat aTa, resX, resY;
mulTransposed(A, aTa, true);
solve(aTa, A.t()*xc, resX, DECOMP_CHOLESKY);
solve(aTa, A.t()*yc, resY, DECOMP_CHOLESKY);
// store result
memcpy(transf.ptr<float>(0), resX.data, m*sizeof(float));
memcpy(transf.ptr<float>(1), resY.data, m*sizeof(float));
return true;
}
int faceAlign(Mat src, Mat &output, vector<Point2f> pointSrc)
{
if(!src.data)
{
cout << "image not read properly" << endl;
return -1;
}
// Dimensions of output image
int w = 200;
int h = 200;
vector<Point2f> pointDst;
pointDst.push_back(Point2f( 64, 100)); //左眼角
pointDst.push_back(Point2f( 136, 100)); //右眼角
pointDst.push_back(Point2f(100,130)); //鼻尖
pointDst.push_back(Point2f(68,150)); //左嘴角
pointDst.push_back(Point2f(132,150)); //右嘴角
// Calculate similarity transform
Mat tform;
computeAffine(pointSrc, pointDst, tform);
// Apply transform to input image
Mat AffineImg = Mat::zeros(h, w, CV_32FC3);
warpAffine(src, AffineImg, tform, AffineImg.size());
output = AffineImg;
imshow("img", AffineImg);
//waitKey();
return 1;
}