opengl 实现瘦脸等脸部微调

美颜瘦脸

在这个靠脸吃饭的时代,有张漂亮的脸蛋无疑会令你加分不少;那万一天生的颜值不够怎么办呢?。。。还有美颜来拯救。

现在很多相机以及大多数修图软件都提供了瘦脸的功能。现在主流的瘦脸功能都是基于opengl来完成的。

先看效果

原图:
在这里插入图片描述

瘦脸:
在这里插入图片描述

很明显下面的照片要比上面的照片的脸要瘦了很多。
下面一步步去实现这些功能。

先上源码

VS2019的项目,环境完整,可直接运行

实现

识别人脸并定位特征点

用dlib或者face++或者自己训练个神经网络去识别出特征点。
这里我用dlib 识别出特征点

初始化dlib:

    dlib::frontal_face_detector detector;
	dlib::shape_predictor pose_model;
	std::string  facemodel = "./model/shape_predictor_68_face_landmarks.dat";
	detector = dlib::get_frontal_face_detector();
	dlib::deserialize(facemodel) >> pose_model;

识别人脸并保存特征点

    dlib::cv_image<dlib::bgr_pixel> cimg(src);
	std::vector<dlib::rectangle> faces = detector(cimg);	// Detect faces
	dlib::full_object_detection  shape;		// Find the pose of one face
	facelandmarks.clear();
	if (faces.size() > 0) {
		shape = pose_model(cimg, faces[0]);
		facerect = cv::Rect(cv::Point2i(faces[0].left(), faces[0].top()), cv::Point2i(faces[0].right() + 1, faces[0].bottom() + 1));
		for (int i = 0; i < 68; i++) {
			facelandmarks.push_back(cv::Point2f(shape.part(i).x(), shape.part(i).y()));
		}
	}
	else {
		return -1;
	}

识别的特征点如下 共68个:
在这里插入图片描述

人脸分割

这里为了简单只将图片分为26个三角形。若想效果更平滑,可以将图片分的更细。

