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

在线人像抠图体验:CV案例

相关链接:

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

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

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

上面的2篇博客,分别分析了MODNet的原理以及python部署方法,本文将使用C++部署MODNet模型,实现图片Matting和摄像头Matting功能。先上效果图:

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

目录

一、环境

二、模型

三、代码

四、效果

附录

一、环境

windows 10×64 cpu

onnxruntime-win-x64-1.10.0

opencv 4.5.5

visual studio 2019

二、模型

下载官方提供的onnx模型,官方的repo地址:https://github.com/ZHKKKe/MODNet.git,在onnx文件夹下有下载链接,这里就不给出来了。

使用netron查看onnx模型:

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

网络结构:

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

三、代码

实现了2个功能:图片Matting、摄像头Matting(速度与电脑性能有关,cpu会很慢)

代码目录:

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

MODNet.h内容:

#pragma once
#include
#include
#include
#include
#include
#include

class MODNet
{
protected:
    Ort::Env env_;
    Ort::SessionOptions session_options_;
    Ort::Session session_{ nullptr };
    Ort::RunOptions run_options_{ nullptr };

    std::vector input_tensors_;

    std::vector input_node_names_;
    std::vector input_node_dims_;
    size_t input_tensor_size_{ 1 };

    std::vector out_node_names_;
    size_t out_tensor_size_{ 1 };

    int image_h;
    int image_w;

    cv::Mat normalize(cv::Mat& image);
    cv::Mat preprocess(cv::Mat image);

public:
    MODNet() = delete;
    MODNet(std::wstring model_path, int num_threads, std::vector input_node_dims);
    cv::Mat predict_image(cv::Mat& src);
    void predict_image(const std::string& src_path, const std::string& dst_path);
    void predict_camera();

};

MODNet.cpp内容:

#include "MODNet.h"

MODNet::MODNet(std::wstring model_path, int num_threads = 1, std::vector input_node_dims = { 1, 3, 192, 192 }) {
    input_node_dims_ = input_node_dims;
    for (int64_t i : input_node_dims_) {
        input_tensor_size_ *= i;
        out_tensor_size_ *= i;
    }

    //std::cout << input_tensor_size_ << std::endl;
    session_options_.SetIntraOpNumThreads(num_threads);
    session_options_.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);

    try {
        session_ = Ort::Session(env_, model_path.c_str(), session_options_);
    }
    catch (...) {

    }

    Ort::AllocatorWithDefaultOptions allocator;
    //获取输入name
    const char* input_name = session_.GetInputName(0, allocator);
    input_node_names_ = { input_name };
    //std::cout << "input name:" << input_name << std::endl;
    const char* output_name = session_.GetOutputName(0, allocator);
    out_node_names_ = { output_name };
    //std::cout << "output name:" << output_name << std::endl;
}

cv::Mat MODNet::normalize(cv::Mat& image) {
    std::vector 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;
}

/*
* preprocess: resize -> normalize
*/
cv::Mat MODNet::preprocess(cv::Mat image) {
    image_h = image.rows;
    image_w = image.cols;
    cv::Mat dst, dst_float, normalized_image;
    cv::resize(image, dst, cv::Size(int(input_node_dims_[3]), int(input_node_dims_[2])), 0, 0);
    dst.convertTo(dst_float, CV_32F);
    normalized_image = normalize(dst_float);

    return normalized_image;
}

