调节像素偏移

2019-11-29  本文已影响0人  一川烟草i蓑衣

调节像素偏移主要是用来处理瘦脸大眼、调节下巴等处理。前面我们做了图像三角剖分和重建工作,得到了整张人脸的索引。接下来我们只需要得到对应的顶点坐标、纹理坐标,更新顶点坐标缓冲、纹理坐标缓冲即可。这里需要根据是否有人脸来做顶点判断。其中updateCartesianVertices()方法是用来传递人脸关键点在图像中的实际笛卡尔坐标的,这里主要是为了方便做像素偏移计算:

if (LandmarkEngine.getInstance().hasFace()) {

            LandmarkEngine.getInstance().updateFaceAdjustPoints(mVertices, mTextureVertices, 0);

            mVertexBuffer.clear();

            mVertexBuffer.put(mVertices);

            mVertexBuffer.position(0);

            mTextureBuffer.clear();

            mTextureBuffer.put(mTextureVertices);

            mTextureBuffer.position(0);

            updateCartesianVertices();

            mIndexBuffer.clear();

            mIndexBuffer.put(FaceImageIndices);

            mIndexBuffer.position(0);

            mIndexLength = mIndexBuffer.capacity();

            setInteger(mEnableReshapeHandle, 1);

        } else { // 没有人脸时索引变回默认的6个

            mIndexBuffer.clear();

            mIndexBuffer.put(TextureRotationUtils.Indices);

            mIndexBuffer.position(0);

            mIndexLength = 6;

            setInteger(mEnableReshapeHandle, 0);

        }

接下来,我们就可以在fragment shader 中进行像素调节处理了。关于像素偏移调节,可以参考下面这篇文章,写得比较详细:

在OpenGL中利用shader进行实时瘦脸大眼等脸型微调

脸型调节的fragment shader 如下所示(截止本文章位置,部分脸型调节功能还没完成)

precision mediump float;

varying vec2 textureCoordinate;

uniform sampler2D inputTexture;

// 图像笛卡尔坐标系的关键点,也就是纹理坐标乘以宽高得到

uniform vec2 cartesianPoints[106];

#define INDEX_FACE_LIFT    0  // 瘦脸

#define INDEX_FACE_SHAVE    1  // 削脸

#define INDEX_FACE_NARROW  2  // 小脸

#define INDEX_CHIN          3  // 下巴

#define INDEX_FOREHEAD      4  // 额头

#define INDEX_EYE_ENLARGE  5  // 大眼

#define INDEX_EYE_DISTANCE  6  // 眼距

#define INDEX_EYE_CORNER    7  // 眼角

#define INDEX_NOSE_THIN    8  // 瘦鼻

#define INDEX_ALAE          9  // 鼻翼

#define INDEX_PROBOSCIS    10  // 长鼻

#define INDEX_MOUTH        11  // 嘴型

#define INDEX_SIZE 12          // 索引大小

// 美型程度参数列表

uniform float reshapeIntensity[INDEX_SIZE];

// 纹理宽度

uniform int textureWidth;

// 纹理高度

uniform int textureHeight;

// 是否允许美型处理,存在人脸时为1,没有人脸时为0

uniform int enableReshape;

// 曲线形变处理

vec2 curveWarp(vec2 textureCoord, vec2 originPosition, vec2 targetPosition, float radius)

{

    vec2 offset = vec2(0.0);

    vec2 result = vec2(0.0);

    vec2 direction = targetPosition - originPosition;

    float infect = distance(textureCoord, originPosition)/radius;

    infect = 1.0 - infect;

    infect = clamp(infect, 0.0, 1.0);

    offset = direction * infect;

    result = textureCoord - offset;

    return result;

}

// 大眼处理

vec2 enlargeEye(vec2 currentCoordinate, vec2 circleCenter, float radius, float intensity)

{

    float currentDistance = distance(currentCoordinate, circleCenter);

    float weight = currentDistance / radius;

    weight = 1.0 - intensity * (1.0 - weight * weight);

    weight = clamp(weight, 0.0, 1.0);

    currentCoordinate = circleCenter + (currentCoordinate - circleCenter) * weight;

    return currentCoordinate;

}

// 瘦脸

vec2 faceLift(vec2 currentCoordinate, float faceLength)

