怎么实现女神想要的大眼瘦脸效果?程序员追女神有一招事半功倍!

俗话说,亚洲四大邪术,中国的PS术占大片江山,既不要伤筋动骨,也不要出钱出力,只需要一个软件,轻松搞定!
程序员追女神,实现女神想要的要的大眼瘦脸效果,那不是给自己增加了机会!
想要满足自己女神要求的程序员们,我们往下看:
实现瘦脸大眼效果,其本质上都是对图像中某些区域的像素按照我们设定的规则进行移动,而 OpenGL 的片段着色器天然适合处理像素(纹素)层面的操作。。
OpenGL 实现大眼效果
为了更好的展示大眼效果,动图中形变参数设置较大,所以看起来比较夸张。
OpenGL 实现大眼效果,可以参照放大镜的实现原理,即将纹理上一块区域采样后映射到一块相对较大的区域。
本文所实现的大眼效果进行了简化,是在以人眼为中心的圆形区域内进行放大,距离圆心越远,放大的强度越大。

如上图所示,圆内部为发生形变(放大)的区域,红点为不发生形变时的采样点(原始纹理坐标),绿点为发生形变时对应的采样点(纹理坐标发生偏移)。
实现眼睛放大效果的着色器脚本(代码中指定了图片人眼中心坐标和人眼半径):
#version 300 es
precision highp float;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap;
in vec2 v_texCoord;
uniform highp vec2 u_LeftEyeCenterPos;// 左眼中心点
uniform highp vec2 u_RightEyeCenterPos;// 右眼中心点
uniform highp float u_ScaleRatio;//放大系数
uniform highp float u_Radius;// 影响半径
uniform vec2 u_ImgSize;//图片分辨率
vec2 warpEyes(vec2 centerPos, vec2 curPos, float radius, float scaleRatio)
{
vec2 result = curPos;
vec2 imgCurPos = curPos * u_ImgSize;
float d = distance(imgCurPos, centerPos);
if (d < radius)
{
float gamma = 1.0 - scaleRatio * pow(smoothstep(0.0, 1.0, d / radius) - 1.0, 2.0);
result = centerPos + gamma * (imgCurPos - centerPos);
result = result / u_ImgSize;
}
return result;
}
void main()
{
vec2 newTexCoord = warpEyes(u_LeftEyeCenterPos, v_texCoord, u_Radius, u_ScaleRatio);
newTexCoord = warpEyes(u_RightEyeCenterPos, newTexCoord, u_Radius, u_ScaleRatio);
outColor = texture(s_TextureMap, newTexCoord);
}
OpenGL 实现瘦脸效果
瘦脸效果的实现,是将指定区域内的像素按照一定的规则进行整体偏移,从而形成一种对脸部挤压的效果。

如上图所示,BC表示偏移方向和偏移程度的向量,将圆内的所有像素按照向量BC的方向进行一定程度的偏移,像素偏移的强度,和像素与圆心的距离相关,越靠近圆心强度越大。

为了简化计算流程,只做原理性展示,我们选取 了3 个人脸部位的关键点(如上图,左右太阳穴和下巴),再由关键点计算出来控制点(太阳穴和下巴的连线的中心点),控制点组成上述的 BC 向量。当然你若想快速验证瘦脸效果,可以直接手动指定。
瘦脸效果的着色器脚本:
#version 300 es
precision highp float;
layout(location = 0) out vec4 outColor;
in vec2 v_texCoord;
uniform sampler2D s_TextureMap;
uniform vec2 u_texSize;//图像分辨率
uniform vec4 u_preCtrlPoints;//pre控制点
uniform vec4 u_curCtrlPoints;//cur控制点
uniform float u_reshapeRadius;//影响半径
uniform float u_reshapeRatio;//强度
vec2 face_slender_1(vec2 prePoint, vec2 curPoint, vec2 texCoord, float radius, vec2 texSize)
{
vec2 pos = texCoord;
vec2 newSrc = prePoint * texSize;
vec2 newDst = curPoint * texSize;
vec2 newTex = texCoord * texSize;
float newRadius = radius;
float r = distance(newSrc, newTex);
if (r < newRadius)
{
float alpha = 1.0 - r / newRadius;
vec2 displacementVec = (newDst - newSrc) * pow(alpha, 2.0) * 0.002 * u_reshapeRatio;
pos = (newTex - displacementVec) / texSize;
}
return pos;
}
void main() {
vec2 leftPreCtrl = u_preCtrlPoints.xy;
vec2 rightPreCtrl = u_preCtrlPoints.zw;
vec2 leftCurCtrl = u_curCtrlPoints.xy;
vec2 rightCurCtrl = u_curCtrlPoints.zw;
vec2 newTexCoord = face_slender_1(leftPreCtrl, leftCurCtrl, v_texCoord, u_reshapeRadius, u_texSize);
newTexCoord = face_slender_1(rightPreCtrl, rightCurCtrl, newTexCoord, u_reshapeRadius, u_texSize);
outColor = texture(s_TextureMap, newTexCoord);
}
最后
附上我的Android核心技术学习大纲,获取更多内容来我的GitHub一起玩耍:https://github.com/Meng997998/AndroidJX
最近不是面试季嘛,再给大家一个福利:【2017-2019字节跳动面试真题解析&简历制作PDF模板】
针对字节跳动的面试题整理的,进行了分类,循序渐进,由基础到深入,由易到简。
将内容整理成了五个章节、计算机基础面试题、数据结构和算法面试题、Java面试题、Android面试题、其他扩展面试题、非技术面试题总共五个章节354页。
每个问题都附上1个标准参考答案,都是反复摸索消化(真心花了很多时间),觉得写的比较好的文章作为答案。
来节省大家自己去搜索的时间,把时间用在正确的东西上。。
还整理了全套简历制作、春招困惑、HR面试等问题解析参考建议,都是福利分享给大家。