相关链接:

【Matting】MODNet:实时人像抠图模型-onnx python部署

【Matting】MODNet:实时人像抠图模型-笔记

【Matting】MODNet:实时人像抠图模型-onnx C++部署

MODNet是一个轻量级Matting模型,之前已经使用python部署MODNet的onnx模型,本章节将使用NCNN部署MODNet,除此之外,对模型进行静态量化,使其大小降低原模型的为1/4。Matting效果如下:

完整的代码和所需权重在文末链接。


一、NCNN编译

具体步骤可参考:官方编译教程

1、编译protobuf

下载protobuf:https://github.com/google/protobuf/archive/v3.4.0.zip

打开开始菜单中的x64 Native Tools Command Prompt for VS 2017命令行工具(更高级的版本也可以,我用2022成功了),编译protobuf。

cd <protobuf-root-dir>
mkdir build
cd build
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF ../cmake
nmake
nmake install

2、编译NCNN

克隆NCNN仓库:

git clone https://github.com/Tencent/ncnn.git

编译NCNN(我这里没用Vulkan,需要的话参考官方教程),取代命令中的路径为自己的路径:

cd <ncnn-root-dir>
mkdir -p build
cd build
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -DProtobuf_INCLUDE_DIR=<protobuf-root-dir>/build/install/include -DProtobuf_LIBRARIES=<protobuf-root-dir>/build/install/lib/libprotobuf.lib -DProtobuf_PROTOC_EXECUTABLE=<protobuf-root-dir>/build/install/bin/protoc.exe -DNCNN_VULKAN=OFF.. -DOpenCV_DIR=C:/opencv/opencv/build
nmake
nmake install

二、NCNN部署

1、环境

windows cpu

opencv 4.5.5

visual studio 2019

2、onnx转ncnn模型

首先将上面得到的简化后的onnx模型转换为ncnn模型(得到param和bin后缀的2个文件),注意转换的时候要没有报错,不然后续加载会出错:

可以在这里下载转换好的模型:传送门

../ncnn/build/tools/onnx/onnx2ncnn simple_modnet.onnx simple_modnet.param simple_modnet.bin 

3、C++代码

代码结构:

MODNet.h代码:

#pragma once
#include <string>
#include "net.h"
#include <opencv.hpp>
#include "time.h"class MODNet
{private:std::string param_path;std::string bin_path;std::vector<int> input_shape;ncnn::Net net;const float norm_vals[3] = { 1 / 177.5, 1 / 177.5, 1 / 177.5 };const float mean_vals[3] = { 175.5, 175.5, 175.5 };cv::Mat normalize(cv::Mat& image);
public:MODNet() = delete;MODNet(const std::string param_path, const std::string bin_path, std::vector<int> input_shape);~MODNet();cv::Mat predict_image(cv::Mat& image);void predict_image(const std::string& src_image_path, const std::string& dst_path);void predict_camera();
};

MODNet.cpp代码:

