• 【OpenCV】车辆识别 C++ OpenCV 原理介绍 + 案例实现


    目录

    前言 

    一、图像处理

    💻二值化处理

    💻膨胀、腐蚀

    💻开运算、闭运算

    二、案例实现

    Step1:灰度处理

    Step2:对视频进行帧差处理

    Step3:二值化处理

    Step4:腐蚀处理

    Step5:膨胀处理 

    Step6:标记、框选目标

    💡完整代码

    三、总结 


    前言 

    本文主要以车辆识别为目标,利用 C++语言 结合 Qt + OpenCV 进行图像处理相关步骤的讲解

    一、图像处理

    💻二值化处理

    二值化:是通过遍历灰度图中点,将图像信息二值化处理,处理过后的图片只有黑白两种色值

    📍作用:

    • 图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果
    • 在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓

    📍全局阈值:

    函数:threshold()

    参数:

    参数1:InputArray类型的src,输入数组,填单通道 , 8或32位浮点类型的Mat即可 

    参数2:OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放输出结果,且和第一个参数中的Mat变量有一样的尺寸和类型

    参数3:double类型的thresh,阈值的具体值

    参数4:double类型的maxval,当第5个参数阈值类型type取 THRESH_BINARY 或THRESH_BINARY_INV阈值类型时的最大值

    参数5:int类型的type,取阀值的算法

    📍局部阈值:

    函数:adaptiveThreshold()

    参数:

    参数1:InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可

    参数2:函数运算后的结果存放在这。即为输出图像

    参数3:预设满足条件的最大值

    参数4:指定自适应阈值算法,可选择ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C两种

    参数5:指定阈值类型,可选择THRESH_BINARY或者THRESH_BINARY_INV两种

    (即二进制阈值或反二进制阈值)

    参数6:表示邻域块大小,用来计算区域阈值,一般选择为3、5、7等

    参数7:参数C表示与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数

    💻膨胀、腐蚀

    • 膨胀和腐蚀是针对图片的二值化数据进行操作的主要是针对高亮部分
    • 膨胀就是使用算法,将图像的边缘扩大些,作用就是将目标的边缘或者是内部的坑填掉 
    • 腐蚀就是使用算法,将图像的边缘腐蚀掉,作用就是将目标的边缘的“毛刺”踢除掉

    1️⃣膨胀过程 

    膨胀是求局部最大值的操作,核B与图形卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素,这样就会使图像中的高亮区域逐渐增长

    2️⃣腐蚀过程

    腐蚀可以理解为B的中心(锚点)沿着A的内边界走了一圈。腐蚀也是对高亮部分而言,A区域之外的部分 < A的高亮像素,所里里面被外面取代

    💻开运算、闭运算

    1️⃣开运算:先腐蚀再膨胀,用来消除小物体 

    2️⃣闭运算: 先膨胀再腐蚀,用于排除小型黑洞

    二、案例实现

    Step1:灰度处理

    • 将传入的两帧先进行处理,先将其转化成RGB类型图片再转化为灰度图 
    1. cvtColor(frontFrame,frontGray,CV_BGR2GRAY);//前一帧灰度处理
    2. cvtColor(afterFrame,afterGray,CV_BGR2GRAY);//后一帧灰度处理

    Step2:对视频进行帧差处理

    • 将两帧图片进行帧差处理,将对比结果存储在diff中
    1. //【帧差法】对比两帧图像之间差异,捕获运动物体
    2. //缺点:所有运动的物体都会展现
    3. Mat diff;
    4. absdiff(frontGray,afterGray,diff);//前后两帧对比存在diff中
    • 灰度图 + 帧差处理后,效果如下:

    Step3:二值化处理

    • 我们可以看到,公交车的识别区块并不是很明显,因此,接下来我们对视频进行二值化处理
    1. //【二值化】黑白分明
    2. //局部阈值
    3. threshold(diff,diff,25,255,CV_THRESH_BINARY);
    • 黑白更加分明,效果如下:

    Step4:腐蚀处理

    • 我们会发现,二值化处理后,比原来多出好多的白色的小点,这时候我们就需要进行腐蚀处理,腐蚀掉方块大小的像素,这里设置了4*4,来清除大部分噪点 
    1. //【腐蚀处理】将背景中的白色噪点尽可能去除 降噪处理
    2. Mat element = cv::getStructuringElement(MORPH_RECT,Size(4,4));//小于4*4方块的白色噪点都会被腐蚀
    3. erode(diff,diff,element);
    • 腐蚀处理之后,效果如下:

    Step5:膨胀处理 

    • 噪点相较于之前确实少了很多,但是运动的物体也被腐蚀掉了很多,可能会识别不到一些移动车辆,这里我们继续进行膨胀处理,将我们的目标像素图像变“胖”
    1. //【膨胀处理】将白色区域扩大,更加明显,利于目标识别
    2. Mat element2=cv::getStructuringElement(MORPH_RECT,Size(30,30));
    3. dilate(diff,diff,element2);
    • 膨胀处理后,效果如下:

    Step6:标记、框选目标

    • 最后,将我们的目标像素图像进行标记,并且加一个框把移动的物体框选出来
    1. //动态物体的位置进行标记
    2. vector>contours;
    3. findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
    4. //提取关键点
    5. vector>contours_poly(contours.size());
    6. vectorboundRect(contours.size());
    7. //确定四个点来进行框住目标物体
    8. int x,y,w,h;
    9. int num=contours.size();
    10. for(int i = 0;i < num;i++)
    11. {
    12. approxPolyDP(Mat(contours[i]),contours_poly[i],3,true);
    13. boundRect[i]=boundingRect(Mat(contours_poly[i]));
    14. x=boundRect[i].x;
    15. y=boundRect[i].y;
    16. w=boundRect[i].width;
    17. h=boundRect[i].height;
    18. //绘制矩形
    19. rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(255,0,0),2);//Scalar颜色
    20. }
    • 完成上述所有步骤后,效果如下: 

    💡完整代码

    1. #include
    2. #include
    3. using namespace std;
    4. using namespace cv;
    5. Mat MoveCheck(Mat &frontFrame,Mat &afterFrame)
    6. {
    7. Mat frontGray,afterGray;//前后灰度处理
    8. Mat resFrame = afterFrame.clone();
    9. //【灰度处理】
    10. cvtColor(frontFrame,frontGray,CV_BGR2GRAY);//前一帧灰度处理
    11. cvtColor(afterFrame,afterGray,CV_BGR2GRAY);//后一帧灰度处理
    12. //【帧差法】对比两帧图像之间差异,捕获运动物体
    13. //缺点:所有运动的物体都会展现
    14. Mat diff;
    15. absdiff(frontGray,afterGray,diff);//前后两帧对比存在diff中
    16. //imshow("diff",diff);
    17. //【二值化】黑白分明
    18. //局部阈值
    19. threshold(diff,diff,25,255,CV_THRESH_BINARY);
    20. //imshow("threshold",diff);
    21. //【腐蚀处理】将背景中的白色噪点尽可能去除 降噪处理
    22. Mat element = cv::getStructuringElement(MORPH_RECT,Size(4,4));//小于4*4方块的白色噪点都会被腐蚀
    23. erode(diff,diff,element);
    24. //imshow("erode",diff);
    25. //【膨胀处理】将白色区域扩大,更加明显,利于目标识别
    26. Mat element2=cv::getStructuringElement(MORPH_RECT,Size(30,30));
    27. dilate(diff,diff,element2);
    28. //imshow("dilate",diff);
    29. //开运算:先腐蚀后膨胀,去掉高亮物体背景中白色的噪点,凸显高亮物体
    30. //闭运算:先膨胀后腐蚀,去掉高亮物体内部的黑色小坑洞,凸显高亮物体
    31. //动态物体的位置进行标记
    32. vector>contours;
    33. findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
    34. //提取关键点
    35. vector>contours_poly(contours.size());
    36. vectorboundRect(contours.size());
    37. //确定四个点来进行框住目标物体
    38. int x,y,w,h;
    39. int num=contours.size();
    40. for(int i = 0;i < num;i++)
    41. {
    42. approxPolyDP(Mat(contours[i]),contours_poly[i],3,true);
    43. boundRect[i]=boundingRect(Mat(contours_poly[i]));
    44. x=boundRect[i].x;
    45. y=boundRect[i].y;
    46. w=boundRect[i].width;
    47. h=boundRect[i].height;
    48. //绘制矩形
    49. rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(255,0,0),2);//Scalar颜色
    50. }
    51. return resFrame;
    52. }
    53. int main(int argc, char *argv[])
    54. {
    55. Mat frame;
    56. Mat temp;
    57. Mat res;
    58. int count = 0;
    59. VideoCapture cap("C:/Users/86177/Desktop/image/carMove.mp4");//视频路径
    60. while(cap.read(frame))
    61. {
    62. count++;
    63. if(count == 1)
    64. {
    65. res = MoveCheck(frame,frame);
    66. }
    67. else
    68. {
    69. res = MoveCheck(temp,frame);
    70. }
    71. temp = frame.clone();
    72. imshow("frame",frame);
    73. imshow("res",res);
    74. waitKey(25);//延时
    75. }
    76. return 0;
    77. }

    三、总结

    • 本文主要讲解了OpenCV图像处理基本的原理,包括帧差法二值化膨胀腐蚀开运算闭运算
    • 以车辆识别为例子,详细讲解了图像处理相关操作,在各个步骤是怎么样的一个效果
    • 车辆识别在我们日常生活中非常常见,是一个很经典的案例,本案例算是初步实现,但是,通过案例也发现,帧差法的缺点显而易见,测试视频存在很多干扰,比如说其他移动的物体,例如,风比较大,树叶跟着动,我们的框选位置就会受到干扰,不一定是我们预期想要的目标,接下来也会继续对这方面进行深入探究和学习,争取做到更好!

    以上就是本文的全部内容啦!如果对您有帮助,麻烦点赞啦!收藏啦!欢迎各位评论区留言!!!

  • 相关阅读:
    第三部分—数据结构与算法基础_2. 线性表
    SQL Server 2022 安装步骤——SQL Server设置身份验证教程
    8.Tornado_RequestHandler功能函数
    2311rust到20版本更新
    正则表达式
    NIO-Socket实现简易聊天室
    手撸mybatis03: xml配置的解析与注册
    C++ atomic 和 memory ordering
    【2022.12.06】备战春招Day1——每日一题 + 49.字母异位词分组
    C#winform门诊医生系统+sqlserver
  • 原文地址:https://blog.csdn.net/m0_61745661/article/details/125684478