python - 在视频中识别夜间汽车的好方法
问题描述
我正在尝试在视频中识别夜间汽车轮廓(视频链接是链接,您可以从这里下载)。我知道object detection
基于 R-CNN 或 YOLO 可以完成这项工作。但是,我想要更简单、更快速的东西,因为我想要的只是实时识别移动的汽车。(而且我没有像样的 GPU。)我可以在白天使用背景减法来找到汽车的轮廓。
因为白天的光照条件比较稳定,所以前罩的大轮廓几乎都是汽车。通过设置轮廓大小的阈值,我可以轻松获得汽车的轮廓。然而,晚上的情况却大不相同,而且很复杂,主要是因为汽车的灯光。请看下面的图片:
地面上的灯光也与背景具有高对比度,因此它们也是前景蒙版中的轮廓。为了放下那些灯,我试图找出 light contours 和 car contours 之间的区别。到目前为止,我已经提取了边界矩形的轮廓面积、质心、周长、凸度、高度和宽度作为评估的特征。这是代码:
import cv2
import numpy as np
import random
random.seed(100)
# ===============================================
# get video
video = "night_save.avi"
cap = cv2.VideoCapture(video)
# fg bg subtract model (MOG2)
fgbg = cv2.createBackgroundSubtractorMOG2(history=500, detectShadows=True) # filter model detec gery shadows for removing
# for writing video:
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('night_output.avi',fourcc,20.0,(704,576))
#==============================================
frameID = 0
contours_info = []
# main loop:
while True:
#============================================
ret, frame = cap.read()
if ret:
#====================== get and filter foreground mask ================
original_frame = frame.copy()
fgmask = fgbg.apply(frame)
#==================================================================
# filter kernel for denoising:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2))
# Fill any small holes
closing = cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, kernel)
# Remove noise
opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, kernel)
# Dilate to merge adjacent blobs
dilation = cv2.dilate(opening, kernel, iterations = 2)
# threshold (remove grey shadows)
dilation[dilation < 240] = 0
#=========================== contours ======================
im, contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# extract every contour and its information:
for cID, contour in enumerate(contours):
M = cv2.moments(contour)
# neglect small contours:
if M['m00'] < 400:
continue
# centroid
c_centroid = int(M['m10']/M['m00']), int(M['m01']/M['m00'])
# area
c_area = M['m00']
# perimeter
try:
c_perimeter = cv2.arcLength(contour, True)
except:
c_perimeter = cv2.arcLength(contour, False)
# convexity
c_convexity = cv2.isContourConvex(contour)
# boundingRect
(x, y, w, h) = cv2.boundingRect(contour)
# br centroid
br_centroid = (x + int(w/2), y + int(h/2))
# draw rect for each contour:
cv2.rectangle(original_frame,(x,y),(x+w,y+h),(0,255,0),2)
# draw id:
cv2.putText(original_frame, str(cID), (x+w,y+h), cv2.FONT_HERSHEY_PLAIN, 3, (127, 255, 255), 1)
# save contour info
contours_info.append([cID,frameID,c_centroid,br_centroid,c_area,c_perimeter,c_convexity,w,h])
#======================= show processed frame img ============================
cv2.imshow('fg',dilation)
cv2.imshow('origin',original_frame)
# save frame image:
cv2.imwrite('pics/{}.png'.format(str(frameID)), original_frame)
cv2.imwrite('pics/fb-{}.png'.format(str(frameID)), dilation)
frameID += 1
k = cv2.waitKey(30) & 0xff
if k == 27:
cap.release()
cv2.destroyAllWindows()
break
else:
break
#==========================save contour_info=========================
import pandas as pd
pd = pd.DataFrame(contours_info, columns = ['ID','frame','c_centroid','br_centroid','area','perimeter','convexity','width','height'])
pd.to_csv('contours.csv')
但是,我没有看到我在灯光和汽车之间提取的特征有太大区别。地面上的一些大灯可以根据面积和周长而有所不同,但仍然很难区分小灯。有人可以给我一些指示吗?也许一些更有价值的功能或另一种不同的方法?
编辑:
感谢@ZdaR 的建议。它让我考虑使用cv2.cvtColor
将帧图像切换到另一个颜色空间。这样做的原因是为了让大灯本身和地面上的光之间的色差更加明显,这样我们就可以更准确地检测大灯。切换色彩空间后查看差异:
ORIGIN(地面灯光颜色与车灯本身相似):
切换后(一个变为蓝色,另一个变为红色):
所以我现在正在做的是
1.切换色彩空间;
2.用一定的滤色片过滤切换的框架(滤除蓝色,黄色,保留红色,只保留汽车大灯。)
3.将过滤后的帧输入到背景减法模型中,得到前景蒙版,然后进行膨胀。
这是执行此操作的代码:
ret, frame = cap.read()
if ret:
#====================== switch and filter ================
col_switch = cv2.cvtColor(frame, 70)
lower = np.array([0,0,0])
upper = np.array([40,10,255])
mask = cv2.inRange(col_switch, lower, upper)
res = cv2.bitwise_and(col_switch,col_switch, mask= mask)
#======================== get foreground mask=====================
fgmask = fgbg.apply(res)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2))
# Dilate to merge adjacent blobs
d_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
dilation = cv2.dilate(fgmask, d_kernel, iterations = 2)
dilation[dilation < 255] = 0
我可以得到这个带有前灯的前景蒙版(还有一些噪音):
基于这一步,我可以非常准确地检测到汽车的前灯并在地面上熄灭灯光:
但是,我仍然不知道如何根据这些大灯来识别汽车。
解决方案
推荐阅读
- python - 根据另一个 numpy 数组中的值查找 numpy 数组的索引
- mysql - 避免 SELECT 和 UPDATE 查询的损坏数据以及两者之间的长时间运行的任务
- javascript - 如何使用 d3 zoomBehavior 检测用户的平移和缩放?
- mysql - 在长查询中转换为系统时间
- ibm-mq - 使用 IBM MQ 配置连接节点 js 应用程序
- typescript - 我可以在 {...} 中导入 ES5 导出的函数吗
- mongodb - 如何使用 MongoDB 聚合的结果?
- powershell - 是否可以将 Send-MailMessage 与默认凭据一起使用?
- mysql - 使用 Scala 从一个平台查询另一个平台
- python - 我如何计算我在递归中划分了多少次?