本期教程我们将和小伙伴们一起研究如何使用计算机视觉和图像处理技术来检测汽车在行驶中时汽车是否在改变车道!大家一定听说过使用 OpenCV 的 haar 级联文件可以检测到面部、眼睛等,但是如果目标是汽车,公共汽车呢?
01. 数据集
我们将道路上汽车的视频文件用作数据集。当然可以使用图像数据集检测来汽车,但是由于汽车在变道时我们需要通过弹出窗口提供警报,因此对于这些动态情况,视频输入更为可行。
02. 输入
第一步是提供要在本教程中使用的输入 - OpenCV 的 haar 级联文件,用于检测汽车的坐标,道路上的汽车的视频文件 -
cascade_src = 'cascade/cars.xml'video_src = 'dataset/cars.mp4'
cap = cv2.VideoCapture(video_src)car_cascade = cv2.CascadeClassifier(cascade_src)
cv2.VideoCapture()方法用于捕获输入视频,视频通常为每秒 25 个图像 / 帧(fps)。捕获输入后,使用循环提取帧,并使用汽车的 haar 级联文件检测到的坐标,我们在循环中在汽车周围绘制一个矩形,以在对捕获的帧执行其他操作时获得一致性。
while(1):# Take each frame _, frame = cap.read() cars = car_cascade.detectMultiScale(frame, 1.1, 1)for (x,y,w,h) in cars: roi = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),2) #ROI is region of interest
在 OpenCV 中,使用 BGR 而不是 RGB,因此(0,0,255)将在汽车上绘制一个红色矩形,而不是蓝色。
03. 图像处理
如果帧的分辨率很高,则会减慢执行的操作,此外,该帧还包含噪声,可以使用模糊降低噪声,这里使用高斯模糊。
3.1 HSV 框架
在此,我们使用从 cv2.VideoCapture()捕获的帧中获得的 HSV 帧仅突出显示汽车转弯的点,并遮挡其余道路和在道路上直行的汽车。设置上限和下限阈值是为了定义 HSV 中的颜色范围,以查看汽车改变车道的点,并用作框架的遮罩。以下是用于获取此代码的代码段 -
#canceling noise in the video frames using blurframe = cv2.GaussianBlur(frame,(21,21),0) # Convert BGR to HSVhsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # define range of color in HSV to see the points at which the car is changing angleslower_limit = np.array([0,150,150])upper_limit = np.array([10,255,255]) # Threshold the HSV image to get only the thresholded colorsmask = cv2.inRange(hsv, lower_limit, upper_limit)
3.2 腐蚀与膨胀
腐蚀和膨胀是图像处理中常使用的两个基本形态学操作。腐蚀算子在内核区域上具有局部最小值的作用。腐蚀用于减少图像中的斑点噪声,斑点会从图像中的对象边界腐蚀掉。膨胀具有局部最大值运算符的作用。当添加像素以平滑图像中对象的边界时,将使用膨胀来重新获得一些丢失的区域。现在,通过基本形态学操作(腐蚀和膨胀)处理从 HSV 帧的第一步生成的蒙版。通过将帧和掩码之间的按位与运算应用于获取 ROI(感兴趣区域),可以生成结果帧。
kernel = np.ones((3,3),np.uint8) kernel_lg = np.ones((15,15),np.uint8) # image processing technique called the erosion is used for noise reduction mask = cv2.erode(mask,kernel,iterations = 1) # image processing technique called the dilation is used to regain some lost area mask = cv2.dilate(mask,kernel_lg,iterations = 1) # Bitwise-AND to get black everywhere else except the region of interest result = cv2.bitwise_and(frame,frame, mask= mask)
3.3 车道检测
canny 边缘检测器与霍夫线变换一起用于检测车道。
canny 边缘检测(作者提供的图像)
04. 边缘检测
诸如 canny 边缘检测器之类的算法用于查找将图像中的边缘像素,但是由于我们无法融合某些点和边缘,因此它无法找到实际对象,在这里我们可以使用 OpenCV 中的 cv2.findContours()实现轮廓的查找。
定义 -“轮廓是代表图像中曲线的点的列表。” 等高线由序列表示(序列是结构的链表),每个序列都编码有关下一点位置的信息。我们在 ROI 中多次运行 cv2.findContours()以获得实体,然后使用 cv2.drawContours()绘制轮廓区域。等高线可以是点,边,多边形等,因此在绘制等高线时,我们进行多边形近似,以找到边的长度和区域的面积。函数 cv2.drawContours()的工作方式是从根节点开始绘制一棵树(数据结构),然后将后续点,边界框和 freeman 链代码连接在一起。
找到轮廓后的另一个重要任务是匹配它们。轮廓匹配意味着我们有两个单独的计算轮廓相互比较,或者轮廓与抽象模板相比较。
thresh = maskcontours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)# define a minimum area for a contour (ignoring all values below min)min_area = 1000cont_filtered = []# filter out all contours below a min_areafor cont in contours: if cv2.contourArea(cont) > min_area: cont_filtered.append(cont)
cnt = cont_filtered[0]# draw the rectangles around contoursrect = cv2.minAreaRect(cnt)box = cv2.boxPoints(rect)box = np.int0(box)cv2.drawContours(frame,[box],0,(0,0,255),2)rows,cols = thresh.shape[:2][vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)lefty = int((-x*vy/vx) + y)righty = int(((cols-x)*vy/vx)+y)cv2.line(frame,(cols-1,righty),(0,lefty),(0,255,0),2)
05. 中心矩
我们可以通过计算轮廓矩来比较两个轮廓。“中心矩是通过将轮廓的所有像素相加而得出的轮廓的总体特征。”
中心矩型 -
- 空间矩: m00,m10,m01,m20,m11,m02,m30,m21,m12,m03。
- 中心矩: mu20,mu11,mu02,mu30,mu21,mu12,mu03。
- Hu 矩:有七个 Hu 矩(h0 — h6)或(h1 — h7),两种表示法都使用。
我们使用 cv2.fitEllipse()计算矩并将椭圆拟合在这些点上。从轮廓和力矩中得出角度,因为改变车道需要 45 度旋转,这被认为是汽车转弯角度的阈值。
现在,我们不仅可以打印检测变化的车道,还可以使用 Tkinter 作为一个简单的弹出窗口来提醒更改。
使用 Greenline 测量角度,并在框架中的汽车上绘制矩形
弹出警报(作者提供的图片)
输出
06. 总结
在本教程中,使用车道变更检测方法探索了智能汽车导航的小型演示。计算机视觉正在迅速发展,其应用不仅在汽车的本地导航中而且在火星导航和产品检查领域中也在不断发展,甚至医疗应用也正在开发中,并可以在早期用于检测 X 射线图像中的癌症和肿瘤阶段。