自动瘦脸与眼睛放大美颜算法

自动瘦脸与眼睛放大可以算作图像局部扭曲算法的一个应用,其参考文献可以追溯至1993年的一篇博士论文:Interactive Image Warping。这篇论文详细描述了算法原理,并提供了伪码实现,有兴趣的同学自行下载研读。

图像局部扭曲算法有三个:局部缩放(Local Scaling)算法、局部平移(Local Transition)算法和局部旋转(Local Rotation)算法。其中应用局部缩放算法可实现眼睛放大,局部平移算法则可用于实现瘦脸效果。当然,图像局部缩放算法只是眼睛放大算法流程中的最关键的一步,要实现自动眼睛放大算法还需要额外的步骤。简单来说,给一张美女头像,你首先需要应用自动人脸检测技术定位出图像中的眼睛位置;然后基于此位置坐标应用图像局部缩放算法。自动瘦脸算法流程类似,不同之处在于应用人脸检测技术得到人脸轮廓点,由这些轮廓坐标点应用局部平移算法得到瘦脸效果。

人脸检测现在已经是一个很成熟的技术,网上也有很多开放资源,目前我只是算法验证,暂时使用的是face++提供的人脸关键点检测SDK。它可以得到很丰富的人脸特征点,包括眉毛、眼睛、鼻子、嘴巴以及脸部轮廓的各个参数,企业应用可能需要付费授权才能使用,个人验证只要注册获取key就能简单集成。

图像局部缩放算法

待续。。。

至于图像局部缩放算法实现,文献中有伪码描述,这里我给出一个简单的OpenGL Shader可以用于实现眼睛放大(其实也可以缩小),偷懒的同学自取,有问题可以跟我讨论,但我不对此代码导致的bug负责。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

precision highp float;

varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;

uniform highp float scaleRatio;// 缩放系数,0无缩放,大于0则放大

uniform highp float radius;// 缩放算法的作用域半径

uniform highp vec2 leftEyeCenterPosition; // 左眼控制点,越远变形越小

uniform highp vec2 rightEyeCenterPosition; // 右眼控制点

uniform float aspectRatio; // 所处理图像的宽高比

highp vec2 warpPositionToUse(vec2 centerPostion, vec2 currentPosition, float radius, float scaleRatio, float aspectRatio)

{

     vec2 positionToUse = currentPosition;

    

     vec2 currentPositionToUse = vec2(currentPosition.x, currentPosition.y * aspectRatio + 0.5 - 0.5 * aspectRatio);

     vec2 centerPostionToUse = vec2(centerPostion.x, centerPostion.y * aspectRatio + 0.5 - 0.5 * aspectRatio);

    

     float r = distance(currentPositionToUse, centerPostionToUse);

    

     if(r < radius)

     {

         float alpha = 1.0 - scaleRatio * pow(r / radius - 1.0, 2.0);

         positionToUse = centerPostion + alpha * (currentPosition - centerPostion);

     }

      

     return positionToUse;

}

void main()

{

     vec2 positionToUse = warpPositionToUse(leftEyeCenterPosition, textureCoordinate, radius, scaleRatio, aspectRatio);

      

     positionToUse = warpPositionToUse(rightEyeCenterPosition, positionToUse, radius, scaleRatio, aspectRatio);

  

     gl_FragColor = texture2D(inputImageTexture, positionToUse);  

}

给个测试效果图:

 

图像局部平移算法

图像局部平移算法还是参见论文,多说无益,在此奉上对应Shader代码给需要的同学,可以实现瘦脸和肥脸。这里需要指定瘦脸的控制点,最多支持MAX_CONTOUR_POINT_COUNT个控制点。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

precision highp float;

varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;

uniform highp float radius;

uniform highp float aspectRatio;

uniform float leftContourPoints[MAX_CONTOUR_POINT_COUNT*2];

uniform float rightContourPoints[MAX_CONTOUR_POINT_COUNT*2];

uniform float deltaArray[MAX_CONTOUR_POINT_COUNT];

uniform int arraySize;

highp vec2 warpPositionToUse(vec2 currentPoint, vec2 contourPointA,  vec2 contourPointB, float radius, float delta, float aspectRatio)

{

     vec2 positionToUse = currentPoint;

    

     vec2 currentPointToUse = vec2(currentPoint.x, currentPoint.y * aspectRatio + 0.5 - 0.5 * aspectRatio);

     vec2 contourPointAToUse = vec2(contourPointA.x, contourPointA.y * aspectRatio + 0.5 - 0.5 * aspectRatio);

    

     float r = distance(currentPointToUse, contourPointAToUse);

     if(r < radius)

     {

         vec2 dir = normalize(contourPointB - contourPointA);

         float dist = radius * radius - r * r;

         float alpha = dist / (dist + (r-delta) * (r-delta));

         alpha = alpha * alpha;

        

         positionToUse = positionToUse - alpha * delta * dir;

        

     }

    

     return positionToUse;

    

}

void main()

{

     vec2 positionToUse = textureCoordinate;

    

     for(int i = 0; i < arraySize; i++)

     {

      

         positionToUse = warpPositionToUse(positionToUse, vec2(leftContourPoints[i * 2], leftContourPoints[i * 2 + 1]), vec2(rightContourPoints[i * 2], rightContourPoints[i * 2 + 1]), radius, deltaArray[i], aspectRatio);

         positionToUse = warpPositionToUse(positionToUse, vec2(rightContourPoints[i * 2], rightContourPoints[i * 2 + 1]), vec2(leftContourPoints[i * 2], leftContourPoints[i * 2 + 1]), radius, deltaArray[i], aspectRatio);

     }

    

     gl_FragColor = texture2D(inputImageTexture, positionToUse);

    

}

同样给个测试效果:

猜你喜欢

转载自blog.csdn.net/qq_21743659/article/details/107530884
今日推荐