前言

1.抠图技术应用很广泛,比如证件照,美体,人体区域特殊处理,还有B站的字幕穿人效果等等。这些的关键技术都在于高精度高性能的分割算法。RobustVideoMatting是来自字节跳动视频人像抠图算法(RVM),专为稳定人物视频抠像设计。 不同于现有神经网络将每一帧作为单独图片处理,RVM 使用循环神经网络,在处理视频流时有时间记忆。RVM 可在任意视频上做实时高清人像抠图。
2.关于RobustVideoMatting算法和模型训练步骤可以直接转到官方的git:https://github.com/PeterL1n/RobustVideoMatting。这里只实现模型的C++推理与部署。
3.使用的开发环境是win10,显卡RTX3080,cuda11.2,cudnn8.1,OpenCV4.5,onnxruntime,IDE 是Vs2019。

一、模型与依赖

1.官方公布了很多种格式的模型,有mnn,ncnn,onnx等等,这里使用的是onnx这个模型,直接从这官方公布的地址(gym7)下载就可以了。

2.onnxruntime直接下载 官方编译好的release版本就可以使用了。

3.如果想用GPU进行推理,则要下载安装cuda,cudnn,具体安装方法网上有很多种,可以参考。

二、代码

1.推理代码

typedef struct MattingContentType
{Mat fgr_mat; Mat pha_mat;Mat merge_mat;bool flag;MattingContentType() : flag(false){};
} MattingContent;class RobustVideoMatting
{public:RobustVideoMatting(string model_path);void detect(const Mat& mat, MattingContent& content, float downsample_ratio);
private:Session* session_;Env env = Env(ORT_LOGGING_LEVEL_ERROR, "robustvideomatting");SessionOptions sessionOptions = SessionOptions();unsigned int num_inputs = 6;vector<const char*> input_node_names = {"src","r1i","r2i","r3i","r4i","downsample_ratio"};vector<vector<int64_t>> dynamic_input_node_dims = {{1, 3, 1280, 720}, {1, 1, 1,    1}, {1, 1, 1,    1}, {1, 1, 1,    1},{1, 1, 1,    1},{1} };unsigned int num_outputs = 6;vector<const char*> output_node_names = {"fgr","pha","r1o","r2o","r3o","r4o"};vector<float> dynamic_src_value_handler;vector<float> dynamic_r1i_value_handler = { 0.0f }; vector<float> dynamic_r2i_value_handler = { 0.0f };vector<float> dynamic_r3i_value_handler = { 0.0f };vector<float> dynamic_r4i_value_handler = { 0.0f };vector<float> dynamic_dsr_value_handler = { 0.25f }; int64_t value_size_of(const std::vector<int64_t>& dims);bool context_is_update = false;void normalize_(Mat img, vector<float>& output);vector<Ort::Value> transform(const Mat& mat);void generate_matting(vector<Ort::Value>& output_tensors, MattingContent& content);void update_context(vector<Ort::Value>& output_tensors);
};RobustVideoMatting::RobustVideoMatting(string model_path)
{wstring widestr = wstring(model_path.begin(), model_path.end());sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_EXTENDED);session_ = new Session(env, widestr.c_str(), sessionOptions);
}void RobustVideoMatting::normalize_(Mat img, vector<float>& output)
{int row = img.rows;int col = img.cols;for (int c = 0; c < 3; c++){for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {float pix = img.ptr<uchar>(i)[j * 3 + 2 - c]; output[c * row * col + i * col + j] = pix / 255.0;}}}
}int64_t RobustVideoMatting::value_size_of(const std::vector<int64_t>& dims)
{if (dims.empty()) return 0;int64_t value_size = 1;for (const auto& size : dims) value_size *= size;return value_size;
}vector<Ort::Value> RobustVideoMatting::transform(const Mat& mat)
{Mat src = mat.clone();const unsigned int img_height = mat.rows;const unsigned int img_width = mat.cols;vector<int64_t>& src_dims = dynamic_input_node_dims.at(0); src_dims.at(2) = img_height;src_dims.at(3) = img_width;std::vector<int64_t>& r1i_dims = dynamic_input_node_dims.at(1); std::vector<int64_t>& r2i_dims = dynamic_input_node_dims.at(2); std::vector<int64_t>& r3i_dims = dynamic_input_node_dims.at(3); std::vector<int64_t>& r4i_dims = dynamic_input_node_dims.at(4);std::vector<int64_t>& dsr_dims = dynamic_input_node_dims.at(5); int64_t src_value_size = this->value_size_of(src_dims); int64_t r1i_value_size = this->value_size_of(r1i_dims); int64_t r2i_value_size = this->value_size_of(r2i_dims); int64_t r3i_value_size = this->value_size_of(r3i_dims); int64_t r4i_value_size = this->value_size_of(r4i_dims); int64_t dsr_value_size = this->value_size_of(dsr_dims); dynamic_src_value_handler.resize(src_value_size);this->normalize_(src, dynamic_src_value_handler);std::vector<Ort::Value> input_tensors;auto allocator_info = MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);input_tensors.push_back(Value::CreateTensor<float>(allocator_info, dynamic_src_value_handler.data(), dynamic_src_value_handler.size(), src_dims.data(), src_dims.size()));input_tensors.push_back(Value::CreateTensor<float>(allocator_info, dynamic_r1i_value_handler.data(), r1i_value_size, r1i_dims.data(), r1i_dims.size()));input_tensors.push_back(Value::CreateTensor<float>(allocator_info, dynamic_r2i_value_handler.data(), r2i_value_size, r2i_dims.data(), r2i_dims.size()));input_tensors.push_back(Value::CreateTensor<float>(allocator_info, dynamic_r3i_value_handler.data(), r3i_value_size, r3i_dims.data(), r3i_dims.size()));input_tensors.push_back(Value::CreateTensor<float>(allocator_info, dynamic_r4i_value_handler.data(), r4i_value_size, r4i_dims.data(), r4i_dims.size()));input_tensors.push_back(Value::CreateTensor<float>(allocator_info, dynamic_dsr_value_handler.data(), dsr_value_size, dsr_dims.data(), dsr_dims.size()));return input_tensors;
}void RobustVideoMatting::generate_matting(std::vector<Ort::Value>& output_tensors, MattingContent& content)
{Ort::Value& fgr = output_tensors.at(0); Ort::Value& pha = output_tensors.at(1); auto fgr_dims = fgr.GetTypeInfo().GetTensorTypeAndShapeInfo().GetShape();auto pha_dims = pha.GetTypeInfo().GetTensorTypeAndShapeInfo().GetShape();const unsigned int height = fgr_dims.at(2);const unsigned int width = fgr_dims.at(3); const unsigned int channel_step = height * width;float* fgr_ptr = fgr.GetTensorMutableData<float>();float* pha_ptr = pha.GetTensorMutableData<float>();Mat rmat(height, width, CV_32FC1, fgr_ptr);Mat gmat(height, width, CV_32FC1, fgr_ptr + channel_step);Mat bmat(height, width, CV_32FC1, fgr_ptr + 2 * channel_step);Mat pmat(height, width, CV_32FC1, pha_ptr);rmat *= 255.;bmat *= 255.;gmat *= 255.;Mat rest = 1. - pmat;Mat mbmat = bmat.mul(pmat) + rest * 153.;Mat mgmat = gmat.mul(pmat) + rest * 255.;Mat mrmat = rmat.mul(pmat) + rest * 120.;std::vector<Mat> fgr_channel_mats, merge_channel_mats;fgr_channel_mats.push_back(bmat);fgr_channel_mats.push_back(gmat);fgr_channel_mats.push_back(rmat);merge_channel_mats.push_back(mbmat);merge_channel_mats.push_back(mgmat);merge_channel_mats.push_back(mrmat);content.pha_mat = pmat;merge(fgr_channel_mats, content.fgr_mat);merge(merge_channel_mats, content.merge_mat);content.fgr_mat.convertTo(content.fgr_mat, CV_8UC3);content.merge_mat.convertTo(content.merge_mat, CV_8UC3);content.flag = true;
}void RobustVideoMatting::update_context(std::vector<Ort::Value>& output_tensors)
{Ort::Value& r1o = output_tensors.at(2);Ort::Value& r2o = output_tensors.at(3); Ort::Value& r3o = output_tensors.at(4); Ort::Value& r4o = output_tensors.at(5); auto r1o_dims = r1o.GetTypeInfo().GetTensorTypeAndShapeInfo().GetShape();auto r2o_dims = r2o.GetTypeInfo().GetTensorTypeAndShapeInfo().GetShape();auto r3o_dims = r3o.GetTypeInfo().GetTensorTypeAndShapeInfo().GetShape();auto r4o_dims = r4o.GetTypeInfo().GetTensorTypeAndShapeInfo().GetShape();dynamic_input_node_dims.at(1) = r1o_dims;dynamic_input_node_dims.at(2) = r2o_dims;dynamic_input_node_dims.at(3) = r3o_dims;dynamic_input_node_dims.at(4) = r4o_dims;int64_t new_r1i_value_size = this->value_size_of(r1o_dims); int64_t new_r2i_value_size = this->value_size_of(r2o_dims); int64_t new_r3i_value_size = this->value_size_of(r3o_dims);int64_t new_r4i_value_size = this->value_size_of(r4o_dims); dynamic_r1i_value_handler.resize(new_r1i_value_size);dynamic_r2i_value_handler.resize(new_r2i_value_size);dynamic_r3i_value_handler.resize(new_r3i_value_size);dynamic_r4i_value_handler.resize(new_r4i_value_size);float* new_r1i_value_ptr = r1o.GetTensorMutableData<float>();float* new_r2i_value_ptr = r2o.GetTensorMutableData<float>();float* new_r3i_value_ptr = r3o.GetTensorMutableData<float>();float* new_r4i_value_ptr = r4o.GetTensorMutableData<float>();std::memcpy(dynamic_r1i_value_handler.data(), new_r1i_value_ptr, new_r1i_value_size * sizeof(float));std::memcpy(dynamic_r2i_value_handler.data(), new_r2i_value_ptr, new_r2i_value_size * sizeof(float));std::memcpy(dynamic_r3i_value_handler.data(), new_r3i_value_ptr, new_r3i_value_size * sizeof(float));std::memcpy(dynamic_r4i_value_handler.data(), new_r4i_value_ptr, new_r4i_value_size * sizeof(float));context_is_update = true;
}void RobustVideoMatting::detect(const Mat& mat, MattingContent& content, float downsample_ratio)
{if (mat.empty()) return;dynamic_dsr_value_handler.at(0) = downsample_ratio;std::vector<Ort::Value> input_tensors = this->transform(mat);auto output_tensors = session_->Run(Ort::RunOptions{ nullptr }, input_node_names.data(),input_tensors.data(), num_inputs, output_node_names.data(),num_outputs);this->generate_matting(output_tensors, content);context_is_update = false; this->update_context(output_tensors);
}

