查看原文
其他

人像抠图 + OpenGL ES 还能这样玩?没想到吧

字节流动 字节流动 2022-04-23


人像留色的原理

现在人像分割技术就像当初的人脸检测算法一样,称为广泛使用的基础算法。


今天本文介绍的人像留色其实就是三年前某 AI 巨头利用 video 分割技术展示的应用场景:人体区域保留彩色,人体区域之外灰度化。所以人像留色的关键技术在于高精度高性能的分割算法。


OpenGL ES 利用抠图算法实现人像留色


首先利用分割算法获取到人像的 mask 图(灰度图),其中人像区域的灰度值大于 0 ,非人像区域的灰度值等于 0 。在 shader 中,首先对 mask 图采样判断采样点是否位于人像区域,然后分别进行不同的处理。


获取人像 mask 图

那么如何获取人像 mask 图?Github 上已经有很多大神开源了相关的分割或者抠图算法。


这里推荐 3 个比较受欢迎的开源项目。


Multi-Human-Parsing

Multi-Human-Parsing


Multi-Human-Parsing 的优势在于支持多人不同部位的分割,同时支持目标检测和人体部位分割。


Multi-Human-Parsing 将人群场景图像划分为语义一致的属于身体部位或衣服物品的区域,从而为图像中的每个像素分配一个语义部位标签,以及它所属的身份。


有很多应用场景,如虚拟现实、视频监控、群体行为分析等。Multi-Human-Parsing 的分割精度对于人体关键点检测其实够用了。


项目地址:
https://github.com/ZhaoJ9014/Multi-Human-Parsing


BackgroundMattingV2

Real-Time High-Resolution Background Matting


大名鼎鼎的 BackgroundMattingV2 算法,这也是本文所使用的抠图算法,主要特点就是实时、高分辨率、高精度的分割(Background Matting),项目免费可商用


但是要在移动端落地的话,性能将会是很大的瓶颈,需要进行大量的算法优化,这也是目前大部分 AI 算法面临的问题:如何将 AI 算法落地到低算力平台


项目地址:
https://github.com/PeterL1n/BackgroundMattingV2


TensorFlow Lite

TensorFlow Lite


TensorFlow Lite 是针对移动端的开源机器学习框架,支持 Android 和 iOS,提供了丰富的算法模型,包括图像分割、目标检测、图像分类、超分等模型。


其中分割模型支持的场景比较丰富,包括人体、宠物和物体等。

val labelsArrays = arrayOf(
"background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus",
"car", "cat", "chair", "cow", "dining table", "dog", "horse", "motorbike",
"person", "potted plant", "sheep", "sofa", "train", "tv"
)

TensorFlow Lite 所提供的分割模型,使用 GPU 的话,单张 2K 的图处理时间在几百毫秒,基本上做不了 video 处理,另外分割精度也是 demo 级别的


项目地址:
https://github.com/tensorflow/examples/tree/master/lite/examples/image_segmentation


人像留色的实现

人像留色 2


用于实现人像留色的简单 shader :

#version 300 es
precision mediump float;
in vec2 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform sampler2D u_texture0;//rgba
uniform sampler2D u_texture1;//人像灰度图
uniform int u_renderType;
uniform float u_offset;
void main()
{
float gray = texture(u_texture1, v_texCoord).r;//对 mask 进行采样
vec4 rgba = texture(u_texture0, v_texCoord);
if(gray > 0.01) {
outColor = rgba;
}
else
{
float Y = 0.299 * rgba.r + 0.587 * rgba.g + 0.114 * rgba.b;//RGB 灰度化
vec4 grayColor = vec4(vec3(Y), 1.0);
outColor = mix(grayColor, rgba, u_offset);//混合渐变
}
}

shader 中首先对 mask 采样,然后判断采样点是否位于人像区域(灰度值是否大于 0 ),若采样点位于人像区域外,对颜色进行灰度化。


另外需要注意 OpenGL 访问的图像内存默认是 4 字节对齐,这样灰度 Mask 图的宽度不是 4 的整数倍的话,会有花屏现象,这里需要取消对齐设置:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_GrayTexId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_GrayImage.width, m_GrayImage.height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_GrayImage.ppPlane[0]);
glBindTexture(GL_TEXTURE_2D, GL_NONE);

完整实现代码见项目:
https://github.com/githubhaohao/NDK_OpenGLES_3_0



-- END --


进技术交流群,扫码添加我的微信:Byte-Flow



获取视频教程和源码



推荐:

Android FFmpeg 实现带滤镜的微信小视频录制功能

全网最全的 Android 音视频和 OpenGL ES 干货,都在这了

一文掌握 YUV 图像的基本处理

Android FFmpeg 流媒体边播放边录制功能

FFmpeg + Android AudioRecorder 音频录制编码

利用 FFmpeg 和 ANativeWindow 实现视频解码播放

FFmpeg、x264以及fdk-aac 编译整合

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存