[转载]基于MLS( Moving Least Squares)的瘦脸算法

一、原文连接

opencv+c++实现的瘦脸算法_VitowithoutHair的博客-CSDN博客关键思想是《Image Deformation Using Moving Least Squares》这篇论文中提到的方法。实现:1>实现人脸关键点定位2>实现论文中像素点的坐标变换坐标变换源码:void face_lift(Mat &src,const vector& landmarks,int change..._瘦脸算法https://blog.csdn.net/skyqsdyy/article/details/89467143?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-89467143-blog-130638921.235^v38^pc_relevant_default_base&spm=1001.2101.3001.4242.2&utm_relevant_index=4

二、代码整理

Point2f Normalize(Point2f beign, Point2f end)
{
	Point2f vector =beign - end;
	float len = std::sqrt(vector.x * vector.x + vector.y * vector.y);
	return Point2f(vector.x/ len,vector.y / len);
}

//@src:待检测图像
//@landmarks:基于src图像的68个dlib检测点
//@change:瘦脸效果(建议0-5就行,太大就成外星人了)
cv::Mat SkinnyFace_MLS(cv::Mat src, const std::vector landmarks, float change)
{
	//控制点p
	std::vector control_p = { 
		landmarks[0],//脸-开始
		landmarks[3],
		landmarks[7],
		landmarks[10],
		landmarks[13],
		landmarks[16],//脸-结束
		landmarks[33],//鼻子
		landmarks[62]//下巴
	};

	//目的:以鼻子为中心,脸颊往里缩,同时下巴位置不变
	//控制点q   (p和q  一定要是一一对应)
	std::vector control_q = { 
		landmarks[0],
		Point2f(landmarks[3]+ Normalize(landmarks[33],landmarks[3]) *change),
		Point2f(landmarks[7] + Normalize(landmarks[33],landmarks[7]) *change),
		Point2f(landmarks[10] + Normalize(landmarks[33],landmarks[10]) *change),
		Point2f(landmarks[13] + Normalize(landmarks[33],landmarks[13]) *change),
		landmarks[16],
		landmarks[33],
		landmarks[62]
	};

	//变化后的
	Mat dst = src.clone();

	for (int i = 0; i < src.cols; i++)
	{
		for (int j =0; j< src.rows; j++)
		{
			//计算权重
			std::vector weight_p;
			std::vector::iterator itcp = control_p.begin();
			while (itcp != control_p.end())
			{
				double tmp;
				if (itcp->x != i || itcp->y != j)
					tmp = 1 / ((itcp->x - i)*(itcp->x - i) + (itcp->y - j)*(itcp->y - j));
				else
					tmp = INT_MAX;
				weight_p.push_back(tmp);
				++itcp;
			}

			double px = 0, py = 0, qx = 0, qy = 0, tw = 0;
			itcp = control_p.begin();

			std::vector::iterator itwp = weight_p.begin();
			std::vector::iterator itcq = control_q.begin();
			while (itcp != control_p.end())
			{
				px += (*itwp)*(itcp->x);
				py += (*itwp)*(itcp->y);
				qx += (*itwp)*(itcq->x);
				qy += (*itwp)*(itcq->y);

				tw += *itwp;
				++itcp;
				++itcq;
				++itwp;


			}
			px = px / tw;
			py = py / tw;
			qx = qx / tw;
			qy = qy / tw;

			Mat A = Mat::zeros(2, 1, CV_32FC1);
			Mat B = Mat::zeros(1, 2, CV_32FC1);
			Mat C = Mat::zeros(1, 2, CV_32FC1);
			Mat sumL = Mat::zeros(2, 2, CV_32FC1);
			Mat sumR = Mat::zeros(2, 2, CV_32FC1);
			Mat M, pos;
			for (int i = 0; i < weight_p.size(); ++i)
			{
				A.at(0, 0) = (control_p[i].x - px);
				A.at(1, 0) = (control_p[i].y - py);
				B.at(0, 0) = weight_p[i] * ((control_p[i].x - px));
				B.at(0, 1) = weight_p[i] * ((control_p[i].y - py));
				sumL += A * B;
				C.at(0, 0) = weight_p[i] * (control_q[i].x - qx);
				C.at(0, 1) = weight_p[i] * (control_q[i].y - qy);
				sumR += A * C;
			}
			M = sumL.inv()*sumR;

			B.at(0, 0) = i - px;
			B.at(0, 1) = j - py;
			C.at(0, 0) = qx;
			C.at(0, 1) = qy;
			pos = B * M + C;
			int row = pos.at(0, 0);
			int col = pos.at(0, 1);

			//给新位置
			dst.at(col, row)[0] = src.at(j, i)[0];
			dst.at(col, row)[1] = src.at(j, i)[1];
			dst.at(col, row)[2] = src.at(j, i)[2];
		}
	}
	return dst;
}

三、总结

1.能达到瘦脸效果
2.图片质量有所下降,痕迹很严重

[转载]基于MLS( Moving Least Squares)的瘦脸算法_第1张图片

 

你可能感兴趣的:(算法)