Я пытаюсь определить автомобильные контуры ночью в видео ( Ссылка на видео - это ссылка, и вы можете скачать ее с ЗДЕСЬ ). Я знаю, что object detection
на основе R-CNN или YOLO может сделать эту работу. Однако я хочу что-то более простое и более быстрое, потому что все, что я хочу, - это идентифицировать движущиеся автомобили в режиме реального времени . (И у меня нет приличного графического процессора.) Я могу сделать это довольно хорошо в дневное время , используя метод фонового вычитания, чтобы найти контуры автомобилей:
Поскольку условия освещения в дневное время довольно стабильны, большие контуры в передней маске есть почти у всех автомобилей. Установив порог размера контуров, я могу легко получить контуры автомобилей.
Однако в ночное время все сильно отличается и усложняется, главным образом, из-за огней автомобилей . Смотрите фотографии ниже:
Огни на земле также имеют высокую контрастность с фоном, поэтому они также являются контурами в маске переднего плана. Чтобы отбросить эти огни, я пытаюсь найти различия между контурами света и контурами автомобиля . На данный момент я извлек площадь контура , центр тяжести, периметр, выпуклость, высоту и ширину ограничивающего прямоугольника в качестве элементов для оценки. Вот код:
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 , но все еще трудно отличить маленькие источники света. Может ли кто-нибудь дать мне некоторые инструкции по этому поводу? Может быть, есть более ценные функции или другой метод?
Edit:
Спасибо за совет @ 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
И я могу получить эту маску переднего плана с фарами (и немного шума тоже):
Основываясь на этом шаге, я могу довольно точно определить фары автомобилей и выбросить свет на землю:
Однако я до сих пор не знаю, как определить автомобиль по этим фарам.