1.由于OpenCV DNN中的slice层不支持step为2,所以在转换模型时需要修改代码,修改的地方在models/common.py中Focus类

  • 修改前:
class Focus(nn.Module):# Focus wh information into c-spacedef __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groupssuper(Focus, self).__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)return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
  • 修改后
class Focus(nn.Module):# Focus wh information into c-spacedef __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groupssuper(Focus, self).__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)#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(x)

2.转换模型

python models/export.py --weights runs/exp/weights/best.pt
# --weights: 训练得到的模型

运行后,onnx模型保存为了runs/exp/weights/best.onnx,这个模型就可以用OpenCV DNN进行推理。

3.DNN C++推理

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>void imshow(std::string name, const cv::Mat& cv_src)
{cv::namedWindow(name, 0);int max_rows = 800;int max_cols = 800;if (cv_src.rows >= cv_src.cols && cv_src.rows > max_rows){cv::resizeWindow(name, cv::Size(cv_src.cols * max_rows / cv_src.rows, max_rows));}else if (cv_src.cols >= cv_src.rows && cv_src.cols > max_cols){cv::resizeWindow(name, cv::Size(max_cols, cv_src.rows * max_cols / cv_src.cols));}cv::imshow(name, cv_src);
}inline float sigmoid(float x)
{return 1.f / (1.f + exp(-x));
}void sliceAndConcat(cv::Mat& img, cv::Mat* input)
{const float* srcData = img.ptr<float>();float* dstData = input->ptr<float>();using Vec12f = cv::Vec<float, 12>;for (int i = 0; i < input->size[2]; i++){for (int j = 0; j < input->size[3]; j++){for (int k = 0; k < 3; ++k){dstData[k * input->size[2] * input->size[3] + i * input->size[3] + j] =srcData[k * img.size[2] * img.size[3] + 2 * i * img.size[3] + 2 * j];}for (int k = 0; k < 3; ++k){dstData[(3 + k) * input->size[2] * input->size[3] + i * input->size[3] + j] =srcData[k * img.size[2] * img.size[3] + (2 * i + 1) * img.size[3] + 2 * j];}for (int k = 0; k < 3; ++k) {dstData[(6 + k) * input->size[2] * input->size[3] + i * input->size[3] + j] =srcData[k * img.size[2] * img.size[3] + 2 * i * img.size[3] + 2 * j + 1];}for (int k = 0; k < 3; ++k){dstData[(9 + k) * input->size[2] * input->size[3] + i * input->size[3] + j] =srcData[k * img.size[2] * img.size[3] + (2 * i + 1) * img.size[3] + 2 * j + 1];}}}
}std::vector<cv::String> getOutputNames(const cv::dnn::Net& net)
{static std::vector<cv::String> names;if (names.empty()){std::vector<int> outLayers = net.getUnconnectedOutLayers();std::vector<cv::String> layersNames = net.getLayerNames();names.resize(outLayers.size());for (size_t i = 0; i < outLayers.size(); i++){names[i] = layersNames[outLayers[i] - 1];}}return names;
}void drawPred(int classId, float conf, int left, int top, int right, int bottom, cv::Mat& frame,const std::vector<std::string> &classes)
{cv::rectangle(frame, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(0, 255, 0), 3);std::string label = cv::format("%.2f", conf);if (!classes.empty()) {CV_Assert(classId < (int)classes.size());label = classes[classId] + ": " + label;}int baseLine;cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);top = std::max(top, labelSize.height);cv::rectangle(frame, cv::Point(left, top - round(1.5 * labelSize.height)), cv::Point(left + round(1.5 * labelSize.width), top + baseLine), cv::Scalar(0, 255, 0), cv::FILLED);cv::putText(frame, label, cv::Point(left, top), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(), 2);
}void postprocess(cv::Mat& cv_src, std::vector<cv::Mat>& outs, const std::vector<std::string>& classes, int net_size)
{float confThreshold = 0.4f;float nmsThreshold = 0.5f;std::vector<int> classIds;std::vector<float> confidences;std::vector<cv::Rect> boxes;int strides[] = { 8, 16, 32 };std::vector<std::vector<int> > anchors = {{ 10,13, 16,30, 33,23 },{ 30,61, 62,45, 59,119 },{ 116,90, 156,198, 373,326 }};for (size_t k = 0; k < outs.size(); k++){float* data = outs[k].ptr<float>();int stride = strides[k];int num_classes = outs[k].size[4] - 5;for (int i = 0; i < outs[k].size[2]; i++){for (int j = 0; j < outs[k].size[3]; j++){for (int a = 0; a < outs[k].size[1]; ++a){float* record = data + a * outs[k].size[2] * outs[k].size[3] * outs[k].size[4] +i * outs[k].size[3] * outs[k].size[4] + j * outs[k].size[4];float* cls_ptr = record + 5;for (int cls = 0; cls < num_classes; cls++) {float score = sigmoid(cls_ptr[cls]) * sigmoid(record[4]);if (score > confThreshold){float cx = (sigmoid(record[0]) * 2.f - 0.5f + (float)j) * (float)stride;float cy = (sigmoid(record[1]) * 2.f - 0.5f + (float)i) * (float)stride;float w = pow(sigmoid(record[2]) * 2.f, 2) * anchors[k][2 * a];float h = pow(sigmoid(record[3]) * 2.f, 2) * anchors[k][2 * a + 1];float x1 = std::max(0, std::min(cv_src.cols, int((cx - w / 2.f) * (float)cv_src.cols / (float)net_size)));float y1 = std::max(0, std::min(cv_src.rows, int((cy - h / 2.f) * (float)cv_src.rows / (float)net_size)));float x2 = std::max(0, std::min(cv_src.cols, int((cx + w / 2.f) * (float)cv_src.cols / (float)net_size)));float y2 = std::max(0, std::min(cv_src.rows, int((cy + h / 2.f) * (float)cv_src.rows / (float)net_size)));classIds.push_back(cls);confidences.push_back(score);boxes.push_back(cv::Rect(cv::Point(x1, y1), cv::Point(x2, y2)));}}}}}}std::vector<int> indices;cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);for (size_t i = 0; i < indices.size(); i++) {int idx = indices[i];cv::Rect box = boxes[idx];drawPred(classIds[idx], confidences[idx], box.x, box.y,box.x + box.width, box.y + box.height, cv_src, classes);}
}int main(int argc, char* argv[])
{std::string path = "images";std::vector<std::string> filenames;cv::glob(path, filenames, false);for (auto name : filenames){cv::Mat cv_src = cv::imread(name);if (cv_src.empty()){continue;}std::vector<std::string> class_names{ "ida","idb" };int net_size = 640;cv::Mat blob = cv::dnn::blobFromImage(cv_src, 1.0 / 255, cv::Size(net_size, net_size),cv::Scalar(0, 0, 0), true, false);cv::dnn::Net net = cv::dnn::readNet("model/ODID_DNN.onnx");const int sz[] = { 1, 12, net_size / 2, net_size / 2 };cv::Mat input = cv::Mat(4, sz, blob.type());sliceAndConcat(blob, &input);net.setInput(input);auto t0 = cv::getTickCount();std::vector<cv::Mat> outs;net.forward(outs, getOutputNames(net));postprocess(cv_src, outs, class_names, net_size);auto t1 = cv::getTickCount();std::cout << "elapsed time: " << (t1 - t0) * 1000.0 / cv::getTickFrequency() << "ms" << std::endl;imshow("img", cv_src);cv::waitKey();}return 0;
}

