在视频中识别夜间车辆的好方法

时间:2018-07-02 04:48:55

标签: python opencv object-detection contour feature-extraction

我正试图在视频中识别夜间的汽车轮廓( Video Link 是链接,您可以从 HERE 下载) )。我知道基于R-CNN或YOLO的object detection可以完成这项工作。但是,我想要更简单,更快的方法,因为我想要的是实时识别行驶中的汽车。 (而且我没有像样的GPU。)我可以使用背景subtruction方法来找到汽车的轮廓,在白天表现得很好enter image description here

因为白天的光照条件相当稳定,所以前额罩中的大轮廓几乎是所有汽车。通过设置轮廓大小的阈值,我可以轻松获得汽车的轮廓。 但是,由于汽车的灯光,夜晚的事情却大不相同且复杂。参见下面的图片:

enter image description here

enter image description here

地面上的灯光与背景的对比度也很高,因此它们也是前景蒙版中的轮廓。为了放下这些灯光,我试图找到灯光轮廓和汽车轮廓之间的差异。到目前为止,我已经提取了轮廓的区域,质心,周长,凸度,高和边界矩形的宽度作为评估的特征。这是代码:

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')

但是,我发现在灯光和汽车之间提取的功能没有太大差异。地面上的一些大灯光可以通过 area (区域)和 preimeter 来区分,但是仍然很难区分小灯光。有人可以给我一些指示吗?也许一些更有价值的功能或另一种不同的方法?

编辑:

感谢@ZdaR的建议。这使我考虑使用cv2.cvtColor将框架图像切换为另一个颜色空间。这样做的原因是使前灯本身地面上的灯光之间的颜色差异更加明显,以便我们可以更精确地检测前灯。切换色彩空间后查看差异:

原点(地面上的光的颜色类似于车灯本身):

enter image description here

切换后(一个变为蓝色,另一个变为红色):

enter image description here

所以我现在正在做的是

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

我可以用前灯(还有一些噪音)得到这个前景面具:

enter image description here

基于此步骤,我可以非常准确地检测到汽车的前大灯并将光投射到地面上

enter image description here

但是,我仍然不知道如何根据这些前灯识别汽车。

0 个答案:

没有答案