2.对图像中的人像进行抠图:

void detect_image(const cv::Mat& cv_src, string model_path)
{const float downsample_ratio = 0.2;RobustVideoMatting rvm(model_path);MattingContent content;rvm.detect(cv_src, content, downsample_ratio);namedWindow("src", 0);imshow("src", cv_src);namedWindow("matting", 0);imshow("matting", content.pha_mat * 255.);namedWindow("merge", 0);imshow("merge", content.merge_mat);waitKey(0);
}

执行效果:


3.对视频进行人像抠图

void detect_video(const std::string video_path, string model_path)
{const float downsample_ratio = 0.25;RobustVideoMatting rvm(model_path);cv::VideoCapture video_capture(video_path);const unsigned int width = video_capture.get(cv::CAP_PROP_FRAME_WIDTH);const unsigned int height = video_capture.get(cv::CAP_PROP_FRAME_HEIGHT);const unsigned int frame_count = video_capture.get(cv::CAP_PROP_FRAME_COUNT);if (!video_capture.isOpened()){return;}cv::Mat cv_src;while (video_capture.read(cv_src)){MattingContent content;rvm.detect(cv_src, content, downsample_ratio);namedWindow("src", 0);imshow("src", cv_src);namedWindow("matting", WINDOW_NORMAL);imshow("matting", content.pha_mat);namedWindow("merge", WINDOW_NORMAL);imshow("merge", content.merge_mat);waitKey(10);}
}

