一、人像抠图的应用场景
1. 图像编辑:在图像编辑软件中,人像抠图是常用操作之一。通过抠图可以将人物从原背景中分离出来,放到新背景中,实现人物换背景的效果。这在电影后期特效、游戏角色置换等领域有很广泛的应用。
2. 视频特效:在视频编辑与特效制作中,人像抠图也是关键技术之一。通过实时对视频帧中的人物进行抠图与追踪,可以实现人物消失、人物换衣等特效,大大丰富视频的视觉效果。3. AR特效:在AR(增强现实)与静止画面中的特效制作中,抠取人物或目标物体是非常重要的一步。只有准确抠取人物或物体,才能在现实场景中实时替换或跟踪,实现各种有趣的AR特效。这在很多手机AR美妆与界面中都有所体现。4. 人脸识别:在人脸识别系统中,检测和定位人脸是第一步,人像抠图技术 frequently 被用来辅助检测和定位过程,提高系统的性能与准确率。5. 虚拟化妆:通过人像抠图,可以分离出人物的脸部区域。然后在脸部区域上添加各种妆容与装饰,再融合回原图像,实现给人物戴上各种动态妆容与装饰的效果,这在现代化妆领域有较广泛需求。综上,人像抠图在图像处理、计算机视觉与人工智能等领域有着很重要的应用价值。随着相关技术的进步,人像抠图的效果不断提高,应用范围也在持续扩展,它作为基础技术将服务于更加多元化的应用场景。这也为从事相关行业的研究人员和开发者带来很多机会与挑战。
二、抠图效果
遍历文件夹抠图
视频人像抠图
三、部署
从参考网址1下载源码,按照Readme文件,下载onnxruntime-win-x64-gpu-1.9.0,添加(opencv4.5.5和onnxruntime-win-x64-gpu-1.9.0)的包含目录、库目录、windows运行库目录,链接器-输入-附加依赖项(opencv_world455.lib、onnxruntime.lib)。
配置属性-Vcpkg-Use Vcpkg设置为否
修改头文件里的 cuda引用
//#include <cuda_provider_factory.h>
#include <tensorrt_provider_factory.h>
修改Detect_video.cpp文件
#include "Detect_video.h"
#include "Detect.h"
// 调用摄像头或者读取本地视频文件,进行抠图效果展示
void detect_video(float downsample_ratio, Ort::Session& session, string choose,
std::vector<std::vector<int64_t>>& dynamic_input_node_dims,
std::vector<float>& dynamic_src_value_handler,
std::vector<float>& dynamic_r1i_value_handler,
std::vector<float>& dynamic_r2i_value_handler,
std::vector<float>& dynamic_r3i_value_handler,
std::vector<float>& dynamic_r4i_value_handler,
std::vector<float>& dynamic_dsr_value_handler,
std::vector<const char*>& input_node_names,
std::vector<const char*>& output_node_names,
bool& context_is_update,
unsigned int& num_inputs,
unsigned int& num_outputs
)
{
double inferenceTime = 0.0;
cv::VideoCapture video_capture;
cv:String outpath;
// 选择视频地址抠图或者摄像头抠图
if (choose == "movie") {
cout << "视频地址:" << endl;
cin >> choose;
video_capture.open(choose);
outpath = choose + "_out.mp4";
}
else
{
cout << "请输入调用摄像头的序号:" << endl;
int num = 0;
cin >> num;
video_capture.open(num);
outpath= cv::format("%d", num) + "_out.mp4";
}
if (!video_capture.isOpened())
{
std::cout << "Can not open video" << "\n";
return;
}
// 获取视频信息
int fps = video_capture.get(cv::CAP_PROP_FPS);
cv::Size size = cv::Size((int)video_capture.get(cv::CAP_PROP_FRAME_WIDTH),
(int)video_capture.get(cv::CAP_PROP_FRAME_HEIGHT));
// 创建视频写入对象
cv::VideoWriter outputVideo;
//cv:String outpath = choose == "movie" ? choose + "_out.mp4" : cv::format("%d",num) + "_out.mp4";
outputVideo.open(outpath,
cv::VideoWriter::fourcc('M', 'J', 'P', 'G'),
fps, size, true);
if (!outputVideo.isOpened()) {
printf("Failed to open video writer!");
return ;
}
// 2. matting loop
cv::Mat mat,dst1,dst2;
while (video_capture.read(mat))
{
//开始时间
double t1 = static_cast<double>(cv::getTickCount());
cv::resize(mat, dst1, cv::Size(), 0.5, 0.5, cv::INTER_NEAREST);
cv::imshow("原图", dst1);
// 人像抠图
mat = detect_human(mat, downsample_ratio, session,
dynamic_input_node_dims,
dynamic_src_value_handler,
dynamic_r1i_value_handler,
dynamic_r2i_value_handler,
dynamic_r3i_value_handler,
dynamic_r4i_value_handler,
dynamic_dsr_value_handler,
input_node_names,
output_node_names,
context_is_update,
num_inputs,
num_outputs
);
// 人像抠图显示mask
/*mat = detect(mat,true, downsample_ratio, session,
dynamic_input_node_dims,
dynamic_src_value_handler,
dynamic_r1i_value_handler,
dynamic_r2i_value_handler,
dynamic_r3i_value_handler,
dynamic_r4i_value_handler,
dynamic_dsr_value_handler,
input_node_names,
output_node_names,
context_is_update,
num_inputs,
num_outputs
);*/
//结束时间,计算fps
double t2 = static_cast<double>(cv::getTickCount());
inferenceTime = (t2 - t1) / cv::getTickFrequency() * 1000;
std::stringstream fpsSs;
fpsSs << "FPS: " << int(1000.0f / inferenceTime * 100) / 100.0f;
// 向每帧写入fps
cv::putText(mat, fpsSs.str(), cv::Point(16, 32),
cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255));
//缩放显示
cv::resize(mat, dst2, cv::Size(), 0.5, 0.5, cv::INTER_NEAREST);
cv::imshow("抠图", dst2);
// 写入该帧到视频
if (outputVideo.isOpened())
outputVideo.write(mat);
cv::waitKey(1);
// 4. check context states.
if (!context_is_update) break;
if (_kbhit()) // 如果有按键被按下
{
if (_getch() == 'q') //如果按下了q键则跳出循环
{
break;
}
}
}
// 5. release
video_capture.release();
outputVideo.release();
destroyAllWindows();
}
main.cpp
void showmenu()
{
printf("----菜单----\n");
printf("1-遍历文件夹抠图(保存对应抠图文件,默认选项)\n");
printf("2-图片抠图展示(不保存)\n");
printf("3-视频抠图展示(保存)\n");
printf("4-摄像头抠图展示(保存)\n");
printf("5-摄像头换背景展示(不保存)\n");
printf("0-退出函数\n");
}
生成程序后,因为我的cuda路径有好几个版本
所以,根据缺少的dll提示,将C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1 下的所有dll拷贝到 Release 下。缺少的hdf5.dll 也从系统里找到(everything搜索在V:\vcpkg-master\installed\x64-windows\bin 里有个,别的地方也有),拷贝进来。
OK,这么整下来,不在vs环境下运行,直接双击生成的exe没问题了。
参考网址:
1. https://github.com/caip1299920300/RobustVideoMatting_onnxruntime (源码地址)
2. https://github.com/microsoft/onnxruntime/releases/tag/v1.9.0
The End