前面文章人像抠图 OpenGL ES 还能这样玩?没想到吧,我们介绍了利用人像抠图算法生成的 mask 图,然后结合 OpenGL 可以产生一些有趣的效果。
抠图技术应用很广泛,比如很多手机的相机自带“人像留色”滤镜:人体区域保留彩色,人体区域之外灰度化。所以人像留色的关键技术在于高精度高性能的分割算法。
本文将基于开源的人像抠图算法模型和 OpenGL 做一个实时的人像分割 app , 该 app 目前已开源,感兴趣的同学可以参考该项目利用matting算法做一些有趣的特效。
本文主要参考飞鸽传书的开源项目 ncnn_Android_RobustVideoMatting ,它使用的是腾讯的 ncnn 神经网络计算框架,ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架。无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。
ncnn 地址:https://github.com/Tencent/ncnn
不过 ncnn_Android_RobustVideoMatting 数据源使用的是 NdkCamera ,这对做应用层开发的同学来说,学习和移植起来很不方便。
所以本文采用 Android Camera2 (Java)获取实时预览图像,将算法模型和 OpenGL 渲染控件封装成一个类,初学者可以很方便地利用这些类进行移植和二次开发,可以轻易实现自己想要的效果。
将算法模型封装成一个类,可以很方便将其移植到你的播放器或者相机里。
代码语言:javascript复制#ifndef NCNN_ANDROID_ROBUSTVIDEOMATTING_MAIN_BODYSEG_H
#define NCNN_ANDROID_ROBUSTVIDEOMATTING_MAIN_BODYSEG_H
#include <ImageDef.h>
#include <android/looper.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc.hpp>
#include <android/asset_manager_jni.h>
#include <android/sensor.h>
#include "LogUtil.h"
#include "nanodet.h"
class BodySeg {
public:
BodySeg(){}
~BodySeg(){}
void Init(AAssetManager* mgr);
void SetCameraOrt(int ort);
void Process(NativeImage *pInput, NativeImage *pOutput, NativeImage *pOutMask);
void UnInit();
private:
void LoadModel(AAssetManager* mgr);
private:
int camera_facing;
int camera_orientation;
mutable int accelerometer_orientation;
ASensorManager* sensor_manager = nullptr;
mutable ASensorEventQueue* sensor_event_queue = nullptr;
const ASensor* accelerometer_sensor = nullptr;
NanoDet* nanoDet = nullptr;
};
模型类封装的非常简单,Process 执行分割输出分割结果和 mask 图。
Java 层获取相机预览数据传入 Native 做分割处理。
代码语言:javascript复制 private ImageReader.OnImageAvailableListener mOnPreviewImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image != null) {
if (mCamera2FrameCallback != null) {
mCamera2FrameCallback.onPreviewFrame(CameraUtil.YUV_420_888toNV21(image), image.getWidth(), image.getHeight());
}
image.close();
}
}
};
Native 层渲染 Matting 结果和 mask 灰度图的类(渲染控件)。
代码语言:javascript复制class GLCameraRender: public BaseGLRender {
public:
//初始化预览帧的宽高
virtual void Init(AAssetManager* mgr);
//渲染一帧视频
virtual void RenderVideoFrame(NativeImage *pImage, NativeImage **ppSegResult);
virtual void UnInit();
//GLSurfaceView 的三个回调
virtual void OnSurfaceCreated();
virtual void OnSurfaceChanged(int w, int h);
virtual void OnDrawFrame();
static GLCameraRender *GetInstance();
static void ReleaseInstance();
//更新变换矩阵,Camera预览帧需要进行旋转
virtual void UpdateMVPMatrix(int angleX, int angleY, float scaleX, float scaleY);
private:
GLCameraRender();
virtual ~GLCameraRender();
bool CreateFrameBufferObj();
void GetRenderFrameFromFBO();
......
};
渲染组件类包含了 GLSurfaceView 的三个回调,主要就是借助于 GLSurfaceView 创建 OpenGL 渲染上下文环境,RenderVideoFrame 传入 matting 结果和相关的 mask 灰度图,然后进行上屏渲染。
-- END --