执行效果:




三、源码

1.源码地址:https://download.csdn.net/download/matt45m/86821062
2.下载源码后解压,使用vs2019打开,images和video是测试的图像和视频,lib里面有使用到的依赖库,include依赖的头文件。

3.配置include和lib路径

4.添加lib,把lib目录下所有.lib后缀的添加到依赖项。

5.运行配置

人像抠图——基于深度学习一键去除视频背景相关推荐

  1. Matting(抠图)--用深度学习自动去除照片背景

    转自:https://zhuanlan.zhihu.com/p/38031181 https://zhuanlan.zhihu.com/p/151212267 现在又有一个 AI 能干 Photosh ...

  2. 山东大学项目实训小组一——基于深度学习的AI视频剪辑器“易剪”

    技术要点:图像处理 计算机视觉 深度学习 多媒体前端 一.项目研究背景: 随着短视频热潮的兴起,越来越多的人投入精力到了视频剪辑视频制作之中.然而利用现有的视频剪辑工具,剪辑一段视频是非常麻烦的,尤其 ...

  3. 目标检测,FFmpeg中第一个基于深度学习模型的视频分析功能

    2021年4月,终于把目标检测(object detection)加到FFmpeg upstream了,有maintainer身份加持,还是交互了将近100封邮件,花了两个多月才完成upstream, ...

  4. 基于深度学习算法实现视频人脸自动打码

    前言 1.在当下的环境上,短视频已是生活的常态,但这是很容易就侵犯别人肖像权,好多视频都会在后期给不相关的人打上码,这里是基于yolov5的人脸检测实现人脸自动打码功能. 2.开发环境是win10,显 ...

  5. DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对《我要打篮球》视频段进行实时目标检测

    DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对<我要打篮球>视频段进行实时目标检测 目录 输出结果 设计思路 核心代码 相关文章 成功解决AttributeError ...

  6. DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对《俄罗斯总统普京对沙特王储摊的“友好摊手”瞬间—东道主俄罗斯5-0完胜沙特》视频段实时检测

    DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对<俄罗斯总统普京对沙特王储摊的"友好摊手"瞬间-东道主俄罗斯5-0完胜沙特>视频段实时检测 导读   ...

  7. CV:基于深度学习实现目标检测之GUI界面产品设计并实现图片识别、视频识别、摄像头识别(准确度非常高)

    CV:基于深度学习实现目标检测之GUI界面产品设计并实现图片识别.视频识别.摄像头识别(准确度非常高) 目录 GUI编程设计界面 产品演示 GUI编程设计界面 产品演示 视频演示:https://bl ...

  8. ECCV 2018论文解读 | DeepVS:基于深度学习的视频显著性方法

    作者丨蒋铼 学校丨北京航空航天大学在校博士,大不列颠哥伦比亚大学联合培养博士 研究方向丨计算机视觉 本文概述了来自北京航空航天大学徐迈老师组 ECCV 2018 的工作 DeepVS: A Deep ...

  9. 基于深度学习的视频预测研究综述

    原址:http://html.rhhz.net/tis/html/201707032.htm (收集材料ing,为论文做准备)[综述性文章,,,可以做背景资料] 莫凌飞, 蒋红亮, 李煊鹏 摘要:近年 ...

  10. 中国人工智能学会通讯——基于视频的行为识别技术 1.5 基于深度学习的视频识别方法...

    1.5 基于深度学习的视频识别方法 下面介绍面向视频分类的深度学习方 法.深度卷积神经网络在图像分类取得 成功后,研究人员就希望把它推广到视 频分类中.但这不是一件很容易的事, 一个原因是缺乏足够的训 ...

