实现瘦脸算法

一.瘦脸算法实现包括三部分: 1.人脸关键点识别。2.计算瘦脸区域点之间的映射。3.双线性插值实现对应坐标颜色的映射。

1.人脸关键点识别(暂时省略):

2.坐标点的映射:

void LocalTranslationWarp_Eye(Mat &img, Mat &dst, int warpX, int warpY, int endX, int endY, float radius)
{

	//平移距离 
	float ddradius = radius * radius;
	//计算|m-c|^2
	size_t mc = (endX - warpX)*(endX - warpX) + (endY - warpY)*(endY - warpY);  //计算两个点距离的平方
	//计算 图像的高  宽 通道数量
	int height = img.rows;
	int width = img.cols;
	int chan = img.channels();

	auto Abs = [&](float f) {     //取绝对值
		return f > 0 ? f : -f;
	};

	for (int j = 0; j < height; j++)
	{
		for (int i = 0; i < width; i++)
		{
			// # 计算该点是否在形变圆的范围之内
			//# 优化,第一步,直接判断是会在(startX, startY)的矩阵框中
			if ((Abs(i - warpX) > radius) && (Abs(j - warpY) > radius))
				continue;

			float distance = (i - warpX)*(i - warpX) + (j - warpY)*(j - warpY);    //取当前点到变换起始点的距离
			if (distance < ddradius)      //如果处在变换圆的范围内
			{
				//float rnorm = sqrt(distance) / radius;     //当前点与变形圆半径的比值
				//float ratio = 1 - (rnorm - 1)*(rnorm - 1)*0.5;
				映射原位置
				//float UX = warpX + ratio * (i - warpX);
				//float UY = warpY + ratio * (j - warpY);
				float radio = (ddradius - distance) / (ddradius - distance + mc);
				radio = radio * radio;

				float UX = i - radio * (endX - warpX);
				float UY = j - radio * (endY - warpY);

				if (UX < 0 || UY < 0) {
					std::cout << "出错了" << std::endl;
				}
				
				//根据双线性插值得到UX UY的值
				BilinearInsert(img, dst, UX, UY, i, j);
			}
		}
	}
}

3.双线性插值:

void BilinearInsert(Mat &src, Mat &dst, float ux, float uy, int i, int j)
{
	auto Abs = [&](float f) {
		return f > 0 ? f : -f;
	};

	int c = src.channels();
	if (c == 3)
	{
		//存储图像得浮点坐标
		cv::Point3f uv;
		cv::Point3f f1;
		cv::Point3f f2;
		
			
		//取整数
		int iu = (int)ux;
		int iv = (int)uy;
		uv.x = iu + 1;
		uv.y = iv + 1;


		//上面行插值
		f1.x = ((uchar*)(src.data + src.step*iv))[iu * 3] * (1 - Abs(ux - iu)) + \
			((uchar*)(src.data + src.step*iv))[(iu + 1) * 3] * (ux - iu);
		f1.y = ((uchar*)(src.data + src.step*iv))[iu * 3 + 1] * (1 - Abs(ux - iu)) + \
			((uchar*)(src.data + src.step*iv))[(iu + 1) * 3 + 1] * (ux - iu);
		f1.z = ((uchar*)(src.data + src.step*iv))[iu * 3 + 2] * (1 - Abs(ux - iu)) + \
			((uchar*)(src.data + src.step*iv))[(iu + 1) * 3 + 2] * (ux - iu);



		//下面行插值
		f2.x = ((uchar*)(src.data + src.step*(iv + 1)))[iu * 3] * (1 - Abs(ux - iu)) + \
			((uchar*)(src.data + src.step*(iv + 1)))[(iu + 1) * 3] * (ux - iu);
		f2.y = ((uchar*)(src.data + src.step*(iv + 1)))[iu * 3 + 1] * (1 - Abs(ux - iu)) + \
			((uchar*)(src.data + src.step*(iv + 1)))[(iu + 1) * 3 + 1] * (ux - iu);
		f2.z = ((uchar*)(src.data + src.step*(iv + 1)))[iu * 3 + 2] * (1 - Abs(ux - iu)) + \
			((uchar*)(src.data + src.step*(iv + 1)))[(iu + 1) * 3 + 2] * (ux - iu);


		//int tempNum = f1.x*(1 - Abs(uv.y - iv)) + f2.x*(Abs(uv.y - iv));
		((uchar*)(dst.data + dst.step*j))[i * 3] = f1.x*(1 - Abs(uy - iv)) + f2.x*(Abs(uy - iv));  //三个通道进行赋值
		((uchar*)(dst.data + dst.step*j))[i * 3 + 1] = f1.y*(1 - Abs(uy - iv)) + f2.y*(Abs(uy - iv));
		((uchar*)(dst.data + dst.step*j))[i * 3 + 2] = f1.z*(1 - Abs(uy - iv)) + f2.z*(Abs(uy - iv));

	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值