[转载]基于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<Point2f> landmarks, float change)
{
	//控制点p
	std::vector<cv::Point2f> control_p = { 
		landmarks[0],//脸-开始
		landmarks[3],
		landmarks[7],
		landmarks[10],
		landmarks[13],
		landmarks[16],//脸-结束
		landmarks[33],//鼻子
		landmarks[62]//下巴
	};

	//目的:以鼻子为中心,脸颊往里缩,同时下巴位置不变
	//控制点q   (p和q  一定要是一一对应)
	std::vector<cv::Point2f> 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<float> weight_p;
			std::vector<Point2f>::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<float>::iterator itwp = weight_p.begin();
			std::vector<Point2f>::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<float>(0, 0) = (control_p[i].x - px);
				A.at<float>(1, 0) = (control_p[i].y - py);
				B.at<float>(0, 0) = weight_p[i] * ((control_p[i].x - px));
				B.at<float>(0, 1) = weight_p[i] * ((control_p[i].y - py));
				sumL += A * B;
				C.at<float>(0, 0) = weight_p[i] * (control_q[i].x - qx);
				C.at<float>(0, 1) = weight_p[i] * (control_q[i].y - qy);
				sumR += A * C;
			}
			M = sumL.inv()*sumR;

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

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

三、总结

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

 

