【OpenCV】车辆识别 C++ OpenCV 原理介绍 + 案例实现
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
前言
本文主要以车辆识别为目标利用 C++语言 结合 Qt + OpenCV 进行图像处理相关步骤的讲解
一、图像处理
💻二值化处理
二值化是通过遍历灰度图中点将图像信息二值化处理处理过后的图片只有黑白两种色值
📍作用
- 图像的二值化就是将图像上的像素点的灰度值设置为0或255这样将使整个图像呈现出明显的黑白效果
- 在数字图像处理中二值图像占有非常重要的地位图像的二值化使图像中数据量大为减少从而能凸显出目标的轮廓
📍全局阈值
函数threshold
参数
参数1InputArray类型的src输入数组填单通道 , 8或32位浮点类型的Mat即可
参数2OutputArray类型的dst函数调用后的运算结果存在这里即这个参数用于存放输出结果且和第一个参数中的Mat变量有一样的尺寸和类型
参数3double类型的thresh阈值的具体值
参数4double类型的maxval当第5个参数阈值类型type取 THRESH_BINARY 或THRESH_BINARY_INV阈值类型时的最大值
参数5int类型的type取阀值的算法
📍局部阈值
函数adaptiveThreshold
参数
参数1InputArray类型的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类型图片再转化为灰度图
cvtColor(frontFrame,frontGray,CV_BGR2GRAY);//前一帧灰度处理
cvtColor(afterFrame,afterGray,CV_BGR2GRAY);//后一帧灰度处理
Step2对视频进行帧差处理
- 将两帧图片进行帧差处理将对比结果存储在diff中
//【帧差法】对比两帧图像之间差异捕获运动物体
//缺点:所有运动的物体都会展现
Mat diff;
absdiff(frontGray,afterGray,diff);//前后两帧对比存在diff中
- 灰度图 + 帧差处理后效果如下
Step3二值化处理
- 我们可以看到公交车的识别区块并不是很明显因此接下来我们对视频进行二值化处理
//【二值化】黑白分明
//局部阈值
threshold(diff,diff,25,255,CV_THRESH_BINARY);
- 黑白更加分明效果如下
Step4腐蚀处理
- 我们会发现二值化处理后比原来多出好多的白色的小点这时候我们就需要进行腐蚀处理腐蚀掉<x*x方块大小的像素这里设置了4*4来清除大部分噪点
//【腐蚀处理】将背景中的白色噪点尽可能去除 降噪处理
Mat element = cv::getStructuringElement(MORPH_RECT,Size(4,4));//小于4*4方块的白色噪点都会被腐蚀
erode(diff,diff,element);
- 腐蚀处理之后效果如下
Step5膨胀处理
- 噪点相较于之前确实少了很多但是运动的物体也被腐蚀掉了很多可能会识别不到一些移动车辆这里我们继续进行膨胀处理将我们的目标像素图像变“胖”
//【膨胀处理】将白色区域扩大,更加明显利于目标识别
Mat element2=cv::getStructuringElement(MORPH_RECT,Size(30,30));
dilate(diff,diff,element2);
- 膨胀处理后效果如下
Step6标记、框选目标
- 最后将我们的目标像素图像进行标记并且加一个框把移动的物体框选出来
//动态物体的位置进行标记
vector<vector<Point>>contours;
findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
//提取关键点
vector<vector<Point>>contours_poly(contours.size());
vector<Rect>boundRect(contours.size());
//确定四个点来进行框住目标物体
int x,y,w,h;
int num=contours.size();
for(int i = 0;i < num;i++)
{
approxPolyDP(Mat(contours[i]),contours_poly[i],3,true);
boundRect[i]=boundingRect(Mat(contours_poly[i]));
x=boundRect[i].x;
y=boundRect[i].y;
w=boundRect[i].width;
h=boundRect[i].height;
//绘制矩形
rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(255,0,0),2);//Scalar颜色
}
- 完成上述所有步骤后效果如下
💡完整代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat MoveCheck(Mat &frontFrame,Mat &afterFrame)
{
Mat frontGray,afterGray;//前后灰度处理
Mat resFrame = afterFrame.clone();
//【灰度处理】
cvtColor(frontFrame,frontGray,CV_BGR2GRAY);//前一帧灰度处理
cvtColor(afterFrame,afterGray,CV_BGR2GRAY);//后一帧灰度处理
//【帧差法】对比两帧图像之间差异捕获运动物体
//缺点:所有运动的物体都会展现
Mat diff;
absdiff(frontGray,afterGray,diff);//前后两帧对比存在diff中
//imshow("diff",diff);
//【二值化】黑白分明
//局部阈值
threshold(diff,diff,25,255,CV_THRESH_BINARY);
//imshow("threshold",diff);
//【腐蚀处理】将背景中的白色噪点尽可能去除 降噪处理
Mat element = cv::getStructuringElement(MORPH_RECT,Size(4,4));//小于4*4方块的白色噪点都会被腐蚀
erode(diff,diff,element);
//imshow("erode",diff);
//【膨胀处理】将白色区域扩大,更加明显利于目标识别
Mat element2=cv::getStructuringElement(MORPH_RECT,Size(30,30));
dilate(diff,diff,element2);
//imshow("dilate",diff);
//开运算:先腐蚀后膨胀去掉高亮物体背景中白色的噪点凸显高亮物体
//闭运算:先膨胀后腐蚀去掉高亮物体内部的黑色小坑洞凸显高亮物体
//动态物体的位置进行标记
vector<vector<Point>>contours;
findContours(diff,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
//提取关键点
vector<vector<Point>>contours_poly(contours.size());
vector<Rect>boundRect(contours.size());
//确定四个点来进行框住目标物体
int x,y,w,h;
int num=contours.size();
for(int i = 0;i < num;i++)
{
approxPolyDP(Mat(contours[i]),contours_poly[i],3,true);
boundRect[i]=boundingRect(Mat(contours_poly[i]));
x=boundRect[i].x;
y=boundRect[i].y;
w=boundRect[i].width;
h=boundRect[i].height;
//绘制矩形
rectangle(resFrame,Point(x,y),Point(x+w,y+h),Scalar(255,0,0),2);//Scalar颜色
}
return resFrame;
}
int main(int argc, char *argv[])
{
Mat frame;
Mat temp;
Mat res;
int count = 0;
VideoCapture cap("C:/Users/86177/Desktop/image/carMove.mp4");//视频路径
while(cap.read(frame))
{
count++;
if(count == 1)
{
res = MoveCheck(frame,frame);
}
else
{
res = MoveCheck(temp,frame);
}
temp = frame.clone();
imshow("frame",frame);
imshow("res",res);
waitKey(25);//延时
}
return 0;
}
三、总结
- 本文主要讲解了OpenCV图像处理基本的原理包括帧差法、二值化、膨胀腐蚀、开运算、闭运算
- 以车辆识别为例子详细讲解了图像处理相关操作在各个步骤是怎么样的一个效果
- 车辆识别在我们日常生活中非常常见是一个很经典的案例本案例算是初步实现但是通过案例也发现帧差法的缺点显而易见测试视频存在很多干扰比如说其他移动的物体例如风比较大树叶跟着动我们的框选位置就会受到干扰不一定是我们预期想要的目标接下来也会继续对这方面进行深入探究和学习争取做到更好
以上就是本文的全部内容啦如果对您有帮助麻烦点赞啦收藏啦欢迎各位评论区留言