• OpenCV之MobileNet-SDD目标检测


    • 💂 个人主页:风间琉璃
    • 🤟 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主
    • 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)订阅专栏

    目录

    前言

    一、MobileNet-SSD 简介

    二、加载网络模型

    三、预处理

    四、执行推理

    五、解析输出


    前言

    MobileNet系列是谷歌为适配移动终端提供了一系列模型,包含图像分类:mobileNet v1,mobileNet v2,mobileNet v3,目标检测SSD mobileNet等。

    MobileNet-SSD 是以 MobileNet 为基础的目标检测算法,很好的继承了 MobileNet 预测速度快,易于部署的特点,能够很好的在多种设备上完成图像目标检测任务。

    一、MobileNet-SSD 简介

    想要了解MobileNet系列,需要先了解深度可分离卷积(depthwise separable convolution),在MobileNet网络中,由depthwise(DW)和pointwise(PW)两个部分结合起来,用来提取特征feature map。其核心思想就是减少卷积计算以及参数

    对于SSD来说,其针对YOLO和Faster R-CNN的各自不足与优势,SSD整个网络采取了one stage的思想,以此提高检测速度。SSD就是在VGG的网络基础之上,在中间几层提取了featuremap,用来提取Default Bounding Boxes,做目标检测。

    MobileNet-SSD它采用SSD的思想,在MobileNet2基础上进行改善,其网络模型结构参考:Netscope (ethereon.github.io)

    二、加载网络模型

    这里使用Caffe深度学习框架中已经预训练好的SSD网络,需要相应的模型权重文件(.caffemodel)以及模型配置文件(.prototxt)。

    加载模型和配置文件如下所示:

    1. //分类标签名称
    2. const char* classNames[] = { "background", "aeroplane", "bicycle", "bird", "boat",
    3. "bottle", "bus", "car", "cat", "chair",
    4. "cow", "diningtable", "dog", "horse", "motorbike",
    5. "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor" };
    6. //模型文件
    7. String model = "F:/data/CQU/VS/MobileNetSSD_ObjectDetection/MobileNetSSD_deploy.caffemodel";
    8. //配置文件
    9. String config = "F:/data/CQU/VS/MobileNetSSD_ObjectDetection/MobileNetSSD_deploy.prototxt";

     由于该网络的目标检测对象只有20个类别,这里直接将目标检测标签用一个字符串数组存储。

    三、预处理

    通过 OpenCV中的VideoCapture类读取视频流。这里我们需要对每一帧图像进行预处理后,在进行目标检测。

    1. const size_t width = 300; //图像宽度
    2. const size_t height = 300; //图像高度
    3. const float meanVal = 127.5;//均值
    4. const float scaleFactor = 0.007843f;
    5. //预处理
    6. Mat inputblob = blobFromImage(frame, scaleFactor, Size(width, height), meanVal, false);
    7. //输入
    8. net.setInput(inputblob, "data");

    预处理主要要使输入图像尺寸满足网络输入的大小,网络输入的大小可以在配置文件prototxt中查看。

    四、执行推理

    图片预处理完成,就可以利用网络进行预测,这个过程也是把输入图像在网络各层中前向进行传播。

    1. //预测
    2. Mat detection = net.forward("detection_out");

    这里的detection_out是网络的输出层的名称,在网络的配置文件中可以查看。 

    若要使用CUDA进行加速可以推理前加入下面的代码

    1. //使用cuda加速
    2. net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
    3. net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);

    五、解析输出

    在 detection中存储着网络的所有输出。在获得正确的分类类别之前,还有一些需要与处理得步骤。

    1. //获取分类的结果
    2. Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
    3. //置信度设置,越小检测到的物体越多,官方推荐为0.25
    4. float confidence_threshold = 0.35;
    5. for (int i = 0; i < detectionMat.rows; i++)
    6. {
    7. //获取置信度
    8. float confidence = detectionMat.at<float>(i, 2);
    9. //过滤置信度较低的结果
    10. if (confidence > confidence_threshold)
    11. {
    12. //获取分类索引值
    13. size_t objIndex = (size_t)(detectionMat.at<float>(i, 1));
    14. //获取目标边框坐标
    15. float tl_x = detectionMat.at<float>(i, 3) * frame.cols;
    16. float tl_y = detectionMat.at<float>(i, 4) * frame.rows;
    17. float br_x = detectionMat.at<float>(i, 5) * frame.cols;
    18. float br_y = detectionMat.at<float>(i, 6) * frame.rows;
    19. Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
    20. rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
    21. putText(frame, format("%s:%.2f", classNames[objIndex], confidence), Point(tl_x, tl_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
    22. }
    23. }

    帧率的计算:

    在图像进行目标检测之前加入下面一句代码,获取当前系统的计时周期

    1. //获得当前系统的计时间周期数,求FPS
    2. double t = (double)getTickCount();

     然后在图像目标检测完加入下面的代码,计算FPS并显示

    1. //FPS计算
    2. t = ((double)getTickCount() - t) / getTickFrequency();//求输入帧后经过的周期数/每秒系统计的周期数=一帧用时多少秒
    3. double fps = 1.0 / t;//求倒数得到每秒经过多少帧,即帧率
    4. string text = "FPS:" + to_string(fps);
    5. cv::putText(frame, text, Point(10, 50), FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2, 8, 0);

    运行结果:

    (1)不使用CUDA:

    mobile

    (2)使用CUDA

    MobileNet-SSD CUDA加速

    opencv_cuda_mobilenet_ssd

    源码:完整程序下载:OpenCVSSD目标检测(C++)资源-CSDN文库

    1. // MobileNetSSD_ObjectDetection.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    2. //
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. using namespace cv;
    9. using namespace cv::dnn;
    10. using namespace std;
    11. const size_t width = 300; //图像宽度
    12. const size_t height = 300; //图像高度
    13. const float meanVal = 127.5;//均值
    14. const float scaleFactor = 0.007843f;
    15. //分类标签名称
    16. const char* classNames[] = { "background", "aeroplane", "bicycle", "bird", "boat",
    17. "bottle", "bus", "car", "cat", "chair",
    18. "cow", "diningtable", "dog", "horse", "motorbike",
    19. "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor" };
    20. //模型文件
    21. String model = "F:/data/CQU/VS/MobileNetSSD_ObjectDetection/MobileNetSSD_deploy.caffemodel";
    22. //配置文件
    23. String config = "F:/data/CQU/VS/MobileNetSSD_ObjectDetection/MobileNetSSD_deploy.prototxt";
    24. int main()
    25. {
    26. //读取视频流
    27. VideoCapture capture("F:/data/CQU/VS/MobileNetSSD_ObjectDetection/vtest.avi");
    28. if (capture.isOpened())
    29. {
    30. namedWindow("原视频", CV_WINDOW_AUTOSIZE);
    31. //视频宽带
    32. int w = capture.get(CAP_PROP_FRAME_WIDTH);
    33. //视频高度
    34. int h = capture.get(CAP_PROP_FRAME_HEIGHT);
    35. printf("frame width : %d, frame height : %d", w, h);
    36. }
    37. //加载网络模型
    38. Net net = readNetFromCaffe(config, model);
    39. //对视频的每一帧进行检测
    40. Mat frame;
    41. while (capture.read(frame))
    42. {
    43. //显示原视频
    44. imshow("原视频",frame);
    45. //获得当前系统的计时间周期数,求FPS
    46. double t = (double)getTickCount();
    47. //预处理
    48. Mat inputblob = blobFromImage(frame, scaleFactor, Size(width, height), meanVal, false);
    49. //输入
    50. net.setInput(inputblob, "data");
    51. //使用cuda加速
    52. net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
    53. net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);
    54. //预测
    55. Mat detection = net.forward("detection_out");
    56. //获取分类的结果
    57. Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
    58. //置信度设置,越小检测到的物体越多,官方推荐为0.25
    59. float confidence_threshold = 0.35;
    60. for (int i = 0; i < detectionMat.rows; i++)
    61. {
    62. //获取置信度
    63. float confidence = detectionMat.at<float>(i, 2);
    64. //过滤置信度较低的结果
    65. if (confidence > confidence_threshold)
    66. {
    67. //获取分类索引值
    68. size_t objIndex = (size_t)(detectionMat.at<float>(i, 1));
    69. //获取目标边框坐标
    70. float tl_x = detectionMat.at<float>(i, 3) * frame.cols;
    71. float tl_y = detectionMat.at<float>(i, 4) * frame.rows;
    72. float br_x = detectionMat.at<float>(i, 5) * frame.cols;
    73. float br_y = detectionMat.at<float>(i, 6) * frame.rows;
    74. Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
    75. rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
    76. putText(frame, format("%s:%.2f", classNames[objIndex], confidence), Point(tl_x, tl_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
    77. }
    78. }
    79. //FPS计算
    80. t = ((double)getTickCount() - t) / getTickFrequency();//求输入帧后经过的周期数/每秒系统计的周期数=一帧用时多少秒
    81. double fps = 1.0 / t;//求倒数得到每秒经过多少帧,即帧率
    82. string text = "FPS:" + to_string(fps);
    83. cv::putText(frame, text, Point(10, 50), FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2, 8, 0);
    84. //显示处理结果
    85. imshow("MobileNetSSD", frame);
    86. char c = waitKey(1);
    87. //ESC退出
    88. if (c == 27)
    89. {
    90. break;
    91. }
    92. }
    93. capture.release();
    94. waitKey(0);
    95. }

    结束语
    感谢你观看我的文章呐~本次航班到这里就结束啦 🛬

    希望本篇文章有对你带来帮助 🎉,有学习到一点知识~

    躲起来的星星🍥也在努力发光,你也要努力加油(让我们一起努力叭)。

    最后,博主要一下你们的三连呀(点赞、评论、收藏),不要钱的还是可以搞一搞的嘛~

    不知道评论啥的,即使扣个666也是对博主的鼓舞吖 💞 感谢 💐

  • 相关阅读:
    在vue中点击右键出现自定义操作菜单
    FoneDog iOS Unlocker(ios解锁工具) 适用macos电脑
    数值分析思考题(钟尓杰版)参考解答——第五章
    vscode文件夹折叠问题
    【Ubuntu】Systemctl控制nacos启动与关闭
    面试冲刺季,Android进阶开发知识点面试题全汇总
    强大的开源API接口可视化管理平台-YApi
    MySQL安装及应用合集(5):如何优雅地写MySQL
    钢建筑模板和木建筑模板的优缺点?
    模拟前端ADC芯片LH001-91
  • 原文地址:https://blog.csdn.net/qq_53144843/article/details/132833977