Yolov7模型转ONNX后用OpenCV部署出现NonMaxSuppression层报错
问题分析与解决方案
报错原因
- 模型结构不兼容:Yolov7默认导出的ONNX模型内置了NonMaxSuppression(NMS)层,但你的代码是针对Yolov5设计的——Yolov5导出的ONNX输出原始检测框,由代码手动做NMS,两者输出结构完全不同。
- OpenCV版本限制:你使用的OpenCV 4.5.5对ONNX标准的NMS层支持不完善,无法解析Yolov7内置的NMS节点。
解决方案一:重新导出不带内置NMS的Yolov7 ONNX模型
直接导出和Yolov5输出格式一致的模型,这样可以完全复用你现有的后处理代码。
在Yolov7项目根目录下执行导出命令,添加--no-nms参数禁用内置NMS:
python export.py --weights runs/train/exp/weights/best.pt --include onnx --simplify --opset 12 --no-nms
--no-nms:禁用模型内置的NMS层--opset 12:指定ONNX算子版本,提升兼容性--simplify:简化ONNX模型结构
导出完成后,用新生成的ONNX文件替换原来的data.onnx,原代码无需修改即可运行。
解决方案二:修改代码适配带内置NMS的Yolov7模型
如果不想重新导出模型,可调整后处理逻辑,直接解析模型输出的NMS结果:
替换原代码中的Detect函数为以下内容:
def Detect(): net = cv2.dnn.readNet(path+"Config/data.onnx") # 处理图像,保持输入尺寸和模型一致 blob = cv2.dnn.blobFromImage(img , 1/255.0, (640, 640), swapRB=True) net.setInput(blob) # Yolov7带NMS的ONNX输出是4个张量:[num_detections, boxes, scores, classes] num_detections, boxes, scores, classes = net.forward(net.getUnconnectedOutLayersNames()) class_list = [] with open(path+"Config/obj.names", "r") as f: class_list = [cname.strip() for cname in f.readlines()] image_width, image_height, _ = img.shape x_factor = image_width / 640 y_factor = image_height / 640 # 解析检测结果 for i in range(int(num_detections[0][0])): score = scores[0][i] if score < 0.55: continue class_id = int(classes[0][i]) box = boxes[0][i] # 转换坐标到原始图像尺寸 x1 = int(box[0] * x_factor) y1 = int(box[1] * y_factor) x2 = int(box[2] * x_factor) y2 = int(box[3] * y_factor) box = [x1, y1, x2-x1, y2-y1] allProductsArray.append(class_list[class_id]) # 绘制检测框和标签 cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 255), 2) cv2.rectangle(img, (x1, y1 - 20), (x2, y1), (0, 255, 255), -1) cv2.putText(img, class_list[class_id], (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0)) cv2.putText(img, f"{score:.2f}", (x1+60, y1), cv2.FONT_HERSHEY_SIMPLEX, .6, (0,0,0))
额外建议
如果选择方案二,建议升级OpenCV到4.6.0及以上版本,新版本对ONNX算子的支持更完善,能避免很多层解析问题。
内容的提问来源于stack exchange,提问作者techgtec
相关产品推荐
相关产品推荐