/*
* postprocess: preprocessed image -> infer -> postprocess
*/
cv::Mat MODNet::predict_image(cv::Mat& src) {
    cv::Mat preprocessed_image = preprocess(src);
    cv::Mat blob = cv::dnn::blobFromImage(preprocessed_image, 1, cv::Size(int(input_node_dims_[3]), int(input_node_dims_[2])), cv::Scalar(0, 0, 0), false, true);
    //std::cout << "load image success." << std::endl;
    // create input tensor
    auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);

    input_tensors_.emplace_back(Ort::Value::CreateTensor(memory_info, blob.ptr(), blob.total(), input_node_dims_.data(), input_node_dims_.size()));

    std::vector output_tensors_ = session_.Run(
        Ort::RunOptions{ nullptr },
        input_node_names_.data(),
        input_tensors_.data(),
        input_node_names_.size(),
        out_node_names_.data(),
        out_node_names_.size()
    );
    float* floatarr = output_tensors_[0].GetTensorMutableData();

    // decoder
    cv::Mat mask = cv::Mat::zeros(static_cast(input_node_dims_[2]), static_cast(input_node_dims_[3]), CV_8UC1);

    for (int i{ 0 }; i < static_cast(input_node_dims_[2]); i++) {
        for (int j{ 0 }; j < static_cast(input_node_dims_[3]); ++j) {
            mask.at(i, j) = static_cast(floatarr[i * static_cast(input_node_dims_[3]) + j] > 0.5);
        }
    }
    cv::resize(mask, mask, cv::Size(image_w, image_h), 0, 0);
    input_tensors_.clear();
    return mask;
}

void MODNet::predict_image(const std::string& src_path, const std::string& dst_path) {
    cv::Mat image = cv::imread(src_path);
    cv::Mat mask = predict_image(image);
    cv::Mat predict_image;
    cv::bitwise_and(image, image, predict_image, mask = mask);
    cv::imwrite(dst_path, predict_image);
    //std::cout << "predict image over" << std::endl;

}

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 LOOP
    std::cout << "Start grabbing" << std::endl << "Press any key to terminate" << std::endl;
    int count{ 0 };
    clock_t start{ clock() }, end;
    double fps{ 0 };
    for (;;)
    {
        // wait for a new frame from camera and store it into 'frame'
        cap.read(frame);
        // check if we succeeded
        if (frame.empty()) {
            std::cout << "ERROR! blank frame grabbed" << std::endl;
            break;
        }
        cv::Mat mask = predict_image(frame);
        cv::Mat segFrame;
        cv::bitwise_and(frame, frame, segFrame, mask = mask);
        // fps
        end = clock();
        ++count;
        fps = count / (float(end - start) / CLOCKS_PER_SEC);
        if (count >= 100) {
            count = 0;
            start = clock();
        }
        std::cout << fps << "  " << count << "   " << end - start << 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 images
        cv::imshow("Live", segFrame);
        if (cv::waitKey(5) >= 0)
            break;

    }
    cap.release();
    cv::destroyWindow("Live");

    return;
}

main.cpp内容:

#include
#include
#include
#include "MODNet.h"
#include

int main()
{
    std::wstring model_path(L"modnet.onnx");
    std::cout << "infer...." << std::endl;
    MODNet modnet(model_path, 1, { 1, 3, 512, 512 });
    modnet.predict_image("C:\\Users\\xxx\\Pictures\\test1.jpeg", "C:\\Users\\xxx\\Pictures\\matting.png");
    modnet.predict_camera(); //使用摄像头
    return 0;
}

四、效果

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

附录

本文代码及权重链接:modnet onnx C++部署,实现了图像matting,摄像头matting功能