在这里插入图片描述

	//人脸分割
	cv::Point2f LALL0 = cv::Point2f(-1.0f, -1.0f);
	cv::Point2f LALL1 = cv::Point2f(-1.0f, 1.0f);
	cv::Point2f LALL2 = cv::Point2f(1.0f, 1.0f);
	cv::Point2f LALL3 = cv::Point2f(1.0f, -1.0f);
	cv::Point2f LFace30 = cv::Point2f(facelandmarks[30].x * 2.0 / width - 1.0, (height - facelandmarks[30].y) * 2.0 / height - 1.0);
	cv::Point2f LFace3 = cv::Point2f(facelandmarks[3].x * 2.0 / width - 1.0, (height - facelandmarks[3].y) * 2.0 / height - 1.0);
	cv::Point2f LFace4 = cv::Point2f(facelandmarks[4].x * 2.0 / width - 1.0, (height - facelandmarks[4].y) * 2.0 / height - 1.0);
	cv::Point2f LFace5 = cv::Point2f(facelandmarks[5].x * 2.0 / width - 1.0, (height - facelandmarks[5].y) * 2.0 / height - 1.0);
	cv::Point2f LFace6 = cv::Point2f(facelandmarks[6].x * 2.0 / width - 1.0, (height - facelandmarks[6].y) * 2.0 / height - 1.0);
	cv::Point2f LFace7 = cv::Point2f(facelandmarks[7].x * 2.0 / width - 1.0, (height - facelandmarks[7].y) * 2.0 / height - 1.0);
	cv::Point2f LFace8 = cv::Point2f(facelandmarks[8].x * 2.0 / width - 1.0, (height - facelandmarks[8].y) * 2.0 / height - 1.0);
	cv::Point2f LFace9 = cv::Point2f(facelandmarks[9].x * 2.0 / width - 1.0, (height - facelandmarks[9].y) * 2.0 / height - 1.0);
	cv::Point2f LFace10 = cv::Point2f(facelandmarks[10].x * 2.0 / width - 1.0, (height - facelandmarks[10].y) * 2.0 / height - 1.0);
	cv::Point2f LFace11 = cv::Point2f(facelandmarks[11].x * 2.0 / width - 1.0, (height - facelandmarks[11].y) * 2.0 / height - 1.0);
	cv::Point2f LFace12 = cv::Point2f(facelandmarks[12].x * 2.0 / width - 1.0, (height - facelandmarks[12].y) * 2.0 / height - 1.0);
	cv::Point2f LFace13 = cv::Point2f(facelandmarks[13].x * 2.0 / width - 1.0, (height - facelandmarks[13].y) * 2.0 / height - 1.0);

	cv::Point2f VALL0 = cv::Point2f(0.0f, 1.0f);
	cv::Point2f VALL1 = cv::Point2f(0.0f, 0.0f);
	cv::Point2f VALL2 = cv::Point2f(1.0f, 0.0f);
	cv::Point2f VALL3 = cv::Point2f(1.0f, 1.0f);
	cv::Point2f VFace30 = cv::Point2f(facelandmarks[30].x / width, facelandmarks[30].y / height);
	cv::Point2f VFace3 = cv::Point2f(facelandmarks[3].x / width, facelandmarks[3].y / height);
	cv::Point2f VFace4 = cv::Point2f(facelandmarks[4].x / width, facelandmarks[4].y / height);
	cv::Point2f VFace5 = cv::Point2f(facelandmarks[5].x / width, facelandmarks[5].y / height);
	cv::Point2f VFace6 = cv::Point2f(facelandmarks[6].x / width, facelandmarks[6].y / height);
	cv::Point2f VFace7 = cv::Point2f(facelandmarks[7].x / width, facelandmarks[7].y / height);
	cv::Point2f VFace8 = cv::Point2f(facelandmarks[8].x / width, facelandmarks[8].y / height);
	cv::Point2f VFace9 = cv::Point2f(facelandmarks[9].x / width, facelandmarks[9].y / height);
	cv::Point2f VFace10 = cv::Point2f(facelandmarks[10].x / width, facelandmarks[10].y / height);
	cv::Point2f VFace11 = cv::Point2f(facelandmarks[11].x / width, facelandmarks[11].y / height);
	cv::Point2f VFace12 = cv::Point2f(facelandmarks[12].x / width, facelandmarks[12].y / height);
	cv::Point2f VFace13 = cv::Point2f(facelandmarks[13].x / width, facelandmarks[13].y / height);


	float vertices[] = {
		//----位置----						---纹理---
		LALL0.x,	LALL0.y,	0.0f,		VALL0.x,	VALL0.y,
		LALL1.x,	LALL1.y,	0.0f,		VALL1.x,	VALL1.y,
		LALL2.x,	LALL2.y,	0.0f,		VALL2.x,	VALL2.y,
		LALL3.x,	LALL3.y,	0.0f,		VALL3.x,	VALL3.y,
		LFace30.x,	LFace30.y,	0.0f,       VFace30.x,	VFace30.y,
		LFace3.x,	LFace3.y,	0.0f,       VFace3.x,	VFace3.y,
		LFace4.x,	LFace4.y,	0.0f,       VFace4.x,	VFace4.y,
		LFace5.x,	LFace5.y,	0.0f,       VFace5.x,	VFace5.y,
		LFace6.x,	LFace6.y,	0.0f,       VFace6.x,	VFace6.y,
		LFace7.x,	LFace7.y,	0.0f,       VFace7.x,	VFace7.y,
		LFace8.x,	LFace8.y,	0.0f,       VFace8.x,	VFace8.y,
		LFace9.x,	LFace9.y,	0.0f,       VFace9.x,	VFace9.y,
		LFace10.x,	LFace10.y,	0.0f,       VFace10.x,	VFace10.y,
		LFace11.x,	LFace11.y,	0.0f,       VFace11.x,	VFace11.y,
		LFace12.x,	LFace12.y,	0.0f,       VFace12.x,	VFace12.y,
		LFace13.x,	LFace13.y,	0.0f,       VFace13.x,	VFace13.y
	};

	unsigned int indices[] = {
		0,1,5,
		5,1,4,
		4,1,2,
		2,4,15,
		15,2,3,
		0,5,6,
		0,6,7,
		0,7,8,
		0,8,9,
		0,9,10,
		0,10,3,
		3,10,11,
		3,11,12,
		3,12,13,
		3,13,14,
		3,14,15,
		4,5,6,
		4,6,7,
		4,7,8,
		4,8,9,
		4,9,10,
		4,10,11,
		4,11,12,
		4,12,13,
		4,13,14,
		4,14,15
	};

瘦脸变形

在这里插入图片描述

只需要将图中标记的点按照箭头方向拖动,即可实现瘦脸,为了不显得太过于尖锐,我们将范围包括到附近的几个点。

关于像素偏移调节,可以参考这篇文章

shader:

#version 330 core
precision mediump float;

in vec2 TexCoord;
out vec4 outColor;
uniform sampler2D inputTexture;

uniform float face5x;
uniform float face5y;

vec2 stretchFun(vec2 textureCoord, vec2 originPosition, vec2 targetPosition, float radius,float curve)
{
    vec2 direction = targetPosition - originPosition;
    float infect = distance(textureCoord, originPosition)/radius;
    infect =1.0 -  pow(infect,curve);
    infect = clamp(infect,0.0,1.0);
    vec2 offset = direction * infect;
    vec2 result = textureCoord - offset;
    return result;
}

void main(){
    vec2 A1 = vec2(face5x,face5y);
    vec2 A2 = vec2(face5x+0.02f,face5y + 0.01f);

    vec2 TexCoord2 = stretchFun(TexCoord,A1,A2,0.19f,2.0f);

    vec3 tmpColor = texture(inputTexture, TexCoord2).rgb;
    outColor = vec4(tmpColor,1.0f);
}

像素偏移后结果

在这里插入图片描述

去掉特征点后结果

在这里插入图片描述

完成

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值