原创:好玩的视频人像抠图

2022-04-06 12:42:20 浏览数 (1)

前面文章人像抠图 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 --

0 人点赞