本文章记录对RobustVideoMatting模型进行C++推理的过程。
文章目录
相关参考
本文参考模型代码:
[1]RobustVideoMatting.
本文参考C++推理工具:
[2]lite.ai.toolkit-RVM.
提示:该案例运行环境为Windows+CPU环境
一、基于lite.ai.toolkit的RVM推理编译
1.源码编译
从参考【2】处下载源码后,需要使用cmake进行编译。从官网下载 cmake的GUI版本,安装成功后对RVM源码编译:
Step 1:将源码中lite.ai.toolkit\lib文件夹下的所有依赖库替换(源码中dylib是Mac系统的动态依赖库格式,Windows下是dll格式);将cmakelist.txt中不需要的推理格式(我这里仅保留onnxruntime)注释掉。
Step 2:在cmake中选择好生成路径,点击Configure编译,成功后点击Generate生成。
成功后会提示Configuring done 及 Generating done
Step 3:上述步骤完成后会发现在对应生成路径下有了sln文件。点击进入:
在这里切换版本为Release,右击ALL_BUILD生成:
成功生成后显示如下:
Step 4:下面运行一下看一看吧~
打开test_lite_rvm.cpp,如下图配置好路径后,将lite.ai.toolkit\lib文件夹下所有的dll文件拷贝到RobustVideoMatting-v1.0\examples\build\Release文件夹下
双击lite_rvm.exe,运行结果:
在logs文件夹下即可查看推理结果
以上,一个在Windows+CPU环境下的视频人像分割的C++推理demo就搞定啦~ 接下来我们就在作者原版demo上自己修改玩一下吧!
二、推理功能改进与完善
1.修改背景颜色
lite.ai.toolkit/sourceFile/rvm.cpp更改以下代码(改为白色):
cv::Mat mbmat = bmat.mul(pmat) + rest * 255.;
cv::Mat mgmat = gmat.mul(pmat) + rest * 255.;
cv::Mat mrmat = rmat.mul(pmat) + rest * 255.;
重新生成lite.ai.toolkit.dll,将其copy至与exe相同目录下,得到结果:
2.灵活输入输出
按照原版本,在推理前要把待推理的视频放到resource文件夹下,即路径是写死的。现在简单改动一下,能够让用户在命令行里通过拖拽文件进行推理。
在RobustVideoMatting.lite.ai.toolkit/test_lite_rvm.cpp中,增加获取文件名函数:
//get the file's name that you input
string get_file_name(string file_path)
{
int location = file_path.rfind("\\") + 1;//记录最后一次出现"\"的位置
string file_name = file_path.substr(location);//提取"\"后字符串,作为文件名
return file_name;
}
为test_video()和test_image()增加string类型参数,主函数调用如下:
cout << "请输入待处理视频路径:" << endl;
cin >> VideoPath;
test_video(VideoPath);
cout << "请输入待处理图片路径:(若无输入图片退出即可)" << endl;
cin >> ImagePath;
test_image(ImagePath);
重新编译后,将文件拖拽到命令行中,即可get到文件的路径,进行推理啦:
3.同时输出视频mask和result
为了方便对MIOU评价指标的计算,同时能够更好地呈现结果,现在试试同时输出mask和result吧
在lite.ai.toolkit/rvm.cpp中,修改函数detect_video,增加一输出路径,函数更改后如下:
void RobustVideoMatting::detect_video(const std::string &video_path,
const std::string &output_path,
//
// const std::string &output_path_mask,
//
std::vector<types::MattingContent> &contents,
bool save_contents, float downsample_ratio,
unsigned int writer_fps)
{
int location = output_path.rfind("\\") + 1;
const std::string fileName = output_path.substr(location);
const std::string fileNameMask = "mask_" + fileName;
const std::string output_path_mask = output_path.substr(0,location)+fileNameMask;
// 0. init video capture
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())
{
std::cout << "Can not open video: " << video_path << "\n";
return;
}
// 1. init video writer
cv::VideoWriter video_writer(output_path, cv::VideoWriter::fourcc('m', 'p', '4', 'v'),
writer_fps, cv::Size(width, height));
//
cv::VideoWriter video_writer_mask(output_path_mask, cv::VideoWriter::fourcc('m', 'p', '4', 'v'),
writer_fps, cv::Size(width, height));
//
if (!video_writer.isOpened())
{
std::cout << "Can not open writer: " << output_path << "\n";
return;
}
//
if (!video_writer_mask.isOpened())
{
std::cout << "Can not open writer mask: " << output_path_mask << "\n";
return;
}
//
// 2. matting loop
cv::Mat mat;
unsigned int i = 0;
while (video_capture.read(mat))
{
i += 1;
types::MattingContent content;
this->detect(mat, content, downsample_ratio);
// 3. save contents and writing out.
if (content.flag)
{
if (save_contents) contents.push_back(content);
if (!content.merge_mat.empty()) video_writer.write(content.merge_mat);
if(!content.pha_mat.empty())video_writer_mask.write(content.pha_mat * 255.);
}
// 4. check context states.
if (!context_is_update) break;
#ifdef LITEORT_DEBUG
std::cout << i << "/" << frame_count << " done!" << "\n";
#endif
}
// 5. release
video_capture.release();
video_writer.release();
//
video_writer_mask.release();
//
}
接下来推一个demo试试看:
结果输出如下:
OK,实现mask和result同时输出啦!
嗷对了,记得将新生成的lite.ai.toolkit.dll复制到exe同路径下!
4.可在控制台选择模型 | 下采样比 | 推理线程数
由于不同模型及下采样比适用的效果不同,同时不同机器的CPU型号不一样,最大的推理线程数也不同。为了方便使用,我这里将这些功能集成到控制台里能够自由选择,使用时的效果如下:
5.视频抠图可实现背景替换
之前将视频中的人像分割出来以后我们仅将背景颜色做了一定修改,现在能否给视频换个背景呢?
lite.ai.toolkit作者最近将背景替换功能加入了工具箱中,现在我们将这部分功能添加到这个独立的子工程里。
重新编译lite.ai.toolkit,将最新生成的lite.ai.toolkit.dll、lite.ai.toolkit.exp、lite.ai.toolkit.lib拷贝至lite_rvm相同的目录下:
修改rvm.h中detect_video()和detect()接口:
void detect(const cv::Mat& mat, types::MattingContent& content,
float downsample_ratio = 0.25f, bool video_mode = false,
bool remove_noise = false, bool minimum_post_process = false);
void detect_video(const std::string& video_path,
const std::string& output_path,
std::vector<types::MattingContent>& contents,
bool save_contents = false,
float downsample_ratio = 0.25f,
unsigned int writer_fps = 20,
bool remove_noise = false,
bool minimum_post_process = false,
const cv::Mat& background = cv::Mat());
在utils.h中加入新增功能函数定义:
//Matting&Segmentation Utils
LITE_EXPORTS void swap_background(const cv::Mat& fgr_mat, const cv::Mat& pha_mat, const cv::Mat& bgr_mat, cv::Mat& out_mat, bool fgr_is_already_mul_pha = false);
LITE_EXPORTS void remove_small_connected_area(cv::Mat& alpha_pred, float threshold = 0.05f);
现在我们来推一个视频看看吧:
输出结果:
总结
本文最终经过改进的应用程序可以直接下载使用:
(背景替换功能暂未添加)
下载地址: 视频人像分割系统
提取码:o9jl
另外需要源码学习的小伙伴可在下面链接中找到Windows端能够运行的lite.ai.toolkit :下载地址: 视频人像分割系统源码
提取码:nuxp