基础知识(五)对齐变换相关函数

在机器学习、图像处理中,经常要计算两个特征向量之间形状的距离,比如我用face++检测到两张人脸的特征点数据,我们要用人脸的特征点计算出这两张人脸的之间的相似度,这个时候我们就需要对这两张人脸进行对齐操作,就是AAM算法中的Procrustes Analysis对齐算法。这个是基础算法,因此在这里做一下笔记,贴一下代码,以便日后调用,因为最近搞项目,老是用到这个算法。

一、固定两点对齐


假如我要计算线段PQ变换成P'Q'的变换矩阵,那么我首先要计算计算向量PQ和向量P'Q'的变换矩阵(旋转和缩放),然后再以P点为源点,把P点平移到P'点。因此过程分成两步:

1、计算向量间的变换矩阵

<span style="font-size:18px;">//计算两个线段之间的变换矩阵,求解线段(Line2P,Line2Q)往(Line1P,Line1Q)的变换矩阵
Eigen::Matrix2d CSearchFace::Transform_Line_Segment(cv::Vec2f Line1P,cv::Vec2f Line1Q,cv::Vec2f Line2P,cv::Vec2f Line2Q)
{
	Eigen::Vector2d A;
	Eigen::Vector2d B;
	A(0)=Line1P[0];
	A(1)=Line1P[1];
	B(0)=Line1Q[0];
	B(1)=Line1Q[1];

	Eigen::Vector2d C;
	Eigen::Vector2d D;
	C(0)=Line2P[0];
	C(1)=Line2P[1];
	D(0)=Line2Q[0];
	D(1)=Line2Q[1];

	Eigen::Vector2d cd=D-C;
	Eigen::Vector2d ab=B-A;

	Eigen::Matrix2d cof;
	cof(0,0)=cd(0);
	cof(0,1)=cd(1);
	cof(1,0)=cd(1);
	cof(1,1)=-cd(0);
	Eigen::Vector2d tr=cof.inverse()*ab;

	cof(0,0)=tr(0);
	cof(0,1)=tr(1);
	cof(1,0)=-tr(1);
	cof(1,1)=tr(0);

	return cof;

}</span>

2、平移变换。

下面以人脸特征点的对齐为例子,计算两个人脸特征点之间的相似度,因为最近做到的项目是参考文献《Data-Driven Face Cartoon Stylization》的算法,里面涉及到从脸型库里面寻找与用户输入的人脸最相似的脸型。在第4部分的第4段,Chin and mouth的算法,脸庞之间距离的计算方法是通过固定脸庞上的两个顶点,然后进行计算距离,因此我把代码贴一下:

//算法通过固定脸庞上的1、13号点,对这两个点进行变换对齐,然后计算1~13号点之间的距离总和
float CSearchFace::GetFaceDistance(vector<cv::Vec2f>face1_landmark,vector<cv::Vec2f>face2_landmark)
{
	float sum_dis=0;
	vector<cv::Vec2f>result0;
	//计算向量间的变换矩阵
	Eigen::Matrix2d tm=Transform_Line_Segment(face1_landmark[1],face1_landmark[13],face2_landmark[1],face2_landmark[13]);
	//平移
	Eigen::Vector2d Line1P(face2_landmark[1][0],face2_landmark[1][1]);
	Eigen::Vector2d Movv(face1_landmark[1][0],face1_landmark[1][1]);
	for (int i=1;i<14;i++)
	{
		Eigen::Vector2d pt(face2_landmark[i][0],face2_landmark[i][1]);
		Eigen::Vector2d dst_point_eigen=pt-Line1P;
		Eigen::Vector2d src_point_eigen=tm*dst_point_eigen+Movv;//变换后的点
		result0.push_back(cv::Vec2f(src_point_eigen(0),src_point_eigen(1)));//最后的结果
		
		//距离计算
		cv::Vec2f disv=cv::Vec2f(src_point_eigen(0),src_point_eigen(1))-face1_landmark[i];
		sum_dis+=sqrt(disv[0]*disv[0]+disv[1]*disv[1]);
	}
	m_restul=result0;
	return sum_dis;

}
二、相似变换对齐

Data-Driven Face Cartoon Stylization》的算法嘴部的对齐算法与脸庞的对齐算法不一样,嘴部是通过相似变换的算法实现的。或者称之为仿射变换

python 版本:

def transformation_from_points(points1, points2):
    """
    Return an affine transformation [s * R | T] such that:
        sum ||s*R*p1,i + T - p2,i||^2
    is minimized.
    """

    points1 = points1.astype(numpy.float64)
    points2 = points2.astype(numpy.float64)

    c1 = numpy.mean(points1, axis=0)
    c2 = numpy.mean(points2, axis=0)
    points1 -= c1
    points2 -= c2

    s1 = numpy.std(points1)
    s2 = numpy.std(points2)
    points1 /= s1
    points2 /= s2

    U, S, Vt = numpy.linalg.svd(points1.T * points2)


    R = (U * Vt).T

    return numpy.vstack([numpy.hstack(((s2 / s1) * R,
                                       c2.T - (s2 / s1) * R * c1.T)),
                         numpy.matrix([0., 0., 1.])])

c++版本:

//把src往ref进行变换对齐
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> CSearchMouth::Similarity_transform_2d(vector<Vector2> src,vector<Vector2>ref, vector<Vector2>&dst)
{

	int count=ref.size();
	dst.resize(count);
	assert(count >= 3);
	Eigen::Matrix<float, Dynamic, Dynamic> A(2 * count, 4), X, B(2 * count, 1), S;
	for (int i = 0; i < count; i++)
	{
		A(i, 0) = src[i].x;
		A(i, 1) = src[i].y;
		A(i, 2) = 1;
		A(i, 3) = 0;
		A(i + count, 0) = src[i].y;
		A(i + count, 1) = -src[i].x;
		A(i + count, 2) = 0;
		A(i + count, 3) = 1;
		B(i, 0) = ref[i].x;
		B(i + count, 0) = ref[i].y;
	}
	X = A.jacobiSvd(ComputeThinU | ComputeThinV).solve(B);
	Eigen::Matrix<float, 2, 3> M;
	M << X(0, 0), X(1, 0), X(2, 0), -X(1, 0), X(0, 0), X(3, 0);



	for (int i = 0; i < count; i++)
	{
		dst[i].x = M(0, 0) * src[i].x + M(0, 1) * src[i].y + M(0, 2);
		dst[i].y = M(1, 0) * src[i].x + M(1, 1) * src[i].y + M(1, 2);
	}
	return M;
}
本文地址:http://blog.csdn.net/hjimce/article/details/47019223     作者:hjimce     联系qq:1393852684   更多资源请关注我的博客:http://blog.csdn.net/hjimce                原创文章,转载请保留本行信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值