Original: https://blog.csdn.net/qq_40035462/article/details/123788993
Author: 嘟嘟太菜了
Title: 【Matting】MODNet:实时人像抠图模型-onnx C++部署

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/533166/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Sklearn中数据预处理

    数据预处理 Sklearn中的模块preprocessing:几乎包含数据预处理的所有内容 数据无量纲化 在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分…

    人工智能 2023年6月16日
    086
  • 基于KMeans算法的图像分割例子

    文章目录 一、理论基础 * 1、KMeans算法 2、图像分割 二、实验过程 * 1、图片 2、实验步骤 3、Python代码 – (1)导包 (2)读取图像数据 (3…

    人工智能 2023年5月31日
    0101
  • J2EE开发技术概述

    文章目录 主流Web开发技术 一、JAVA & J2EE Java EE Java EE应用分层结构 Java EE应用的分层模型(1) JavaEE的组件和容器 优秀的轻…

    人工智能 2023年5月30日
    085
  • PyTorch:多分类问题实战

    一、batch_size 在合理范围内,增大batch_size的好处 1)内存利用率提高了,大矩阵乘法的并行化效率提高。 2)跑完一次 epoch(全数据集)所需的迭代次数减少,…

    人工智能 2023年7月3日
    091
  • ERNIE3.0一句话,我直接好家伙

    卷友们好,我是rumor。 没想到啊没想到。 最近中文大模型在CLUE的内卷之战轰轰烈烈,就是不见百度的身影,我就猜它肯定在憋什么大招,结果没想到大招来的这么快,也没想到这个大招还…

    人工智能 2023年6月1日
    074
  • OpenCV-Python自适应直方图均衡类CLAHE及方法详解

    一、引言 对比度受限的自适应直方图均衡在OpenCV中是通过类CLAHE来提供实现的,老猿没研究过C++中的应用,但OpenCV-Python中应用时与普通的Python类构建对象…

    人工智能 2023年5月28日
    083
  • 3GPP R17 NR测量GAP增强

    3GPP R17 NR测量GAP增强包含三个部分,(1) Pre-configured MG pattern(s), (2) Multiple concurrent and ind…

    人工智能 2023年6月30日
    081
  • CNN中的底层、高层特征、上下文信息、多尺度

    一、CNN中的底层、高层特征: 简短总结: 分类要求特征有较多的高级信息,回归(定位)要求特征包含更多的细节信息 1)图像的低层特征(对定位任务帮助大,我们可以想想比如轮廓信息都不…

    人工智能 2023年7月30日
    075
  • 简析三种近场通信及其未来发展趋势

    蓝牙篇 蓝牙是一种短距无线通信的技术规范,它最初的目标是取代现有的掌上电脑和移动电话等各种数字设备上的有线电缆连接。从目前的应用来看,由于蓝牙体积小和功率低等特点,其应用已不局限于…

    人工智能 2023年5月25日
    091
  • playwright教程 (一)适合小白

    一、playwright简介 playwright是微软发布的一款自动化测试工具,可以自动生成代码 在学习playwright前可以了解playwright文档,目前只有英文版! …

    人工智能 2023年7月6日
    087
  • 数据库原理-完整性

    什么是数据库的完整性 完整性控制机制 1.完整性约束条件 2.完整性控制 3.SQL Server的完整性 总结: 数据库的完整性是指数据的正确性和相容性,防止不合语义的数据进入数…

    人工智能 2023年6月1日
    094
  • 第十七届全国大学生智能车竞赛智能视觉组总结

    文章目录 前言 一、本次比赛任务分工 二、OpenArt部分任务 * 1.地图识别 2.图像识别 – 1)模型训练 2)图像处理 3)通讯 总结 前言 我参加了第十七届…

    人工智能 2023年6月24日
    097
  • 【代码详解】nerf-pytorch代码逐行分析

    目录 前言 run_nerf.py * config_parser() train() create_nerf() render() batchify_rays() render_…

    人工智能 2023年7月3日
    0365
  • python 链表总结

    链表 链表基础知识 移除链表元素 设计链表 翻转链表 删除链表的倒数第N个节点 链表相交 环形链表 链表基础知识 python定义: class ListNode: def __i…

    人工智能 2023年7月9日
    090
  • python的numpy函数求平方和_如何使用Python和Numpy计算r平方?

    numpy.polyfit文档,它是适合的线性回归。具体来说,具有度’d’的numpy.polyfit拟合具有平均函数的线性回归 E(y | x)= p_d…

    人工智能 2023年6月18日
    071
  • 2022年人工智能5大发展趋势

    近几年随着各行业对于自动化需求的提高,为人工智能带了了一次巨大的提升机会。随着深度学习的开放,人工智能在几年中快速发展,由尖端技术慢慢向着开始普及在各行业和家庭生活中。以下是国外一…

    人工智能 2023年5月28日
    0259
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球