Giter Club home page Giter Club logo

Comments (10)

CainKernel avatar CainKernel commented on June 30, 2024

动态贴纸部分的GLStickerFilter的滤镜我还没做好呢,GLStickerFilter还没验证过能否行得通呢,当时写了一点就去做其他事了。不过动态贴纸这部分功能,估计没有什么好的完全开源的方案吧,都是收费的。最近我在做短视频编辑的功能,没时间实现动态贴纸的功能。动态贴纸部分需要考虑的东西很多的,要做好还是挺花时间的。我大概列举出来,给你提供一个思路吧:

第一、根据人脸关键点计算贴纸的位置。这是要配合设计师调整位置的,因为每个贴纸的位置可能不太一样,每个器官的贴纸也是不一样的,所以一般都是用json来做。解析json,得到各个部位的贴纸的偏移量,配合关键点计算实际的位置。比如说,头部的耳朵位置,106个标准人脸关键点是没有额头的,额头的关键点需要你自己计算,然后根据额头的关键点加上贴纸的偏移量来算出耳朵的位置。然后就是目前的人脸关键点SDK的耳垂部分也是没有固定关键点的。你要不要做耳环之类的贴纸,不过市面上似乎都没什么人做这个,我之前在公司里面做预研,发现不同的姿态角偏差太大了,没什么太好的方法固定耳垂的位置。

第二、是否需要支持透视投影。抖音那个动态贴纸是纯二维的,也就是说,在侧脸的时候是没有做透视投影变换的。FaceU是支持透视投影的,你可以对比一下,看看效果有什么不一样的地方。纯二维和支持三维透视投影变换的贴纸计算方式也不一样。二维的计算只需要根据人脸关键点坐标(即屏幕UV坐标)计算位置就行,但是三维投影的动态贴纸则需要你根据人脸关键点坐标(屏幕UV坐标),配合人脸检测SDK给出来的姿态角(pitch、yaw、roll)倒推贴纸在假想的三维空间中的实际大小,再做投影变换才能得到非常不错的透视结果,这个就是FaceU的动态贴纸方案,我在公司也实现了类似的方案,不过做起来比较麻烦,暂时我也抽不出时间来给CainCamera做动态贴纸功能。

第三、是否支持Blend混合模式。二维跟三维的Blend混合模式有些差别的。目前市面上支持透视投影变换又支持Blend混合模式的好像没几家。FaceU是不支持Blend混合模式的。支持透视投影变换又支持Blend混合模式的贴纸的方式,是需要在Vertex Shader里面先算出动态贴纸经过透视投影变换后的屏幕坐标(即UV坐标),然后再在fragmet shader 里面做跟二维一样的Blend混合模式。

基于上面的三点要求,我建议你先实现纯二维的动态贴纸。用关键点 + json的偏移量,算好屏幕UV坐标的位置,传到glsl,用 texture2D(stickerTexture, textureCoordinate); 得到vec4 向量,然后做自定义Blend混合。这样会简单点,投影变换 + Blend 混合的方式可以暂时不做。另外一个问题就是,你的动态贴纸是放在一张大图里面加载的,跟多张图片加载的,这里也有些不一样的,像无他相机就是一张大图的方式加载的。如果是多张图片加载的方式,你可以考虑用glTexSubImage2D 更新各个部位贴纸的texture,我的GlUtil.java 里面的有封装好了的,你可以参考一下。

from caincamera.

ruijun avatar ruijun commented on June 30, 2024

如果不考虑人脸检测,只是当过视频背景动态图(比如下雨效果或者一个小鸟在飞来来去)这种情况,采用多张png图片加载的方式,大体思路是怎样呢?

from caincamera.

CainKernel avatar CainKernel commented on June 30, 2024

这个就相对简单很多了,只需要你图像的长宽比(4:3、16:9等),对你背景动态进行裁剪(计算好 mipmapCoordinate UV坐标)。图像inputTexture 和 下雨效果的贴纸mipmapTexture,直接用默认的Blend混合就行。fragment shader 就跟下面的一样,下面就是默认的混合效果。然后你用glTexSubImage2D更新mipmapTexture的数据就行,比如说你的背景动画是0.2s更新一次的,那么在应用层用Handler每隔0.2s更新一次mipmapTexture就行。

precision mediump float;
varying vec2 textureCoordinate;    // texture的uv坐标
varying vec2 mipmapCoordinate;     // mipmap经过透视变换到屏幕上的uv坐标

uniform sampler2D inputTexture;    // 原始Texture
uniform sampler2D mipmapTexture;   // 贴图Texture

void main()
{
    lowp vec4 sourceColor = texture2D(inputTexture, 1.0 - textureCoordinate);
    lowp vec4 mipmapColor = texture2D(mipmapTexture, mipmapCoordinate);
    // 混合处理,此时可以做各种混合处理,比如变换透明度,变换颜色等等
    gl_FragColor = mipmapColor * mipmapColor.a + sourceColor * (1.0 - mipmapColor.a);
}

