目录
一、使用步骤
1.引入库
2.读入数据
3.获取帧率
4.创建函数将鼠标在图片中点击的坐标储存
5.逐帧采集视频并显示一帧图片来选择roi区域
6.最后逐帧采集视频并且放入循环一帧一帧的判断感兴趣区域中亮起的灯是哪个
二.全部代码
总结
前言: 可以直接复制代码使用,只需要去全部代码那块复制全部代码,并且在使用步骤中第五点学会如何选取区域即可。
一、使用步骤
1.引入库
首先安装opencv:
然后引入库,代码如下:
import cv2
import numpy as np
2.读入数据
代码如下:
cor_x, cor_y = -1, -1
camera = cv2.VideoCapture('video.mp4') # 从文件读取视频,只需要修改成自己的视频路径即可进行测试
cor = np.array([[1, 1]]) # 初始值并无意义,只是为了能够使用np.row_stack函数
3.获取帧率
fps = camera.get(cv2.CAP_PROP_FPS) # 获取视频帧率
print('视频帧率:%d fps' % fps)
由于视频的帧率不一样,pycharm将视频运行完的时间也不一样。比如120fps的视频,pycharm可以用近乎于原视频播放完的时间来运行。
而24fps的视频,如果是一个20多秒的视频,pycharm只需要3秒多就能将整个视频播放完所以想要pycharm用原视频速度播放,就要利用time.sleep来限制pycharm的循环时间,达到看清运行过程中是否出现错误的情况。方法是用公式 1/fps 获取原视频一帧多少秒,然后将
cv.waitKey(1 / fps * 1000)
加入循环结束的代码让循环一次的间变成 (1/fps)秒
4.创建函数将鼠标在图片中点击的坐标储存
def MouseAction(event, x, y, flags, param):
# 创建回调函数 (event:指触发的阶跃信号,比如鼠标左键按下, x, y:指鼠标的实时坐标, flags:鼠标的保持信号,如鼠标保持按下
# param自己需要使用的参数状态
global cor_x, cor_y, cor # 将变量变为全局变量,使之在函数外也能用
if event == cv2.EVENT_LBUTTONDOWN:
cor_x, cor_y = x, y # 将鼠标点击的x,y坐标赋予全局变量cor_x, cor_y
cor_m = [cor_x, cor_y]
cor = np.row_stack((cor, cor_m)) # 将鼠标点击的x,y坐标进行矩阵合并,并赋予全局变量
elif event == cv2.EVENT_LBUTTONUP:
cv2.line(img, (cor_x, cor_y), (cor_x, cor_y), (255, 255, 0), 7)
# 当鼠标左键由按下变松开时在原地划线 从左到右分别是 (读入的图片, 开始坐标, 结束坐标, 颜色(b, g, r), 线条粗细)
5.逐帧采集视频并显示一帧图片来选择roi区域
grabbed, img = camera.read() # 逐帧采集视频流
img = cv2.resize(img, (1280, 720))
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):
if (isinstance(img, np.ndarray)): # 判断是否OpenCV图片类型
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 创建一个可以在给定图像上绘图的对象
draw = ImageDraw.Draw(img)
# 字体的格式
fontStyle = ImageFont.truetype(
"simsun.ttc", textSize, encoding="utf-8")
# 绘制文本
draw.text(position, text, textColor, font=fontStyle)
# 转换回OpenCV格式
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
img = cv2AddChineseText(img, "利用鼠标点击 左上,右下的顺序来框出整个红绿灯区域和黄灯灯芯区域", [20, 20], (255, 255, 0), 30)
cv2.namedWindow('Traffic light')
cv2.setMouseCallback('Traffic light', MouseAction) # 将回调函数与opencv绑定
# 显示视频画面,并手动在视频中选取整个红绿灯区域和黄灯区域
while True:
cv2.imshow("Traffic light", img)
k = cv2.waitKey(1) & 0xFF
if k == ord(' '): # 空格退出操作
break
cv2.destroyAllWindows() # 关闭页面
需要注意的是选取roi区域时,需要选取整个红绿灯区域,和红绿灯区域中的黄灯区域,
并且选择区域的方式是通过两个点来选取一个区域,按左上,右下来框出感兴趣区域
顺序和区域如下:
选择完后 按空格退出。
6.最后逐帧采集视频并且放入循环一帧一帧的判断感兴趣区域中亮起的灯是哪个
while True:
grabbed, frame = camera.read() # 逐帧采集视频流
if not grabbed:
break
frame = cv2.resize(frame, (1280, 720))
frame_data = np.array(frame) # 每一帧循环存入数组
box_data = frame_data[cor[1, 1]:cor[2, 1], cor[1, 0]:cor[2, 0]] # 取矩形目标区域
yellow_box = frame_data[cor[3, 1]:cor[4, 1], cor[3, 0]:cor[4, 0]]
yellow_max = np.max(yellow_box)
b, g, r = cv2.split(box_data) # 将截取的区域分割为b,g,r单通道颜色图片
max_r = np.max(r)
max_g = np.max(g)
if yellow_max >= 245: # 判断黄灯区域中发光值最大的像素点是不是大于245
choose_box = cv2.rectangle(frame, tuple(cor[1, :]), tuple(cor[2, :]), (0, 255, 255), 2)
cv2.putText(frame, "yellow", (cor[1, 0], cor[1, 1]), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 2) # 显示yellow文本信息
elif max_g >= 245:
choose_box = cv2.rectangle(frame, tuple(cor[1, :]), tuple(cor[2, :]), (0, 255, 0), 2)
cv2.putText(frame, "green", (cor[1, 0], cor[1, 1]), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2) # 显示green文本信息
elif max_r >= 245:
choose_box = cv2.rectangle(frame, tuple(cor[1, :]), tuple(cor[2, :]), (0, 0, 255), 2)
cv2.putText(frame, "red", (cor[1, 0], cor[1, 1]), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2) # 显示red文本信息
# time.sleep(0.141)
cv2.imshow('video', frame) # 显示采集到的视频流
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
camera.release()
cv2.destroyAllWindows()
二.全部代码
# 中华人民共和国
# 人民出版社
# 作者:gaiya
import cv2
import numpy as np
import time
from PIL import Image, ImageDraw, ImageFont
cor_x, cor_y = -1, -1
camera = cv2.VideoCapture('video.mp4') # 从文件读取视频,只需要修改成自己的视频路径即可进行测试
cor = np.array([[1, 1]]) # 初始值并无意义,只是为了能够使用np.row_stack函数
def MouseAction(event, x, y, flags, param):
# 创建回调函数 (event:指触发的阶跃信号,比如鼠标左键按下, x, y:指鼠标的实时坐标, flags:鼠标的保持信号,如鼠标保持按下
# param自己需要使用的参数状态
global cor_x, cor_y, cor # 将变量变为全局变量,使之在函数外也能用
if event == cv2.EVENT_LBUTTONDOWN:
cor_x, cor_y = x, y # 将鼠标点击的x,y坐标赋予全局变量cor_x, cor_y
cor_m = [cor_x, cor_y]
cor = np.row_stack((cor, cor_m)) # 将鼠标点击的x,y坐标进行矩阵合并,并赋予全局变量
elif event == cv2.EVENT_LBUTTONUP:
cv2.line(img, (cor_x, cor_y), (cor_x, cor_y), (255, 255, 0), 7)
# 当鼠标左键由按下变松开时在原地划线 从左到右分别是 (读入的图片, 开始坐标, 结束坐标, 颜色(b, g, r), 线条粗细)
grabbed, img = camera.read() # 逐帧采集视频流
img = cv2.resize(img, (1280, 720))
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):
if (isinstance(img, np.ndarray)): # 判断是否OpenCV图片类型
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 创建一个可以在给定图像上绘图的对象
draw = ImageDraw.Draw(img)
# 字体的格式
fontStyle = ImageFont.truetype(
"simsun.ttc", textSize, encoding="utf-8")
# 绘制文本
draw.text(position, text, textColor, font=fontStyle)
# 转换回OpenCV格式
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
img = cv2AddChineseText(img, "利用鼠标点击 左上,右下的顺序来框出整个红绿灯区域和黄灯灯芯区域", [20, 20], (255, 255, 0), 30)
cv2.namedWindow('Traffic light')
cv2.setMouseCallback('Traffic light', MouseAction) # 将回调函数与opencv绑定
# 显示视频画面,并在视频中选取整个红绿灯区域和黄灯区域
while True:
cv2.imshow("Traffic light", img)
k = cv2.waitKey(1) & 0xFF
if k == ord(' '): # 空格退出操作
break
cv2.destroyAllWindows() # 关闭页面
while True:
grabbed, frame = camera.read() # 逐帧采集视频流
if not grabbed:
break
frame = cv2.resize(frame, (1280, 720))
frame_data = np.array(frame) # 每一帧循环存入数组
box_data = frame_data[cor[1, 1]:cor[2, 1], cor[1, 0]:cor[2, 0]] # 取矩形目标区域
yellow_box = frame_data[cor[3, 1]:cor[4, 1], cor[3, 0]:cor[4, 0]]
yellow_max = np.max(yellow_box)
b, g, r = cv2.split(box_data) # 将截取的区域分割为b,g,r单通道颜色图片
max_r = np.max(r)
max_g = np.max(g)
if yellow_max >= 245: # 判断黄灯区域中发光值最大的像素点是不是大于245
choose_box = cv2.rectangle(frame, tuple(cor[1, :]), tuple(cor[2, :]), (0, 255, 255), 2)
cv2.putText(frame, "yellow", (cor[1, 0], cor[1, 1]), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 2) # 显示yellow文本信息
elif max_g >= 245:
choose_box = cv2.rectangle(frame, tuple(cor[1, :]), tuple(cor[2, :]), (0, 255, 0), 2)
cv2.putText(frame, "green", (cor[1, 0], cor[1, 1]), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2) # 显示green文本信息
elif max_r >= 245:
choose_box = cv2.rectangle(frame, tuple(cor[1, :]), tuple(cor[2, :]), (0, 0, 255), 2)
cv2.putText(frame, "red", (cor[1, 0], cor[1, 1]), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2) # 显示red文本信息
time.sleep(0.141)
cv2.imshow('video', frame) # 显示采集到的视频流
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
camera.release()
cv2.destroyAllWindows()
运行中可以按q退出运行
总结
利用cv.split()来获取b,g,r单通道的图时,红灯亮和黄灯亮的两种情况下,三个通道的图片的最大的像素值都差不多,所以无法区分红灯与黄灯。所以要框一块额外的区域来识别黄灯是否亮起,这种方式还是取巧了,因为不管是什么颜色亮只要黄灯区域亮起,就会输出黄色,即使区域亮起的是任意颜色的灯。