检测一张图像大概要0.1秒左右。

4.模型和源码以上传CSDN。地址:https://download.csdn.net/download/matt45m/46982918

Yolov5身份证检测——C++ OpenCV DNN推理相关推荐

  1. yolov5训练自己的数据集,OpenCV DNN推理

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为4238字,预计阅读9分钟 前言 上一篇<OpenCV--自学笔记>搭建好了yolov5的环境,作为目标检测在应用中 ...

  2. 超简单的pyTorch训练-onnx模型-C++ OpenCV DNN推理(附源码地址)

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为1974字,预计阅读5分钟 前言 很早就想学习深度学习了,因为平时都是自学,业余时间也有限,看过几个pyTorch的入门,都是一 ...

  3. 35、ubuntu20.04搭建瑞芯微的npu仿真环境和测试rv1126的Debain系统下的yolov5+npu检测功能以及RKNN推理部署以及RTSP视频流解码

    基本思想:手中有一块core-1126/1109-JD4,记录一下其刷机过程和开发人数统计,与树莓派的nanodet 每帧200ms对比一下 第一步:刷机,真的是难,各种各样的小问题,反正成功的方法只 ...

  4. Yolov5身份证检测——模型训练

    前言 系统环境是win10,显卡RTX3080;cuda10.2,cudnn7.1;OpenCV4.5;yolov5用的是5s的模型,2020年8月13日的发布v3.0这个版本; ncnn版本是202 ...

  5. 在 C++ 和 Python 中使用 YOLOv5 OpenCV DNN 进行对象检测

    最近,YOLOv5 扩展了对 OpenCV DNN 框架的支持,这增加了使用这种最先进的对象检测模型的优势--Yolov5 OpenCV DNN 模块. 我们已经对 YOLOv5 进行了一段时间的实验 ...

  6. yolov8 OpenCV DNN 部署 推理报错

    yolov8是yolov5作者发布的新作品 目录 1.下载源码 2.下载权重 3.配置环境 4.导出onnx格式 5.OpenCV DNN 推理 1.下载源码 git clone https://gi ...

  7. YOLOv5发布第六个版本,支持一键适配OpenVINO/OpenCV DNN部署

    YOLOv5发布了第六个版本,其它我不说,什么是开源精神,不是写个程序扔github就叫开源,而是持续不断改进,精益求精,不断演化版本,增加最有商业价值的功能,YOLOv5做到了.看看最新版本都有哪些 ...

  8. 深度学习与OpenCV DNN模块:权威指南

    计算机视觉领域自20世纪60年代末就已经存在.图像分类和目标检测是计算机视觉领域的一些最古老的问题,研究人员已经努力解决了几十年.使用神经网络和深度学习,我们已经达到了一个阶段,计算机可以开始真正地理 ...

  9. pyTorch入门(四)——导出Minist模型,C++ OpenCV DNN进行识别

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为2548字,预计阅读8分钟 前言 前三章介绍了pyTorch训练的相关,我们也保存模型成功了,今天这篇就是使用C++ OpenC ...

