2021.03.11更新 c++下使用opencv部署yolov5模型(一)

-----2022.10.10 更新yolov5-seg的实例分割模型部署:

2022.09.29更新 c++下面使用opencv部署yolov5和yolov7实例分割模型(六)_爱晚乏客游的博客-CSDN博客

-----2022.07.25 更新了下yolov7的部署,有需要的自取

2022.07.25 C++下使用opencv部署yolov7模型(五)_爱晚乏客游的博客-CSDN博客

-----2021.11.01更新说明

由于yolov5在6.0版本增加了对opencv的支持,所以模型部署1-3适用于4.0和5.0版本的修改,6.0版本的可以看这里:

2021.09.02更新说明 c++下使用opencv部署yolov5模型 (三)_爱晚乏客游的博客-CSDN博客

2021.11.01 c++下 opencv部署yolov5-6.0版本 (四)_爱晚乏客游的博客-CSDN博客

建议直接走6.0的版本,省事

opencv 读取YOLOV5导出模型失败的原因及其修改方法

首先感谢下这位大佬的文章:用opencv的dnn模块做yolov5目标检测_nihate的专栏-CSDN博客_opencv yolov5,详细的解释了为什么yolov5导出的onnx模型不能被opencv读取的原因以及后面的修改方法。

如果直接事用opencv的dnn模块读取yolov5自带转出的onnx模型,则会有一大堆的报错:

[ERROR:0] global C:\build\master_winpack-build-win64-vc14\opencv\modules\dnn\src\onnx\onnx_importer.cpp (1788) cv::dnn::dnn4_v20200908::ONNXImporter::handleNode DNN/ONNX: ERROR during processing node with 5 inputs and 1 outputs: [Slice]:(131)
Exception: OpenCV(4.5.0) C:\build\master_winpack-build-win64-vc14\opencv\modules\dnn\src\onnx\onnx_importer.cpp:1797: error: (-2:Unspecified error) in function 'cv::dnn::dnn4_v20200908::ONNXImporter::handleNode'
> Node [Slice]:(131) parse error: OpenCV(4.5.0) C:\build\master_winpack-build-win64-vc14\opencv\modules\dnn\src\onnx\onnx_importer.cpp:697: error: (-2:Unspecified error) in function 'void __cdecl cv::dnn::dnn4_v20200908::ONNXImporter::handleNode(const class opencv_onnx::NodeProto &)'
> > Slice layer only supports steps = 1 (expected: 'countNonZero(step_blob != 1) == 0'), where
> >     'countNonZero(step_blob != 1)' is 1
> > must be equal to
> >     '0' is 0
>
Can't load network by using the following files:
请按任意键继续. . .

首先找到yolov5的focus模块,

#models/comment.py
class Focus(nn.Module):
    # Focus wh information into c-space
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
        super(Focus, self).__init__()
        self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
        #self.contract = Contract(gain=2)

    def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)
        return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], dim=1))
        #return self.conv(self.contract(x))

看到在foward里面做了切片的操作。同时看到了被注释掉的两行代码。


#self.contract = Contract(gain=2)
#return self.conv(self.contract(x))

那么我们把这两行代码替换点原本的return会发生什么?

class Focus(nn.Module):
    # Focus wh information into c-space
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
        super(Focus, self).__init__()
        self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
        self.contract = Contract(gain=2)

    def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)
        #return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], dim=1))
        return self.conv(self.contract(x))

然后运行export.py:喜提报错一个,提示为没有这个属性

继续扒拉下Contract(x),找到Contract模块(就在focus下面)

#models/comment.py
class Contract(nn.Module):
    # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40)
    def __init__(self, gain=2):
        super().__init__()
        self.gain = gain

    def forward(self, x):
        N, C, H, W = x.size()  # assert (H / s == 0) and (W / s == 0), 'Indivisible gain'
        s = self.gain
        x = x.view(N, C, H // s, s, W // s, s)  # x(1,64,40,2,40,2)
        x = x.permute(0, 3, 5, 1, 2, 4).contiguous()  # x(1,2,2,64,40,40)
        return x.view(N, C * s * s, H // s, W // s)  # x(1,256,40,40)

可以看到在forward中进行的维度变换,发现起功能类似上面的切片操作。有兴趣的同学可以和上面的切片操作的输出对比下,看下维度是不是一样的。

所以修改了下focus模块:

class Focus(nn.Module):
    # Focus wh information into c-space
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
        super(Focus, self).__init__()
        #self.contract=Conv(c1 * 4, c2, k, s, p, g, act)
        self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
    def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)
        #return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
        N, C, H, W = x.size()  # assert (H / s == 0) and (W / s == 0), 'Indivisible gain'
        s = 2
        x = x.view(N, C, H // s, s, W // s, s)  # x(1,64,40,2,40,2)
        x = x.permute(0, 3, 5, 1, 2, 4).contiguous()  # x(1,2,2,64,40,40)
        y=x.view(N, C * s * s, H // s, W // s)  # x(1,256,40,40)
        return self.conv(y)

################################################################
##############       另外一种比较简单的方法         ##############
################################################################
class Focus(nn.Module):
    # Focus wh information into c-space
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
        super().__init__()
        self.conv = Conv(c1 * 4, c2, k, s, p, g, act)

    def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)
        contract = Contract(gain=2)
        #return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
        return self.conv(contract(x))

接着运行下export.py

可以看到已经读取成功了,使用netron(Netron)看下导出的模型。对比下两个模型,发现opencv不支持的slice层已经修改成可以支持的网络层了,且输入输出一样!

  • 17
    点赞
  • 161
    收藏
    觉得还不错? 一键收藏
  • 47
    评论
为了在Qt项目中部署yolov5使用OpenCV,你需要按照以下步骤进行操作: 1. 首先,确保你已经在Qt项目中成功集成了OpenCV。你可以使用CMake来设置OpenCV的依赖。在CMakeLists.txt文件中,使用`find_package(OpenCV REQUIRED)`来查找并设置OpenCV的依赖,然后使用`target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS})`将OpenCV库链接到你的项目中。\[1\] 2. 接下来,你需要将yolov5模型转换为ONNX格式。这一步通常包含在yolov5开源项目中的说明中。按照相应的介绍进行操作,将模型转换为.onnx格式。\[3\] 3. 一旦你有了ONNX格式的yolov5模型和成功集成了OpenCV,你可以在Qt项目中使用OpenCV和ONNX Runtime进行推理。使用ONNX Runtime进行推理的具体步骤可以参考相关文档和教程。你可以使用OpenCV加载模型使用ONNX Runtime进行推理,从而实现yolov5部署。\[2\] 请注意,这只是一个大致的指导,具体的实现步骤可能会因项目的不同而有所差异。你可能需要根据你的具体情况进行适当的调整和修改。 #### 引用[.reference_title] - *1* *2* *3* [C++模型部署:qt+yolov5/6+onnxruntime+opencv](https://blog.csdn.net/weixin_41006390/article/details/125645415)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 47
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值