#include "MODNet.h"MODNet::MODNet(const std::string param_path, const std::string bin_path, std::vector<int> input_shape):param_path(param_path), bin_path(bin_path), input_shape(input_shape) {net.load_param(param_path.c_str());net.load_model(bin_path.c_str());
}MODNet::~MODNet() {net.clear();
}cv::Mat MODNet::normalize(cv::Mat& image) {std::vector<cv::Mat> channels, normalized_image;cv::split(image, channels);cv::Mat r, g, b;b = channels.at(0);g = channels.at(1);r = channels.at(2);b = (b / 255. - 0.5) / 0.5;g = (g / 255. - 0.5) / 0.5;r = (r / 255. - 0.5) / 0.5;normalized_image.push_back(r);normalized_image.push_back(g);normalized_image.push_back(b);cv::Mat out = cv::Mat(image.rows, image.cols, CV_32F);cv::merge(normalized_image, out);return out;
}cv::Mat MODNet::predict_image(cv::Mat& image) {cv::Mat rgbImage;cv::cvtColor(image, rgbImage, cv::COLOR_BGR2RGB);ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbImage.data, ncnn::Mat::PIXEL_RGB, image.cols, image.rows, input_shape[3], input_shape[2]);in.substract_mean_normalize(mean_vals, norm_vals);ncnn::Extractor ex = net.create_extractor();ex.set_num_threads(4);ex.input("input", in);ncnn::Mat out;ex.extract("output", out);cv::Mat mask(out.h, out.w, CV_8UC1);const float* probMap = out.channel(0);for (int i{ 0 }; i < out.h; i++) {for (int j{ 0 }; j < out.w; ++j) {mask.at<uchar>(i, j) = probMap[i * out.w + j] > 0.5 ? 255 : 0;}}cv::resize(mask, mask, cv::Size(image.cols, image.rows), 0, 0);cv::Mat segFrame;cv::bitwise_and(image, image, segFrame, mask = mask);return segFrame;
}void MODNet::predict_image(const std::string& src_image_path, const std::string& dst_path) {cv::Mat image = cv::imread(src_image_path);cv::Mat segFrame = predict_image(image);cv::imwrite(dst_path, segFrame);
}void MODNet::predict_camera() {cv::Mat frame;cv::VideoCapture cap;int deviceID{ 0 };int apiID{ cv::CAP_ANY };cap.open(deviceID, apiID);if (!cap.isOpened()) {std::cout << "Error, cannot open camera!" << std::endl;return;}//--- GRAB AND WRITE LOOPstd::cout << "Start grabbing" << std::endl << "Press any key to terminate" << std::endl;int count{ 0 };clock_t start{ clock() }, end{ 0 };double fps{ 0 };for (;;){// wait for a new frame from camera and store it into 'frame'cap.read(frame);// check if we succeededif (frame.empty()) {std::cout << "ERROR! blank frame grabbed" << std::endl;break;}cv::Mat segFrame = predict_image(frame);// fps++count;end = clock();fps = count / (float(end - start) / CLOCKS_PER_SEC);if (count >= 50) {count = 0;  //防止计数溢出start = clock();}std::cout << "FPS: " << fps << "  Seg Image Number: " << count << "   time consume:" << (float(end - start) / CLOCKS_PER_SEC) << std::endl;//设置绘制文本的相关参数std::string text{ std::to_string(fps) };int font_face = cv::FONT_HERSHEY_COMPLEX;double font_scale = 1;int thickness = 2;int baseline;cv::Size text_size = cv::getTextSize(text, font_face, font_scale, thickness, &baseline);//将文本框居中绘制cv::Point origin;origin.x = 20;origin.y = 20;cv::putText(segFrame, text, origin, font_face, font_scale, cv::Scalar(0, 255, 255), thickness, 8, 0);// show live and wait for a key with timeout long enough to show imagesimshow("Live", segFrame);if (cv::waitKey(5) >= 0)break;}cap.release();cv::destroyWindow("Live");return;
}

main.cpp代码:

#include <opencv.hpp>
#include <iostream>
#include "MODNet.h"
#include <vector>
#include "net.h"
#include "time.h"int main() {std::string param_path{ "onnx_model\\simple_modnet.param" };std::string bin_path{ "onnx_model\\simple_modnet.bin" };std::vector<int> input_shape{ 1, 3, 512, 512 };MODNet model(param_path, bin_path, input_shape);// 预测并显示cv::Mat image = cv::imread("C:\\Users\\langdu\\Pictures\\test.png");cv::Mat segFrame = model.predict_image(image);cv::imshow("1", segFrame);cv::waitKey(0);// 摄像头//model.predict_camera();return -1;
}

三、NCNN量化

对于移动设备,对模型大小要求非常苛刻,需要有效地方法来降低其存储空间,量化是一种有效地方法降低模型大小,量化资料可参考:【深度学习】模型量化-笔记/实验

这里使用的是静态量化的方法,量化后模型大小对比:

bin(KB) param(KB)
量化前 25236 22
量化后 6442 24

由上表看出,模型经过量化后,其大小仅为原来的1/4左右(预测会有一定的精度损失)。下面开始量化教程,参考官方教程。

1、模型优化

使用ncnnoptimize(在build\tools目录下)优化模型。

./ncnnoptimize simple_modnet.param simple_modnet.bin quantize_modnet.param quantize_modnet 0

2、创建calibration表

ncnn创建calibration表时,mean和norm参数可以参考这里修改,另外注意pixel设置和MODNet官方repo一致,为BGR。images文件夹下存放用来校准的图片。

find images/ -type f > imagelist.txt
./ncnn2table quantize_modnet.param quantize_modnet.bin imagelist.txt modnet.table mean=[177.5, 177.5, 177.5] norm=[0.00784, 0.00784, 0.00784] shape=[512, 512, 3] pixel=BGR thread=8 method=kl

3、量化

使用下面的命令得到int8模型。

./ncnn2int8 quantize_modnet.param quantize_modnet-opt.bin modnet_int8.param modnet_int8.bin modnet.table

4、使用

得到了int8模型,使用非常简单,只需要把上面的代码中,bin和param路径替换为生成的int8模型路径即可。

5、量化后预测结果

