使用opencv-dnn+C++部署onnx肺区分割模型

这篇具有很好参考价值的文章主要介绍了使用opencv-dnn+C++部署onnx肺区分割模型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.环境:

windows + vscdoe + opencv3.4.15

2.流程:

①通过python将训练得到的模型转化为onnx。

②通过C++调用onnx模型实现推理。

3.代码:

① python代码

ResUnet.py

import torch
from torch import nn
import torch.nn.functional as F


class DoubleConv(nn.Module):
    """(convolution => [BN] => ReLU) * 2"""

    def __init__(self, inChannels, outChannels, midChannels=None):
        super().__init__()
        if not midChannels:
            midChannels = outChannels
        self.doubleConv = nn.Sequential(
            nn.Conv2d(inChannels, midChannels, kernel_size=3, padding=1),
            nn.BatchNorm2d(midChannels),
            nn.ReLU(inplace=True),
            nn.Conv2d(midChannels, outChannels, kernel_size=3, padding=1),
            nn.BatchNorm2d(outChannels),
            nn.ReLU(inplace=True)
        )

    def forward(self, inNet):
        return self.doubleConv(inNet)


class ResBlock(nn.Module):
    def __init__(self, inChannels, outChannels):
        super(ResBlock, self).__init__()
        self.down1Sample = nn.Sequential(
            nn.Conv2d(inChannels, outChannels, kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(outChannels))
        self.doubleConv = DoubleConv(inChannels, outChannels)
        self.down2Sample = nn.MaxPool2d(2)
        self.relu = nn.ReLU()

    def forward(self, inNet):
        identity = self.down1Sample(inNet)
        outNet = self.doubleConv(inNet)
        outNet = self.relu(outNet + identity)
        return self.down2Sample(outNet), outNet


class UpBlock(nn.Module):
    def __init__(self, inChannels, outChannels):
        super(UpBlock, self).__init__()
        self.upSample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
        self.doubleConv = DoubleConv(inChannels, outChannels)

    def forward(self, downInput, skipInput):
        inNet = self.upSample(downInput)
        # input is CHW
        dify = skipInput.size()[2] - inNet.size()[2]
        difx = skipInput.size()[3] - inNet.size()[3]

        inNet = F.pad(inNet, [difx // 2, difx - difx // 2,
                              dify // 2, dify - dify // 2])
        inNet = torch.cat([inNet, skipInput], dim=1)
        return self.doubleConv(inNet)


class OutConv(nn.Module):
    def __init__(self, inChannels, outChannels):
        super(OutConv, self).__init__()
        self.conv = nn.Conv2d(inChannels, outChannels, kernel_size=1)

    def forward(self, inNet):
        return self.conv(inNet)


class ResUnet(nn.Module):
    """
    Hybrid solution of resnet blocks and double conv blocks
    """
    def __init__(self, inChannels=3, nClasses=1):
        super(ResUnet, self).__init__()

        self.downConv = nn.ModuleList()
        neuronNum = [64, 128, 256, 512, 1024]
        preChannels = inChannels
        for num in neuronNum[0:-1]:
            self.downConv.append(ResBlock(preChannels, num))
            preChannels = num
        self.doubleConv = DoubleConv(preChannels, neuronNum[-1])

        self.upConv = nn.ModuleList()
        for num1, num2 in zip(neuronNum[1::][::-1],  neuronNum[0:-1][::-1]):
            self.upConv.append(UpBlock(num1 + num2, num2))

        self.convFinal = OutConv(num2, nClasses)

    def forward(self, inNet):
        skipOuts = []
        for cnt, down in enumerate(self.downConv):
            inNet, skipOut = down(inNet)
            skipOuts.append(skipOut)
        inNet = self.doubleConv(inNet)

        for cnt, up in enumerate(self.upConv):
            inNet = up(inNet, skipOuts[-1 - cnt])

        outNet = self.convFinal(inNet)
        return outNet

export.py

def export(ckpt):
    model = ResUnet().to(DEVICE)
    stateDict = torch.load(ckpt)['state_dict']
    new_state_dict = OrderedDict()
    for key, val in stateDict.items():
        name = key[7:]  # remove "module."   
        new_state_dict[name] = val
       
    model.load_state_dict(new_state_dict)
    model.eval()

    inNet = torch.rand(1, 3, calSize[0], calSize[1]).to(DEVICE)
    torch.onnx.export(model, inNet, modelOnnx, opset_version=11, verbose=True, export_params=True, do_constant_folding=True)

② C++代码:

#include <iostream>
#include <fstream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;
using namespace cv::dnn;
 

cv::Scalar meanDefault {0.485, 0.456, 0.406};
cv::Scalar stdDefault {0.229, 0.224, 0.225};
std::vector<std::string> extensions {"jpg", "bmp", "png", "jpeg"};
const int topk = 2;
static const string kWinName = "CT lung seg in OpenCV";

typedef struct
{
    int index;
    double value;
}sortArray;

cv::Mat Preprocess(cv::Mat pendImg)
{

    cv::Mat postImg;
    cv::resize(pendImg, postImg, cv::Size(512, 512));
    postImg.convertTo(postImg, CV_32F, 1.0/255.0);
    cv::subtract(postImg, meanDefault, postImg);
    cv::divide(postImg, stdDefault, postImg);
    return postImg;
}


bool cmp(sortArray a, sortArray b)
{
    return a.value>b.value;
}

std::vector<std::vector<cv::Point>> Postprocess(cv::Mat pendMask)
{

    
    cv::Mat bwImg;
    std::vector<std::vector<cv::Point>> contours; 
    std::vector<double> areas;

    cv::threshold(pendMask, bwImg, 1, 255.0, CV_THRESH_BINARY | CV_THRESH_OTSU);  
    cv::findContours(bwImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);  
    
    std::vector <sortArray> sortedArray(contours.size());
    for(int i=0;i<contours.size();++i){
        sortedArray[i].index = i;
        sortedArray[i].value = cv::contourArea(contours[i]);
    }
    std::sort(sortedArray.begin(), sortedArray.end(), cmp);
  
    std::vector<std::vector<cv::Point>> nContours;

    for (int i=0;i<sortedArray.size();i++)
    {

        if (i<topk) nContours.push_back(contours[sortedArray[i].index]);
        else break;

    }

    return nContours;
}

void GetImgFilenames(std::string path, std::vector<std::string>& imgFilenames)
{
    // imgFilenames.clear();
    if (path.find(".") != std::string::npos)
    {
        imgFilenames.push_back(path);
    }
    else
    {
        std::string fpath = path.append("*.*");
        std::vector<cv::String> allfiles;  //cv::String
        cv::glob(fpath, allfiles);
        for (int i = 0; i < allfiles.size(); i++)
        {
            size_t iPos = allfiles[i].rfind('.');
            std::string fileEx = allfiles[i].substr(iPos + 1, allfiles[i].length());
            // cout << fileEx << endl;
            if (std::find(extensions.begin(), extensions.end(), fileEx) != extensions.end())
            {
                imgFilenames.push_back(allfiles[i]);
            }
        }
    }
    // return;
}

cv::Mat Seg(std::string modelPath, std::string imgPath){

    // Net net = cv::dnn::readNetFromONNX(modelPath);
    cv::dnn::Net net = cv::dnn::readNet(modelPath);
    net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
    net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);

    cv::Mat Oimg = imread(imgPath);    
    cv::Mat img = Preprocess(Oimg.clone());
 
    cv::Mat blob = cv::dnn::blobFromImage(img, 1.0, Size(512, 512), cv::Scalar(0, 0, 0), true, false);    
    net.setInput(blob);    
 
    cv::Mat predOut = net.forward();  
    std::vector<cv::Mat> predTmp;
    cv::dnn::imagesFromBlob(predOut, predTmp); 

    cv::Mat predMask;
    predTmp[0] = (predTmp[0]>0);    
    predTmp[0].convertTo(predMask, CV_8UC1);
    return predMask;

}


int main()
{

    std::string modelBin = "weights/ctSeg.onnx";

    std::string path = "imgs/";
    std::vector<std::string> imgfiles;
  
    GetImgFilenames(path, imgfiles);

    for (int i=0; i<imgfiles.size(); i++)
    {
        // std::cout << imgfiles[i] << std::endl;
        cv::Mat predMask = Seg(modelBin, imgfiles[i]);
        cv::Mat Oimg = imread(imgfiles[i]);    
        cv::Mat imgShow = Oimg.clone();
        cv::resize(imgShow, imgShow, cv::Size(512, 512));

        std::vector<std::vector<cv::Point>> nContours = Postprocess(predMask);
        for (int i = 0; i < nContours.size(); i++)
        {
            cv::drawContours(imgShow, nContours, i, Scalar(0, 255, 0), 2, 8); 
        }
        cv::imshow("iShow", imgShow);
        cv::waitKey(0);
    }
    return 0;

}
4.结果:
c++调用onnx,图像处理,opencv,深度学习,计算机视觉,c++,Powered by 金山文档
5.文件下载路径:

链接:https://pan.baidu.com/s/1DDweuwcpSubLotU79c-jFw

提取码:ZDWD

注:刚接触深度学习完成的模型,所以采用了当时比较常见的网络,网络模型偏大。文章来源地址https://www.toymoban.com/news/detail-647895.html

到了这里,关于使用opencv-dnn+C++部署onnx肺区分割模型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV DNN模块推理YOLOv5 ONNX模型方法

    本文档主要描述 python 平台,使用 opencv-python 深度神经网络模块 dnn ,推理 YOLOv5 模型的方法。 文档主要包含以下内容: opencv-python 模块的安装 YOLOv5 模型格式的说明 ONNX 格式模型的加载 图片数据的预处理 模型推理 推理结果后处理,包括 NMS , cxcywh 坐标转换为 xyxy 坐标等 关键方

    2024年02月16日
    浏览(54)
  • YOLOv5 实例分割 用 OPenCV DNN C++ 部署

    如果之前从没接触过实例分割,建议先了解一下实例分割的输出是什么。 实例分割两个关键输出是:mask系数、mask原型 本文参考自该项目(这么优秀的代码当然要给star!):GitHub - UNeedCryDear/yolov5-seg-opencv-onnxruntime-cpp: yolov5 segmentation with onnxruntime and opencv 目录 Pre: 一、代码总结

    2024年02月12日
    浏览(35)
  • [C++]使用纯opencv去部署yolov9的onnx模型

    【介绍】 部署 YOLOv9 ONNX 模型在 OpenCV 的 C++ 环境中涉及一系列步骤。以下是一个简化的部署方案概述,以及相关的文案。 部署方案概述: 模型准备 :首先,你需要确保你有 YOLOv9 的 ONNX 模型文件。这个文件包含了模型的结构和权重。 环境配置 :安装 OpenCV 库,并确保它支持

    2024年03月13日
    浏览(70)
  • yolov8 opencv dnn部署自己的模型

    源码地址 本人使用的opencv c++ github代码,代码作者非本人 使用github源码结合自己导出的onnx模型推理自己的视频 推理条件 windows 10 Visual Studio 2019 Nvidia GeForce GTX 1070 opencv4.7.0 (opencv4.5.5在别的地方看到不支持yolov8的推理,所以只使用opencv4.7.0) 导出yolov8模型 yolov8版本: version = ‘8.

    2024年01月24日
    浏览(46)
  • yolov5 opencv dnn部署自己的模型

    github开源代码地址 yolov5官网还提供的dnn、tensorrt推理链接 本人使用的opencv c++ github代码,代码作者非本人,也是上面作者推荐的链接之一 如果想要尝试直接运行源码中的yolo.cpp文件和yolov5s.pt推理sample.mp4,请参考这个链接的介绍 使用github源码结合自己导出的onnx模型推理自己的

    2024年01月23日
    浏览(47)
  • 【模型部署 01】C++实现分类模型(以GoogLeNet为例)在OpenCV DNN、ONNXRuntime、TensorRT、OpenVINO上的推理部署

    深度学习领域常用的基于CPU/GPU的推理方式有OpenCV DNN、ONNXRuntime、TensorRT以及OpenVINO。这几种方式的推理过程可以统一用下图来概述。整体可分为模型初始化部分和推理部分,后者包括步骤2-5。 以GoogLeNet模型为例,测得几种推理方式在推理部分的耗时如下: 结论: GPU加速首选

    2024年02月06日
    浏览(57)
  • 【模型部署 01】C++实现GoogLeNet在OpenCV DNN、ONNXRuntime、TensorRT、OpenVINO上的推理部署

    深度学习领域常用的基于CPU/GPU的推理方式有OpenCV DNN、ONNXRuntime、TensorRT以及OpenVINO。这几种方式的推理过程可以统一用下图来概述。整体可分为模型初始化部分和推理部分,后者包括步骤2-5。 以GoogLeNet模型为例,测得几种推理方式在推理部分的耗时如下: 结论: GPU加速首选

    2024年02月06日
    浏览(57)
  • Opencv C++实现yolov5部署onnx模型完成目标检测

    头文件 命名空间 结构体 Net_config 里面存了三个阈值和模型地址,其中 置信度 ,顾名思义,看检测出来的物体的精准度。以测量值为中心,在一定范围内,真值出现在该范围内的几率。 endsWith()函数 判断sub是不是s的子串 anchors_640图像接收数组 根据图像大小,选择相应长度的

    2024年02月13日
    浏览(41)
  • YOLOV5(二):将pt转为onnx模型并用opencv部署

    yolov5s 6.0自带export.py程序可将.pt转为.onnx等,只需配置需要的环境即可。 1. 安装环境 报错:NVIDIA-tensorrt安装失败! 解决:从源码安装TensorRt: ①安装CUDNN和CudaToolKit等GPU配置 ②从官网下载需要的rt版本:https://developer.nvidia.com/nvidia-tensorrt-8x-download ③解压后,将lib文件夹添加到

    2024年02月10日
    浏览(44)
  • OpenCV DNN C++ 使用 YOLO 模型推理

    YOLO(You Only Look Once)是一种流行的目标检测算法,因其速度快和准确度高而被广泛应用。OpenCV 的 DNN(Deep Neural Networks)模块为我们提供了一个简单易用的 API,用于加载和运行预先训练的深度学习模型。本文将详细介绍如何使用 OpenCV 的 DNN 模块来进行 YOLOv5 的目标检测。 确保

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包