解决Opencv dnn模块无法使用onnx模型的问题(将onnx的动态输入改成静态)

news2024/11/17 1:36:35

一、问题来源

最近做人脸识别项目,想只用OpenCV自带的人脸检测和识别模块实现,使用OpenCV传统方法:Haar级联分类器人脸检测+LBPH算法人脸识别的教程已经有了,于是想着用OpenCV中的dnn模块来实现,dnn实现人脸检测也有(详细教程可见我的这篇博客https://blog.csdn.net/weixin_42149550/article/details/131474284),问题就是基于cnn的人脸识别咋用opencv的dnn模块实现?一番搜索,发现OpenCV的dnn模块在加载YuNet模型时会报错
从官网下载的模型文件:
在这里插入图片描述

# 加载人脸检测模型
faceDetector = cv2.FaceDetectorYN.create('./opencvmodels/yunet.onnx', '', (320, 320))
# 加载人脸识别模型
faceRecognizer = cv2.FaceRecognizerSF_create(model='./opencvmodels/face_recognizer_fast.onnx', config='')

yunet模型加载会报错,face_recognizer_fast加载没有问题
报错提示:
在这里插入图片描述
重点看最后一句话:
error: (-215:Assertion failed) !isDynamicShape in function ‘cv::dnn::dnn4_v20221220::ONNXImporter::parseShape’

这句报错是说加载的onnx模型是动态的,但是OpenCV的cv2.FaceDetectorYN.create()不支持加载动态的模型,这里的动态指的是模型没有指定固定的输入参数。

我们通过netron(https://netron.app/)来查看yunet.onnx的模型结构(部分)
在这里插入图片描述
在这里插入图片描述
从图中可以看到,官网上下载的模型结构batch_size,height,width都是未知的,这在OpenCV中是不支持的,虽然问题知道了,但是在网上查了几天都没找到解决办法!!!
PS:遇到bug真的不能陷进去,放一放,平静一下,第二天说不定就能解决了

二、解决办法

非常感谢这几篇文章,让我对onnx模型有了更多的了解,最后终于摸索出来(把自己给感动了)
如何修改已有的ONNX模型 https://tool.4xseo.com/a/15892.html
模型部署入门教程(五):ONNX 模型的修改与调试
https://zhuanlan.zhihu.com/p/516920606?utm_medium=social&utm_oi=800114666985648128&utm_id=0
官网讨论
https://github.com/opencv/opencv/issues/23288


先看onnx解释:
ONNX 在底层是用 Protobuf 定义的。Protobuf,全称 Protocol Buffer,是 Google 提出的一套表示和序列化数据的机制。使用 Protobuf 时,用户需要先写一份数据定义文件,再根据这份定义文件把数据存储进一份二进制文件。可以说,数据定义文件就是数据类,二进制文件就是数据类的实例。

神经网络本质上是一个计算图。计算图的节点是算子,边是参与运算的张量。而通过可视化 ONNX 模型,我们知道 ONNX 记录了所有算子节点的属性信息,并把参与运算的张量信息存储在算子节点的输入输出信息中。事实上,ONNX 模型的结构可以用类图大致表示如下:
在这里插入图片描述
我们把yunet.onnx模型先加载进来

# 使用onnx模块
model = onnx.load('./opencvmodels/yunet.onnx')
onnx.checker.check_model(model) # 验证Onnx模型是否准确

通过验证说明OpenCV提供的onnx模型是没有问题的。
接着我们打印出yunet的计算图

# 计算图太大了
print(model.graph)

在这里插入图片描述
可以看到initializer中储存了一个节点的数据信息,其中的名字name都是跟netron中看到的一一对应,因为数据太多了,看不全,我们只把计算图的ninput输入部分打印出来,看看是怎么样的

print(model.graph.input)

[name: “input”
type {
tensor_type {
elem_type: 1
shape {
dim {
dim_param: “batch_size”
}
dim {
dim_value: 3
}
dim {
dim_param: “height”
}
dim {
dim_param: “width”
}
}
}
}
]

可以看到输入结构在onnx中是一个可迭代的列表容器,包含了name名字,type类型,type中又定义了输入的维度,现在的思路就是要把shape中的dim_param: "height"和dim_param: "width"换成固定的值即dim_value,我们一层一层来打印:

for input_node in model.graph.input:
    print(input_node)

name: “input”
type {
tensor_type {
elem_type: 1
shape {
dim {
dim_param: “batch_size”
}
dim {
dim_value: 3
}
dim {
dim_param: “height”
}
dim {
dim_param: “width”
}
}
}
}

我们遍历输入结构,可以看到外层的括号去掉了,我们接着向下层索引:

for input_node in model.graph.input:
    print(input_node.type)

tensor_type {
elem_type: 1
shape {
dim {
dim_param: “batch_size”
}
dim {
dim_value: 3
}
dim {
dim_param: “height”
}
dim {
dim_param: “width”
}
}
}

for input_node in model.graph.input:
    print(input_node.type.tensor_type.shape)

dim {
dim_param: “batch_size”
}
dim {
dim_value: 3
}
dim {
dim_param: “height”
}
dim {
dim_param: “width”
}

那么思路就有了,我们只要索引到dim这一层,然后把其中的dim_param: "height"和dim_param: "width"替换成固定的dim_value: 320就可以了

for input_node in model.graph.input:
    # print(input_node.type.tensor_type.shape)
    input_node.type.tensor_type.shape.dim[2].dim_value = 320
    input_node.type.tensor_type.shape.dim[3].dim_value = 320
    print(input_node.type.tensor_type.shape)

想要的结果出现了!!!

dim {
dim_param: “batch_size”
}
dim {
dim_value: 3
}
dim {
dim_value: 320
}
dim {
dim_value: 320
}

接下来我们重新验证模型有没有问题,然后将模型保存成新的模型

onnx.checker.check_model(model)
onnx.save(model, 'opencvmodels/new_yunet.onnx')

我们重新在netron中查看一下模型结构
在这里插入图片描述
新的yunet模型的输入已经改成固定输入尺寸,下面我们来测试一下模型能不能用

recognize_net = cv2.dnn.readNetFromONNX('./opencvmodels/new_yunet.onnx')
dnn_faceDetector = cv2.FaceDetectorYN_create(model="./opencvmodels/new_yunet.onnx", config="", input_size=(320, 320))

没有报错!!! 呜呜呜~~~~

来看一下人脸识别效果
(借用彭于晏哥哥的照片)
在这里插入图片描述
人脸对齐
cv2.FaceDetectorYN还封装了人脸对齐,超级方便有木有

face1_align = faceRecognizer.alignCrop(image1, face1_detect[1])

在这里插入图片描述
人脸检测
检测的准确率很高!!

在这里插入图片描述
人脸匹配结果,判断出这是同一个人,这里使用了两种距离匹配方法:余弦距离和L2距离,结果一样。
大功告成!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1077962.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据安全 | 【实验】DES加密解密

文章目录 📚DES介绍📚基本流程🐇初始IP置换和逆置换🐇计算每一轮的子密钥🐇迭代与F函数⭐️E扩展置换⭐️S盒压缩⭐️P盒置换⭐️最后的F函数及迭代实现 📚DES加密解密实现📚关于雪崩效应 &…

企业如何实现信息化管理?IT运维管理有什么注意的事项?

随着信息技术的迅猛发展,企业所面临的IT运维管理挑战也日益复杂。在复杂的IT系统中,如何实施有效的运维管理已成为企业信息化部门关注的重点。本文分析了当前的IT运维管理现状以及所遇到的问题,并提出相应的解决方案——“的修”运维工单管理…

点云处理开发测试题目 完整解决方案

点云处理开发测试题目 文件夹中有一个场景的三块点云数据,单位mm。是一个桌子上放了一个纸箱,纸箱上有四个圆孔。需要做的内容是: 1. 绘制出最小外接立方体,得到纸箱的长宽高值。注意高度计算是纸箱平面到桌子平面的距离。 2. 计算出纸箱上的四个圆的圆心坐标和半径,对圆…

活动聊天机器人如何革新活动行业

在如今快节奏的时代,活动策划和管理对于任何活动的成功变得至关重要。无论是会议、展览会还是企业聚会,组织者都努力为参与者创造难忘的体验,同时确保幕后的顺利执行。然而,由于有许多任务需要处理且资源有限,管理活动…

2023年另类数据研究报告

第一章 引言 1.1 定义 另类数据,通常被定义为传统金融报告和宏观经济指标之外的信息,近年来在投资领域中的重要性日益增长。这种数据通常来源于非传统的数据源,例如社交媒体、卫星图像、互联网搜索记录和消费者交易数据等。与传统数据相比…

docker入门加实战—从部署MySQL入门docker

docker入门加实战—从部署MySQL入门docker docker部署MySQL 输入如下命令: docker run -d \--name mysql \-p 3306:3306 \-e TZAsia/Shanghai \-e MYSQL_ROOT_PASSWORD123 \mysql部署成功截图如下: 当执行命令后,Docker做的第一件事情&…

MAX插件CGMAGIC一键解决效果图在软包硬包上费时费力操作!

使用3dmax软件进行室内建模中的软包、硬包、欧式真皮沙发等家具建模这些的操作相对是比较多的,3dmax软包建模来说,进行手动建模一向都是非常头痛和耗时的事情。 CGMAGIC小编来和大家聊聊,如何一键解决效果图在软包硬包上费时费力操作&#xf…

mp4音视频分离技术

文章目录 问题描述一、分离MP3二、分离无声音的MP4三、结果 问题描述 MP4视频想拆分成一个MP3音频和一个无声音的MP4文件 一、分离MP3 ffmpeg -i C:\Users\Administrator\Desktop\一个文件夹\我在财神殿里长跪不起_完整版MV.mp4 -vn C:\Users\Administrator\Desktop\一个文件…

在XShell里Linux服务器创建和删除子用户

文章目录 在XShell里Linux服务器创建和删除子用户1、创建子用户2、删除子用户 在XShell里Linux服务器创建和删除子用户 1、创建子用户 注意:只有root用户下才能创建子用户 步骤: 首先打开XShell登录上root用户,然后输入useradd 要添加的用户…

SpringBoot-黑马程序员-学习笔记(三)

目录 30.springboot整合MyBatis-plus 32.SSM整合 38.MP中的条件查询 小知识:许多放在类前面的注解,比如Mapper,Service都是将该类定义成一个Bean,交给spring管理 39.Service模块 30.springboot整合MyBatis-plus 1.创建普通springboot项目…

简单大方的自我介绍 PPT 格式

自我介绍是展示自己的机会,同时也是展现自信和魅力的重要时刻。通过简单大方的PPT格式,可以更好地展示自己的个性和才华。下面是一些建议,帮助你在自我介绍中展现自信和魅力。 1. 打造简洁而有吸引力的PPT布局: - 选择简洁大方的背…

牛客 day2 - 7

9.25 day 2 1. 简述方法重写与方法重载的意义与区别: 方法重写: 1.参数列表必须完全与被重写方法相同 //参数列表(分为四种): (1)无参无返回值方法; (2&#xff0…

视频监控系统EasyCVR如何通过API接口获取国标GB28181协议接入的实时录像?

安防监控视频汇聚平台EasyCVR基于云边端一体化架构,具有强大的数据接入、处理及分发能力,可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能分析等功能。平台也提供丰富的API接口供开发者集成、调用…

【吞噬星空4】又魔改,徐欣自杀殉情,变成被阿特金击杀,引发粉丝吐槽

Hello,小伙伴们,我是小郑继续为大家深度解析国漫资讯。 ​ 吞噬星空第四季动画已经更新了,虽然没有什么炸裂的打斗,都是一些过渡性的戏份,但是罗峰成功孕育出了人类分身,阿特金三人组又在为非作歹,这次他…

uCOSIII实时操作系统 四 任务管理

目录 uCOSIII启动过程: stm32的启动过程: uCOSIII的启动过程: 任务状态: 任务控制块: 任务堆栈: 任务就绪表: 优先级位映射表//OSPrioTbl[] 位映射表: 查找优先级&#xf…

GNN+RA 文献阅读

[1] X. Wang et al., ‘Scalable Resource Management for Dynamic MEC: An Unsupervised Link-Output Graph Neural Network Approach’. paper code:GitHub - UNIC-Lab/LOGNN: This is the code for paper "Scalable Resource Management for Dynamic MEC:…

Linux[find命令]-根据路径和条件搜索指定文件并删除

一、find命令简介 find命令:用于根据给定的路径和条件查找相关文件或目录,参数灵活方便,且支持正则表达式,结合管道符后能够实现更加复杂的功能。 基本语法格式:find pathname -options 搜索内容 [其他选项] pathname…

链表(2)——带头双向循环链表

🍁一、链表的分类 🌕1.单向或者双向 🌕2.带头或者不带头(有无哨兵) 🌕3.循环或者不循环 🌕4.无头单向非循环链表(常用) 🌕5.带头双向循环链表(常用…

SNMP报文与MIB Browser软件讲解

目录 SNMP报文结构 MIB Browser软件讲解 具体的操作步骤 MIB操作方式 SNMP报文结构 UDP端口读/写为161,Trap为162 版本号 版本号 名称 0 V1 1 V2c 2 V3 团体字 团体字相当于管理方和被管理方进行校验的密钥 读写团体字 两端需要配置为一致 PDU类型——标…

5项先进采购技术,帮助你的企业脱颖而出

持续的改进对保持每个企业的正常运转有着重要作用,采购部门也不例外。 以前,采购团队主要关注两个方面:降低成本和减少风险。随着自动化和云服务的兴起,如今他们还需要关注采购决策的效率、可访问性和可持续性。 技术与采购的融合…