最新文章

  1. Unit Testing for WinForm
  2. mysql中的if [not] exists
  3. 改jpg_|我来改第04期|—人物海报设计
  4. metronic-Website Template
  5. ACM做题过程中的一些小技巧
  6. JDK11+Maven开发JavaFx启动问题:java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper
  7. 07-12-Exchange Server 2019-安装-CU1
  8. itextpdf 二维码
  9. 安卓开发之ListView优化方案
  10. FullCalendar - 开源的多功能 JavaScript 日历插件
  11. oppo preloader驱动_手机企业冲向IoT新赛道,HOMA格局下OPPO有何不同?
  12. 如何把word文档转换成jpg图片
  13. 【期末划重点】数据库速成
  14. AdSense后台添加美国税务信息W-8BEN纳税表秒过的详细操作图文教程
  15. python 实现Web版股票行情界面
  16. Bootstrap——制作个人简历网页、工具类【边框(添加、删除、颜色、圆角)、清除浮动、颜色(文本、链接、背景)、display属性、浮动、定位、文本对齐】
  17. idea如何全局搜索关键字_intellij idea 怎么全局搜索
  18. 加号和字符串拼接符号
  19. VMware ESX 4.1版本,浏览器无法访问问题【已解决】
  20. context.write

热门文章

  1. python-静态网页爬取
  2. 国密算法 SM2 公钥加密 非对称加密 数字签名 密钥协商 python实现完整代码
  3. vs2015 相关
  4. JS中变量存储在堆中还是栈中?(深入内存原理)
  5. PAT乙级1068 万绿丛中一点红(测试点3、测试点5)
  6. Linux搭建Linpack环境测试GPU性能
  7. 离散数学-各种关联词的符号化
  8. 数组去重几种常见的方法
  9. 如何平衡CVR预估中的延迟反馈问题?(内含招聘)
  10. JavaWeb学习笔记(十三)之session的钝化和活化