视频截取下来的红绿灯图像流程图
代码部分:
import cv2 as cv
import numpy as np
capture = cv.VideoCapture("*/红绿灯.mp4") # 读取视频
ret, frame = capture.read()
while ret:
# 是否读取到了帧,读取到了ret则为True
width, height = frame.shape[:2][::-1] # 获取宽高
img_resize = cv.resize(frame,
(int(width * 0.5), int(height * 0.5)),
interpolation=cv.INTER_CUBIC) # 通过上方获得的宽高更改视频显示尺寸,防止显示不全。
proimage0 = cv.cvtColor(img_resize, cv.COLOR_BGR2GRAY) # 转换为灰度图
ROI = proimage0[212:237, 289:350] # 总的感兴趣区域
RedRoi = ROI[3:, 2:19] # 红色感兴趣区域
YellowRoi = ROI[:, 19:32] # 黄色感兴趣区域
GreenRoi = ROI[:, 37:52] # 绿色感兴趣区域
在上图中我们可以看见整体的感兴趣区域和分别的三个感兴趣区域的灰度图,其中红灯的感兴趣区域我已经做了二值化处理,接下来引出接下来的步骤。
ret, RedFinnal = cv.threshold(RedRoi, 65, 255, cv.THRESH_BINARY) # 对所选择的灯进行阈值处理转换为二值图
kernel = np.ones((3, 3), np.uint8)
hld_dilate = cv.dilate(RedFinnal, kernel, iterations=1) # 对二值化后的图像进行膨胀处理
# 此处往下到显示图像前是获取二值图的白色像素点的数量
pictue_size = hld_dilate.shape
picture_height = pictue_size[0]
picture_width = pictue_size[1]
# print(picture_height, picture_width)
i = 0
for a in range(picture_height):
for b in range(picture_width):
if hld_dilate[a, b].all() > 0:
i = i + 1
print(i)
if i >= 202:
print("识别到了红灯")
在这一段代码里面我们对红灯进行了阈值处理转换为二值图片,然后进行膨胀处理增大白色像素数量,便于判断,最后则判断二值图片里面的白色像素的数量并且当白色像素大于一定数量的时候就输出识别到了红灯。
二值图片已经在上面展示出来了,这个是命令行的输出。
cv.imshow("ROI", ROI)
cv.imshow("hld_dilate", hld_dilate)
cv.imshow("RedFinnal", RedFinnal)
cv.imshow("RedRoi", RedRoi)
cv.imshow("YellowRoi", YellowRoi)
cv.imshow("GreenRoi", GreenRoi)
cv.imshow("video", img_resize)
ret, frame = capture.read()
# 若键盘按下q则退出播放
if cv.waitKey(20) & 0xff == ord('q'):
break
# 释放资源
capture.release()
# 关闭所有窗口
cv.destroyAllWindows()
完成上述部分已经算是完成了识别红绿灯的一半了,接下来我们要做的是同时识别红绿黄三个灯并且把识别结果返回到原视频当中。我的想法就是开个多线程同时监控三个灯。我们先把第二部分的代码封装成一个函数,传入值是某个灯的感兴趣区域和"某灯"。代码如下: 值得注意的是黄灯的白色像素点稍微偏低,所以说黄灯另外判断。
def zhuyao(IpRoi, OpL):
ret, Finnal = cv.threshold(IpRoi, 65, 255, cv.THRESH_BINARY) # 对所选择的灯进行阈值处理转换为二值图
kernel = np.ones((3, 3), np.uint8)
hld_dilate = cv.dilate(Finnal, kernel, iterations=1) # 对二值化后的图像进行膨胀处理
# 此处往下到显示图像前是获取二值图的白色像素点的数量
pictue_size = hld_dilate.shape # 获取图片的维度
picture_height = pictue_size[0] # 获取高
picture_width = pictue_size[1] # 获取宽
i = 0
for a in range(picture_height):
for b in range(picture_width):
if hld_dilate[a, b].all() > 0:
i = i + 1
print(i)
if IpRoi == "RedLight" and IpRoi == "GreenLight" and i >= 202:
print(OpL)
return OpL
elif i >= 150:
print(OpL)
return OpL
然后再开启三个线程分别判断红黄绿三个灯。代码如下:
class myThread(threading.Thread):
def __init__(self, RoiArea, op):
threading.Thread.__init__(self)
self.RoiArea = RoiArea
self.op = op
def run(self):
return zhuyao(self.RoiArea, self.op)
# 创建新线程
thread1 = myThread(RedRoi, "RedLight")
thread2 = myThread(YellowRoi, "YellowLight")
thread3 = myThread(GreenRoi, "GreenLight")
# 开启线程
thread1.start()
thread2.start()
thread3.start()
接下来开始画框,因为视频的红绿灯是固定位置的,所以就直接画框了
画框的x1,y1,x2,y2,在最上方的总体ROI中可以得出,然后值得注意的是OpenCv的putText函数好像不可以输出中文。
最终代码如下:
# coding:utf-8
import cv2 as cv
import numpy as np
import threading
def zhuyao(IpRoi, OpL):
ret, Finnal = cv.threshold(IpRoi, 65, 255, cv.THRESH_BINARY) # 对所选择的灯进行阈值处理转换为二值图
kernel = np.ones((3, 3), np.uint8)
hld_dilate = cv.dilate(Finnal, kernel, iterations=1) # 对二值化后的图像进行膨胀处理
# 此处往下到显示图像前是获取二值图的白色像素点的数量
pictue_size = hld_dilate.shape # 获取图片的维度
picture_height = pictue_size[0] # 获取高
picture_width = pictue_size[1] # 获取宽
i = 0
for a in range(picture_height):
for b in range(picture_width):
if hld_dilate[a, b].all() > 0:
i = i + 1
print(i)
if IpRoi == "RedLight" and IpRoi == "GreenLight" and i >= 202:
print(OpL)
return OpL
elif i >= 150:
print(OpL)
return OpL
if __name__ == "__main__":
capture = cv.VideoCapture("E:/QQ数据/465879238/FileRecv/红绿灯.mp4") # 读取视频
ret, frame = capture.read()
while ret:
# 是否读取到了帧,读取到了ret则为True
width, height = frame.shape[:2][::-1] # 获取宽高
img_resize = cv.resize(frame,
(int(width * 0.5), int(height * 0.5)),
interpolation=cv.INTER_CUBIC) # 通过上方获得的宽高更改视频显示尺寸,防止显示不全。
proimage0 = cv.cvtColor(img_resize, cv.COLOR_BGR2GRAY) # 转换为灰度图
ROI = proimage0[212:237, 289:350] # 总的感兴趣区域
RedRoi = ROI[3:, 2:19] # 红色感兴趣区域
YellowRoi = ROI[:, 19:32] # 黄色感兴趣区域
GreenRoi = ROI[:, 37:52] # 绿色感兴趣区域
class myThread(threading.Thread):
def __init__(self, RoiArea, op):
threading.Thread.__init__(self)
self.RoiArea = RoiArea
self.op = op
def run(self):
return zhuyao(self.RoiArea, self.op)
# 创建新线程
thread1 = myThread(RedRoi, "RedLight")
thread2 = myThread(YellowRoi, "YellowLight")
thread3 = myThread(GreenRoi, "GreenLight")
# 开启线程
thread1.start()
thread2.start()
thread3.start()
# 开始框图并且显示
# (x1,y1)
# o-------+
# | |
# +-------o
# (x2,y2)
x1 = 289
y1 = 210
x2 = 350
y2 = 237
# 颜色
color = (36, 255, 12)
text_color = (0, 0, 255)
text = ""
# 文字内容
if thread1.run() == "RedLight":
text = thread1.run()
elif thread2.run() == "YellowLight":
text = thread2.run()
elif thread3.run() == "GreenLight":
text = thread3.run()
# 加入方框
image = cv.rectangle(img_resize, (x1, y1), (x2, y2), color, 2)
# 计算文字的大小
(w, h), _ = cv.getTextSize(text, cv.FONT_HERSHEY_SIMPLEX, 0.6, 1)
# 加入文字背景区块
image = cv.rectangle(image, (x1, y1 - 20), (x1 + w, y1), color, -1)
# 加入文字
image = cv.putText(image, text, (x1, y1 - 5), cv.FONT_HERSHEY_SIMPLEX, 0.6, text_color, 1)
cv.imshow("video", img_resize)
ret, frame = capture.read()
# 若键盘按下q则退出播放
if cv.waitKey(20) & 0xff == ord('q'):
break
# 释放资源
capture.release()
# 关闭所有窗口
cv.destroyAllWindows()