from caincamera.

ruijun avatar ruijun commented on June 30, 2024

inputTexture 指视频图像 ? 在应用层用Handler每隔0.2s获取下一张png图片,更新到mipmapTexture就可以了?

from caincamera.

CainKernel avatar CainKernel commented on June 30, 2024

是的,就是这么简单,这个跟添加实时水印是同样效果的。只不过的TextureCoordinate的大小和位置不是全屏,并且不是动态的而已。动态贴纸的更新也是这么实现的,就是需要你动态去更新一张贴图,然后等着GPU渲染就好。

from caincamera.

CainKernel avatar CainKernel commented on June 30, 2024

输入的原始图像,跟贴图混合渲染。所有的动态贴纸都是这么做渲染的,upload到mipmapTexture的方式则可以跟我的录制方案一样,另外开一个线程进行,这个要注意OpenGLES 的SharedContext了,不过这个你也可以不用,直接在OpenGLES的渲染线程里面更新贴纸的mipmapTexture。FaceU相机的动态贴纸渲染跟这个glsl也是差不多的。你用SnapDragon Profiler 截一张图片一步步调试就知道了。GPU部分的代码相对简单,动态贴纸的核心还是在应用层的处理策略上。除非你要加自定义的Blend混合了。gl_FragColor = mipmapColor * mipmapColor.a + sourceColor * (1.0 - mipmapColor.a); 这句就是默认的混合方式,跟你调用glBlend是同样的效果。自定义混合就是改这个地方。动态贴纸也是一样的,主要还是在mipmapCoordinate的计算上。这个要你在应用层算好位置的。另外, 支持三维透视变换的Vertex Shader 可以这么写:

uniform mat4 uMVPMatrix;        // 总变换矩阵
uniform mat4 uTexMatrix;        // 输入图像的缩放矩阵
attribute vec4 aPosition;       // 输入图像的位置坐标
attribute vec4 aTextureCoord;   // 输入图像纹理坐标

attribute vec4 aMipmapCoord;    // 贴纸在视锥体空间中的垂直于z轴的假想坐标

uniform int centerX;          // 贴纸处于屏幕的中心位置x
uniform int centerY;          // 贴纸处于屏幕的中心位置y

varying vec2 textureCoordinate; // 输出texture坐标
varying vec2 mipmapCoordinate;  // 输出mipmap坐标

/**
 * 计算贴纸投影到屏幕的UV坐标
 */
vec2 calculateUVPosition(vec4 modelPosition, mat4 mvpMatrix) {
    vec4 tmp = vec4(modelPosition);
    tmp = mvpMatrix * tmp; // gl_Position
    tmp /= tmp.w; // 经过这个步骤,tmp就是归一化标准坐标了.
    tmp = tmp * 0.5 + vec4(0.5f, 0.5f, 0.5f, 0.5f); // NDC坐标
    tmp += vec4(centerx, centerY, 0.5f, 0.5f);// 平移到贴纸中心
    return vec2(tmp.x, tmp.y); // 屏幕的UV坐标
}

void main() {
    // texture的坐标
    textureCoordinate = (uTexMatrix * aTextureCoord).xy;;
    // 变换矩阵
    mipmapCoordinate = calculateUVPosition(aMipmapCoord, uMVPMatrix);
    gl_Position = aPosition;
}

calculateUVPosition 方法是用来做计算经过透视变换到屏幕UV坐标的过程,这里省略掉了平移到世界坐标原点再做透视变换的过程。你也可以不要三维投影的过程,直接用下面的方式直接计算纯二维变换:

mipmapCoordinate = (uMVPMatrix * aMipmapCoord).xy;

from caincamera.

ruijun avatar ruijun commented on June 30, 2024

谢谢你的回答!!还有个问题想问下,渲染指定帧具体是怎样实现的呢?(比如抖音的滤镜特效,长按某种特效,渲染指定的帧,而不是渲染全部)

from caincamera.

CainKernel avatar CainKernel commented on June 30, 2024

from caincamera.

chenliming777 avatar chenliming777 commented on June 30, 2024

您好, 我想咨询一下如何通过106个点计算贴纸的中心点呢(已知2个偏移量坐标以及旋转坐标),看到咱们代码内部有一个centerList貌似通过解析直接过来的,不知道没有centerList如何计算 。有时间帮忙回复一下,谢谢啦

from caincamera.

CainKernel avatar CainKernel commented on June 30, 2024

centerList 就是基准中心点对应的关键点索引。比如鼻子类型的贴纸中心点是人脸关键点46的位置,胡须的话,则是鼻翼两侧的关键点82 和 83的中间值作为中心点。如果你不给中心点的话,你就要对贴纸进行分类了,因为脸颊、耳朵、鼻子、脖子等各个部位的基准中心点是不一样的。没有基准中心点,你就得加入贴纸类型进行判断。要不然你无法定位位置。

from caincamera.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.