计算机视觉-图像视觉实验-实验2

失败是坚忍的最后考验。——俾斯麦

一、实验目的

用OpenCV编写一个车辆计数程序,强化对课堂讲授内容如图像腐蚀、轮廓提取、边缘检测、视频读写等知识的深入理解和灵活应用。

二、实验要求

1、用OpenCV编写一个车辆计数程序,对一段视频里道路上的来往车辆进行计数统计,要求避免同一车辆重复统计,并尽量避免漏检、错检;

2、撰写实验报告,内容包括实验原理、实验过程、关键代码注释、实验结果解释以及实验分析。实验分析部分需要指出实验结果的优劣原因,并提出进一步提高实验性能的方法或手段。

3、使用Python版的OpenCV编写代码。

三、实验原理

本实验旨在使用OpenCV编写一个车辆计数程序,对一段视频中道路上的车辆进行计数统计。

  1. 视频读取和预处理:首先使用cv2.VideoCapture函数读取视频帧,然后将每一帧转换为灰度图像(cv2.cvtColor函数),以便进行后续处理。接下来,对图像进行高斯模糊(cv2.GaussianBlur函数),以去除噪声。
  2. 背景减除:通过创建一个背景减除器(cv2.createBackgroundSubtractorMOG2函数),可以根据当前帧和之前帧的差异来提取前景物体。使用该背景减除器对预处理后的图像进行处理,得到前景掩码。
  3. 形态学操作:使用形态学操作对前景掩码进行处理,以去除小斑块和噪声。首先进行腐蚀操作(cv2.erode函数),然后进行膨胀操作(cv2.dilate函数),以还原并放大前景物体。接着,进行闭操作(cv2.morphologyEx函数),以去除物体内部的小块。
  4. 轮廓提取:使用cv2.findContours函数从处理后的图像中提取轮廓。得到轮廓后,可以通过计算轮廓的边界矩形(cv2.boundingRect函数)来获取车辆的位置和大小。
  5. 车辆计数:对每个边界矩形进行宽度和高度的判断,以验证是否为有效的车辆。将有效的车辆用矩形框标记出来,并记录其中心点坐标。如果车辆的中心点通过预设的检测线(line_high)并且满足一定的偏移要求(offset),则将其计数为一辆车辆。最后,显示车辆计数结果和标记后的图像。

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import cv2
import numpy as np

min_w = 90
min_h = 90

#检测线的高度
line_high = 550

#线的偏移
offset = 7

#统计车的数量
carno =0

#存放有效车辆的数组
cars = []

def center(x, y, w, h):
x1 = int(w/2)
y1 = int(h/2)
cx = x + x1
cy = y + y1

return cx, cy

cap = cv2.VideoCapture('video.mp4')

bgsubmog =cv2.createBackgroundSubtractorMOG2()
#形态学kernel
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))

while True:
ret, frame = cap.read()
if(ret == True):

#灰度
cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#去噪(高斯)
blur = cv2.GaussianBlur(frame, (3,3), 5)
#去背影
mask = bgsubmog.apply(blur)

#腐蚀, 去掉图中小斑块
erode = cv2.erode(mask, kernel)

#膨胀, 还原放大
dilate = cv2.dilate(erode, kernel, iterations = 3)

#闭操作,去掉物体内部的小块
close = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel)
close = cv2.morphologyEx(close, cv2.MORPH_CLOSE, kernel)

cnts, h = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

#画一条检测线
cv2.line(frame, (10, line_high), (1200, line_high), (255, 255, 0), 3)

for (i, c) in enumerate(cnts):
(x,y,w,h) = cv2.boundingRect(c)

#对车辆的宽高进行判断
#以验证是否是有效的车辆
isValid = ( w >= min_w ) and ( h >= min_h)
if( not isValid):
continue

#到这里都是有效的车
cv2.rectangle(frame, (x, y), (x+w, y+h), (0,0,255), 2)
cpoint = center(x, y, w, h)
cars.append(cpoint)
cv2.circle(frame, (cpoint), 5, (0,0,255), -1)

for (x, y) in cars:
if( (y > line_high - offset) and (y < line_high + offset ) ):
carno +=1
cars.remove((x , y ))
print(carno)

cv2.putText(frame, "Cars Count:" + str(carno), (500, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (255,0,0), 5)
cv2.imshow('video', frame)
#cv2.imshow('erode', close)

key = cv2.waitKey(1)
if(key == 27):
break

cap.release()
cv2.destroyAllWindows()

四、实验结果

实验部分视频:

实验部分结果:

  1. 视频显示

视频应该会显示当前帧处理后的图像,其中车辆被红色矩形框标注,并且车辆中心点会用红点表示。

会有一条蓝绿色的线(检测线)在视频帧的 line_high 位置画出。

  1. 车辆计数

当车辆通过检测线时,carno 数字会增加,并且车辆通过的计数会在视频帧上的左上角显示,格式为"Cars Count: 数字"

每当有车辆通过检测线时,程序将在终端输出当前的车辆总数。

五、实验分析

  1. 背景减除的效果:

背景减除是用来分离前景(移动的车辆)和背景(静止的环境)的关键步骤。如果视频中的背景相对静止且车辆有足够的移动,bgsubmog 应能够有效地提取车辆作为前景。

如果视频中有树木摇晃、其他移动物体或者光照变化等动态背景因素,可能会造成误检。

  1. 车辆大小筛选:

通过设定阈值 min_w 和 min_h,代码筛选掉了小于这些尺寸的所有轮廓。这有助于减少噪声和非车辆物体的干扰,但如果有遮挡或车辆距离摄像机太远导致其看起来很小,这些车辆可能会被错误地排除。

  1. 形态学操作:

腐蚀和膨胀操作旨在清除噪点和填充车辆中的空隙。这些操作通常会提高轮廓检测的质量,但如果参数选择不当,可能导致车辆轮廓的过度腐蚀(变细)或相邻车辆的轮廓融合。

  1. 车辆计数逻辑:

车辆计数逻辑依赖于检测线和车辆中心点之间的关系。这个简单的方法适用于车流量不密集、车辆间隔明显的场景。在高密度交通或多车道情况下,可能需要更复杂的逻辑来避免重复计数或漏计。

  1. 程序的稳定性和性能:

检测和计数逻辑运行在一个无限循环中,这种方法适用于实时视频处理。但如果视频中有很多小物体或噪声,增加的计算负担可能导致性能问题,比如延迟或跳帧。

  1. 计数的准确性:

计数准确性取决于轮廓检测的质量和车辆通过检测线的判断准确性。如果轮廓检测出现误差或车辆中心点的计算不准确,可能会导致计数不准确。


计算机视觉-图像视觉实验-实验2
https://yelelalearn.github.io/2024/04/17/计算机视觉-图像视觉实验-实验2/
作者
Yelearn
发布于
2024年4月17日
更新于
2024年4月25日
许可协议