{

    vec2 coordinate = currentCoordinate;

    vec2 currentPoint = vec2(0.0);

    vec2 destPoint = vec2(0.0);

    float faceLiftScale = reshapeIntensity[INDEX_FACE_LIFT] * 0.05;

    float radius = faceLength;

    currentPoint = cartesianPoints[3];

    destPoint = currentPoint + (cartesianPoints[44] - currentPoint) * faceLiftScale;

    coordinate = curveWarp(coordinate, currentPoint, destPoint, radius);

    currentPoint = cartesianPoints[29];

    destPoint = currentPoint + (cartesianPoints[44] - currentPoint) * faceLiftScale;

    coordinate = curveWarp(coordinate, currentPoint, destPoint, radius);

    radius = faceLength * 0.8;

    currentPoint = cartesianPoints[10];

    destPoint = currentPoint + (cartesianPoints[46] - currentPoint) * (faceLiftScale * 0.6);

    coordinate = curveWarp(coordinate, currentPoint, destPoint, radius);

    currentPoint = cartesianPoints[22];

    destPoint = currentPoint + (cartesianPoints[46] - currentPoint) * (faceLiftScale * 0.6);

    coordinate = curveWarp(coordinate, currentPoint, destPoint, radius);

    return coordinate;

}

// 削脸

vec2 faceShave(vec2 currentCoordinate, float faceLength)

{

    vec2 coordinate = currentCoordinate;

    vec2 currentPoint = vec2(0.0);

    vec2 destPoint = vec2(0.0);

    float faceShaveScale = reshapeIntensity[INDEX_FACE_SHAVE] * 0.12;

    float radius = faceLength * 1.0;

    // 下巴中心

    vec2 chinCenter = (cartesianPoints[16] + cartesianPoints[93]) * 0.5;

    currentPoint = cartesianPoints[13];

    destPoint = currentPoint + (chinCenter - currentPoint) * faceShaveScale;

    coordinate = curveWarp(coordinate, currentPoint, destPoint, radius);

    currentPoint = cartesianPoints[19];

    destPoint = currentPoint + (chinCenter - currentPoint) * faceShaveScale;

    coordinate = curveWarp(coordinate, currentPoint, destPoint, radius);

    return coordinate;

}

// 处理下巴

vec2 chinChange(vec2 currentCoordinate, float faceLength)

{

    vec2 coordinate = currentCoordinate;

    vec2 currentPoint = vec2(0.0);

    vec2 destPoint = vec2(0.0);

    float chinScale = reshapeIntensity[INDEX_CHIN] * 0.08;

    float radius = faceLength * 1.25;

    currentPoint = cartesianPoints[16];

    destPoint = currentPoint + (cartesianPoints[46] - currentPoint) * chinScale;

    coordinate = curveWarp(coordinate, currentPoint, destPoint, radius);

    return coordinate;

}

void main()

{

    vec2 coordinate = textureCoordinate.xy;

    // 禁用美型处理或者鼻子不在图像中,则直接绘制

    if (enableReshape == 0 || (cartesianPoints[46].x / float(textureWidth) <= 0.03)

        || (cartesianPoints[46].y / float(textureHeight)) <= 0.03) {

        gl_FragColor = texture2D(inputTexture, coordinate);

        return;

    }

    // 将坐标转成图像大小,这里是为了方便计算

    coordinate = textureCoordinate * vec2(float(textureWidth), float(textureHeight));

    float eyeDistance = distance(cartesianPoints[74], cartesianPoints[77]); // 两个瞳孔的距离

    // 瘦脸

    coordinate = faceLift(coordinate, eyeDistance);

    // 削脸

    coordinate = faceShave(coordinate, eyeDistance);

    // 小脸 TODO 眼睛到下巴图像线性缩小

    // 下巴

    coordinate = chinChange(coordinate, eyeDistance);

    // 额头

    // 大眼

    float eyeEnlarge = reshapeIntensity[INDEX_EYE_ENLARGE] * 0.12; // 放大倍数

    if (eyeEnlarge > 0.0) {

        float radius = eyeDistance * 0.33; // 眼睛放大半径

        coordinate = enlargeEye(coordinate, cartesianPoints[74] + (cartesianPoints[77] - cartesianPoints[74]) * 0.05, radius, eyeEnlarge);

        coordinate = enlargeEye(coordinate, cartesianPoints[77] + (cartesianPoints[74] - cartesianPoints[77]) * 0.05, radius, eyeEnlarge);

    }

    // 眼距

    // 眼角

    // 瘦鼻

    // 鼻翼

    // 长鼻

    // 嘴型

    // 转变回原来的纹理坐标系

    coordinate = coordinate / vec2(float(textureWidth), float(textureHeight));

    // 输出图像

    gl_FragColor = texture2D(inputTexture, coordinate);

}

上一篇下一篇

猜你喜欢

热点阅读