最新文章

  1. 点云深度学习的Pytorch框架
  2. 这款可视化工具,Java 调优起来真的 so easy啊
  3. 关于iar加st-link,报出SWIM error [30200]错误,我自己处理的方法,usb重新插拔
  4. android jni示例_Android服务示例
  5. repeater的嵌套(转+总结)[http://www.cnblogs.com/esshs/archive/2005/04/07/132825.html]
  6. target sum java_LeetCode 494. Target Sum
  7. Gartner数据:RPA以75.6%增长率成2019年Q1增速最快的企业级软件(附全球十大RPA市场数据)
  8. Lucene创建索引和搜索索引
  9. ESXI7.0主机安装群晖DS3617xs
  10. Pytorch:lr_schedule恢复训练的注意事项
  11. python倒计时代码turtle_python实现屏保计时器
  12. springboot实现oos上传下载
  13. gnuplot绘图程序中对线型(linetype)、点型(pointtype)、线条宽度(linewidth)、点大小(pointsize)、图样
  14. open stack——Nove计算服务
  15. Storm学习(一)Storm介绍
  16. python矩阵运算_python矩阵计算
  17. WINCE 车机系统介绍
  18. Win10企业版系统如何连接局域网共享打印机?五步即可。
  19. 校园网高清视频下载器
  20. 怎样创建网页快捷方式,用非默认浏览器打开该网页

热门文章

  1. comsol积分函数_怎样在COMSOL中实现时间和空间积分
  2. linux目录挂载到内存,Linux中内存挂载到目录下
  3. 第十天2017/04/23(1、企业财富库:“循环单链表”的设计与实现)
  4. 【深度学习】单位高斯化
  5. getParameter的用法总结
  6. Executors创建的4种线程池的使用
  7. Java设计模式 - 适配器模式
  8. 关于 Java 对象序列化您不知道的 5 件事
  9. 基于 Python Matplotlib 模块的高质量图形输出
  10. Hadoop学习笔记—4.初识MapReduce