首先给出未量化的预测结果:

量化后结果(精度有损失,鞋子预测全了,地板错误多了):

四、相关链接

1、NCNN部署全部代码+所有模型权重

【Matting】MODNet:实时人像抠图模型-NCNN C++量化部署相关推荐

  1. 【Matting】MODNet:实时人像抠图模型-笔记

    paper:MODNet: Real-Time Trimap-Free Portrait Matting via Objective Decomposition (AAAI 2022) github: ...

  2. 超强实时人像抠图算法开源,随心所欲背景替换!

    谈到人像抠图想必大家都不陌生.在影视剪辑.直播娱乐.线上教学.视频会议等场景中都有人像分割的身影,它可以帮助用户实时.精准地将人物和背景精准识别出来,实现更精细化的人物美颜.背景虚化替换.弹幕穿人等, ...

  3. RobustVideoMatting实时人像抠图实践

    一.准备工作 Code地址:GitHub - PeterL1n/RobustVideoMatting: Robust Video Matting in PyTorch, TensorFlow, Ten ...

  4. untiy 实时人像抠图

    最近公司要求做一个抠图程序,作者想到接一个百度AI来实现抠图,做出来之后效果不是太好,然后领导说想要实时抠图,让用户现场体验更好些,没办法,只能推倒重来,然后在网上找个shader,然后自己改改,就实 ...

  5. 视频人像抠图论文阅读

    视频人像抠图论文阅读 1.Prime Sample Attention in Object Detection 2.Mask RCNN 3.Background Matting: The World ...

  6. 目前最大的人像抠图数据集P3M-10k开源了!助力隐私保护的人像抠图研究

    点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 点击进入-> CV 微信技术交流群 转载自:京东探索研究院 人像抠图,是指从人物图像中提取人物前景,是 ...

  7. Libtorch C++实现人像抠图——面向Windows(部署教程)

    目录 一.环境安装 1.1 基本环境介绍 1.2 pth模型序列化导出转pt 1.2 下载libtorch 1.3 安装OpenCV 1.4 创建win32 C++控制台工程 二.完整推理代码 三.测 ...

  8. Python实现自动人像抠图(小白也能学会)

    原理:AI人工智能,机器学习 工具:paddlehub包和人像抠图模型deeplabv3p_xception65_humanseg 步骤一:安装软件 1.nodepad++ (自行百度安装) 2.py ...

  9. 一键抠图Portrait Matting人像抠图 (C++和Android源码)

    一键抠图Portrait Matting人像抠图 (C++和Android源码) 目录 一键抠图Portrait Matting人像抠图 (C++和Android源码) 1. 项目介绍: 2. MOD ...

最新文章

  1. SQL Server 2012 安全新特性:包含数据库
  2. SRP:The Single-Responsibility Principle
  3. TensorFlow与主流深度学习框架对比
  4. 函数计算机按键没反应,关于waitKey()函数按键无反应情况
  5. TCP/IP(一):数据链路层
  6. .NET使用免费开源类库操作Excel
  7. 那些年,乘风破浪的科学家们
  8. vs简易计算机等于号代码,等于(=)vs.
  9. SXSSFWorkbook使用——使用excel模板
  10. java读取本地图片的绝对地址_我想使用图片的绝对路径。为什么java不能使用图片的绝对路径。...
  11. freopen()函数文件流重定向和文件流的清除
  12. UI设计师常用500多款字体和73款手写字体打包
  13. 白帽子讲Web安全(第一章总结)
  14. BSOD分析之空指针引用
  15. Legion使用:半自动化网络渗透工具
  16. 删库跑路大神的一生,真狠人!
  17. 关于提问的一些书籍及文章
  18. excel表格打印每页都有表头_excel打印如何每页都有表头 最常用的办公小技巧
  19. 介绍2款最流行的画PCB工具
  20. MySQL中单句实现无限层次父子关系查询

热门文章

  1. 20个令人惊叹的深度学习应用
  2. 幼儿园计算机应用研修日志,教师信息技术应用能力提升研修日志
  3. TriggerEvent的动态用法
  4. 清明节 | 数字经济中台战略报告盘点
  5. ATL炒冷饭学习之三:CoInitialize/CoUninitialize
  6. 程序员工作三年:跳槽三家公司,从阿里出来,工资从15K涨到45K?
  7. 【LOJ6178】 「美团 CodeM 初赛 Round B」景区路线规划 期望概率DP
  8. 20190920腾讯
  9. ORACLE上下级列表数据转为树状查询结构
  10. Fundebug后端Node.js插件更新至0.2.0,支持监控Express慢请求