<think>首先,用户的问题是:“我想查找与瘦脸相关的函数或实现方法 请问图像处理中瘦脸效果的算法或函数实现”。这直接询问图像处理中瘦脸效果的算法或函数实现。 从系统级指令中,我需要: - 使用中文回答。 - 所有行内数学表达式用 $...$ 格式。 - 独立公式用 $$...$$ 格式并单独成段。 - LaTeX语法正确。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如 [^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 参考提供的引用: - 引用[1]:提到了美白、磨皮、瘦脸、大眼等算法,其中瘦脸基于液化算法并用dlib提取特征点。 - 引用[2]:讨论了Android修图处理算法,使用drawBitmapMesh算法实现瘦脸效果,参考了Interactive Image Warping文献。 - 引用[3]:记录了图像处理中的瘦脸算法,使用MLS算法C++中实现。 这些引用提供了瘦脸算法的具体方法:液化算法MLS算法Moving Least Squares),以及使用dlib提取特征点。 我的回答应该基于这些信息,但要确保真实可靠。瘦脸效果在图像处理中通常涉及图像变形(image warping),具体方法包括: - **液化算法(Liquify Algorithm)**:常用于Photoshop等软件中,通过移动像素来实现变形。 - **MLS算法Moving Least Squares)**:一种基于特征点的图像变形方法,用于平滑变形。 - **使用dlib提取特征点**:dlib是一个机器学习库,常用于人脸检测和特征点定位。 步骤: 1. **介绍瘦脸效果的基本原理**:解释图像变形如何实现瘦脸。 2. **描述常见算法**:基于引用,讨论液化算法MLS算法等。 3. **提供实现方法**:简要说明如何实现,包括函数或代码示例(如果可能)。 4. **添加引用标识**:在适当的地方添加引用。 5. **生成相关问题**:在最后添加相关问题部分。 回答结构: - 开头:简要介绍瘦脸效果。 - 主体:分步解释算法和实现。 - 结尾:总结并生成相关问题。 确保使用中文。 数学表达式:如果有数学部分,比如变形公式,用LaTeX格式。例如,图像变形可能涉及坐标变换。 可能的数学内容: - 对于MLS算法,可能有公式如:$$ \mathbf{p}' = \mathbf{p} + \sum_{i} w_i(\mathbf{p}) \mathbf{v}_i $$ 其中 $\mathbf{p}$ 是原坐标,$\mathbf{p}'$ 是变形后的坐标,$w_i$ 是权重函数,$\mathbf{v}_i$ 是变形向量。 但不要过度添加数学;只在必要时。 实现方法: - 提到使用OpenCV、dlib等库。 - 给出伪代码或简单代码示例(如Python使用OpenCV)。 引用标识: - 当提到引用内容时,添加 [^1], [^2], [^3]。 - 例如:“根据引用[1],瘦脸算法基于液化算法并用dlib提取特征点。” 生成相关问题: - 在最后,添加“§§相关问题§§”部分,列出3-5个相关问题。 - 例如:瘦脸算法的优化、其他应用、性能分析等。 最终回答结构: 1. 引言:解释瘦脸效果。 2. 算法原理:描述主要算法。 3. 实现方法:提供函数或代码思路。 4. 引用总结。 5. 相关问题。</think>### 图像处理中瘦脸效果的算法及实现方法 瘦脸效果是数字图像处理中的一种常见应用,主要用于美化人像,通过局部变形使脸部轮廓显得更瘦。其核心原理是基于图像变形(image warping),通过移动像素点来实现局部区域的收缩。下面我将逐步解释瘦脸效果的算法原理、实现方法及相关函数,确保回答基于真实可靠的图像处理技术。实现中常使用库如 OpenCV、dlib 和 Android SDK。 #### 1. **瘦脸效果的基本原理** 瘦脸算法通过检测人脸关键点(如脸颊、下巴),然后对这些点施加变形力,使目标区域向内收缩。变形过程需要平滑过渡以避免图像失真。数学上,这涉及坐标变换:给定原图像点 $\mathbf{p} = (x, y)$,变形后点 $\mathbf{p}' = (x', y')$ 通过加权函数计算: $$ \mathbf{p}' = \mathbf{p} + \sum_{i=1}^{n} w_i(\mathbf{p}) \cdot \mathbf{v}_i $$ 其中 $\mathbf{v}_i$ 是变形向量(表示收缩方向),$w_i$ 是基于距离的权重函数(如高斯函数),确保变形只在局部区域生效[^1]。 #### 2. **主要算法及实现方法** 瘦脸效果常用算法包括液化算法(Liquify)和移动最小二乘法(MLS),均依赖于人脸特征点检测。以下是具体实现步骤和函数: - **特征点检测**: 使用 dlib 库检测人脸关键点(如 68 点模型)。dlib 的 `get_frontal_face_detector()` 和 `shape_predictor` 函数可快速定位特征点。 **Python 示例代码(使用 dlib 和 OpenCV)**: ```python import dlib import cv2 # 加载模型 detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 读取图像 image = cv2.imread("face.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 检测人脸和特征点 faces = detector(gray) for face in faces: landmarks = predictor(gray, face) points = [(landmarks.part(i).x, landmarks.part(i).y) for i in range(68)] # 获取68个点 # 关键点索引:脸颊点(如索引3-13和54-64),用于瘦脸变形 ``` - **变形算法实现**: - **液化算法(Liquify Algorithm)**: 基于网格变形,通过移动特征点并插值实现平滑收缩。Android 中可使用 `drawBitmapMesh` 函数实现,参考 Interactive Image Warping 文献[^2]。核心是计算变形网格: $$ \Delta \mathbf{p} = k \cdot \frac{\mathbf{p} - \mathbf{c}}{\|\mathbf{p} - \mathbf{c}\|^2} $$ 其中 $\mathbf{c}$ 是变形中心点(如脸颊),$k$ 是收缩强度系数。 **Android 实现代码(Kotlin)**: ```kotlin // 参考引用[2]的drawBitmapMesh实现 fun thinFace(bitmap: Bitmap, points: Array<PointF>): Bitmap { val width = bitmap.width val height = bitmap.height val meshWidth = 10 // 网格密度 val meshHeight = 10 val verts = FloatArray((meshWidth + 1) * (meshHeight + 1) * 2) // 初始化网格点... // 应用变形:移动脸颊点(points[3]到points[13]) for (i in 3..13) { val dx = -5f // 收缩方向(负值表示向内) val dy = 0f verts[2*i] += dx verts[2*i + 1] += dy } val result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(result) canvas.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, 0, null, 0, null) return result } ``` - **移动最小二乘法(MLS, Moving Least Squares)**: 一种更精确的变形方法,通过最小化变形误差实现平滑过渡。公式为: $$ \mathbf{p}' = \mathbf{M} \cdot (\mathbf{p} - \mathbf{p}_0) + \mathbf{q}_0 $$ 其中 $\mathbf{M}$ 是仿射变换矩阵,$\mathbf{p}_0$ 和 $\mathbf{q}_0$ 是控制点。MLS 在 OpenCV 中可手动实现[^3]。 **C++ 示例代码(使用 OpenCV)**: ```cpp #include <opencv2/opencv.hpp> #include <vector> cv::Mat thinFaceMLS(cv::Mat image, std::vector<cv::Point2f> srcPoints, std::vector<cv::Point2f> dstPoints) { // srcPoints: 原始特征点(如dlib检测的点) // dstPoints: 变形后点(脸颊点向内移动) cv::Mat result; cv::Mat grid = cv::Mat::zeros(image.size(), CV_32FC2); // 计算MLS变形网格 for (int y = 0; y < image.rows; y++) { for (int x = 0; x < image.cols; x++) { cv::Point2f p(x, y); cv::Point2f newP(0, 0); float totalWeight = 0; for (int i = 0; i < srcPoints.size(); i++) { float dist = cv::norm(p - srcPoints[i]); float weight = exp(-dist * dist / 100.0); // 高斯权重 newP += weight * (dstPoints[i] - srcPoints[i]); totalWeight += weight; } if (totalWeight > 0) newP = p + newP / totalWeight; grid.at<cv::Vec2f>(y, x) = cv::Vec2f(newP.x, newP.y); } } cv::remap(image, result, grid, cv::Mat(), cv::INTER_LINEAR); return result; } ``` - **关键函数和库**: - **dlib**:用于人脸检测和特征点提取(函数:`get_frontal_face_detector()`, `shape_predictor()`)。 - **OpenCV**:提供图像变形函数如 `remap()` 和网格计算(库函数:`cv::remap`, `cv::Mat`)。 - **Android SDK**:`drawBitmapMesh` 函数直接支持网格变形[^2]。 - 算法优化:结合双边滤波(bilateral filter)避免锯齿,如引用[1]所述。 #### 3. **注意事项和最佳实践** - **性能优化**:瘦脸算法计算量较大,建议在 GPU 上加速或使用多线程。MLS 算法复杂度为 $O(n \cdot m)$($n$ 为像素数,$m$ 为特征点数),可通过减少网格点提升速度。 - **可靠性**:实际应用中,需处理多角度人脸和光照变化。dlib 的特征点检测在正脸效果最佳;侧脸时需结合深度学习模型(如 MTCNN)。 - **引用总结**:液化算法简单高效,适合移动端[^1][^2];MLS 算法变形更平滑,但实现复杂[^3]。所有方法都依赖准确的特征点定位。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值