imlementacja sledzenia pojazdow i kierunku ich ruchu. Zliczanie przejezdzajacych pojazdow.
This commit is contained in:
parent
c7e7bd6c70
commit
50a90d23d6
BIN
data/video_1.avi
BIN
data/video_1.avi
Binary file not shown.
BIN
data/video_2.mp4
Normal file
BIN
data/video_2.mp4
Normal file
Binary file not shown.
239
main.py
239
main.py
@ -1,68 +1,199 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import vehicles
|
||||
import time
|
||||
|
||||
input_video = 'data/video_1.avi'
|
||||
size = 1.0 #wielkosc obrazu
|
||||
|
||||
cap = cv2.VideoCapture(input_video)
|
||||
height, width, frames_count, fps = cap.get(cv2.CAP_PROP_FRAME_HEIGHT), cap.get(
|
||||
cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_COUNT), cap.get(cv2.CAP_PROP_FPS),
|
||||
|
||||
height = int(height)
|
||||
width = int(width)
|
||||
print(height, width, frames_count, fps)
|
||||
|
||||
sub = cv2.createBackgroundSubtractorMOG2() # utworz background subtractor
|
||||
counter_up=0 #licznik pojazdow jadacych w gore
|
||||
counter_down=0 #licznik pojazdow jadacych w dol
|
||||
|
||||
while True:
|
||||
user_choice = input("Wybierz nagranie:\n1. video_1.mp4\n2. video_2.avi\n")
|
||||
if user_choice == "1":
|
||||
input_video = 'data/video_1.avi'
|
||||
vid_name = 'video_1'
|
||||
kernelSize = 6
|
||||
break
|
||||
elif user_choice == "2":
|
||||
input_video = 'data/video_2.mp4'
|
||||
vid_name = 'video_2'
|
||||
kernelSize = 3
|
||||
break
|
||||
|
||||
cap = cv2.VideoCapture(input_video)
|
||||
|
||||
height, width, frames_count, fps = cap.get(cv2.CAP_PROP_FRAME_HEIGHT), cap.get(
|
||||
cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_COUNT), cap.get(cv2.CAP_PROP_FPS),
|
||||
height = int(height)
|
||||
width = int(width)
|
||||
frameArea = height*width
|
||||
|
||||
print("Wysokosc", height, "szerokosc", width, "liczba klatek", frames_count, "fps",fps)
|
||||
font = cv2.FONT_HERSHEY_SIMPLEX
|
||||
"""
|
||||
#Polozenie linii "mety" (na srodku kadru)
|
||||
lineUpper = int(4*(height/10))
|
||||
lineLower = int(6*(height/10))
|
||||
|
||||
upLimit = int(2*(height/10))
|
||||
downLimit = int(8*(height/10))
|
||||
"""
|
||||
#Polozenie linii "mety" (w dolnej czesci kadru)
|
||||
lineUpper = int(7*(height/10))
|
||||
lineLower = int(8*(height/10))
|
||||
|
||||
upLimit = int(4*(height/10))
|
||||
downLimit = int(10*(height/10))
|
||||
|
||||
print("Zielona linia y:",str(lineLower))
|
||||
print("Czerwona linia y:",str(lineUpper))
|
||||
lineLower_color = (0,255,0)
|
||||
lineUpper_color = (0,0,255)
|
||||
point1 = [0, lineLower]
|
||||
point2 = [width, lineLower]
|
||||
points_lineLower = np.array([point1,point2], np.int32)
|
||||
# Przekształcenie tablicy do 1x2, polecane w dokumentacji OpenCV ale chyba zbedne w tym przypadku
|
||||
#points_lineLower = points_lineLower.reshape((-1,1,2))
|
||||
point3 = [0, lineUpper]
|
||||
point4 = [width, lineUpper]
|
||||
points_LineUpper = np.array([point3,point4], np.int32)
|
||||
#points_LineUpper = points_LineUpper.reshape((-1,1,2))
|
||||
point5 = [0, upLimit]
|
||||
point6 = [width, upLimit]
|
||||
points_upLimit = np.array([point5,point6], np.int32)
|
||||
#points_upLimit = points_upLimit.reshape((-1,1,2))
|
||||
point7 = [0, downLimit]
|
||||
point8 = [width, downLimit]
|
||||
points_downLimit= np.array([point7,point8], np.int32)
|
||||
#points_downLimit = points_downLimit.reshape((-1,1,2))
|
||||
|
||||
sub=cv2.createBackgroundSubtractorMOG2() # utworz background subtractor
|
||||
|
||||
size = 1.0 #wielkosc obrazu
|
||||
cars = []
|
||||
maxAllowedAge = 3 #przez ile klatek "zgubiony" pojazd bedzie pozostawal na liscie do "sledzenia"
|
||||
id = 1
|
||||
|
||||
|
||||
while(cap.isOpened()):
|
||||
ret, frame = cap.read()
|
||||
if not ret: # jezeli film sie zakonczyl
|
||||
#frame = cv2.VideoCapture(input_video)
|
||||
#continue
|
||||
break
|
||||
if ret: #przetwarzanie kadru
|
||||
input_vid = cv2.resize(frame, (0, 0), None, size, size) # rozmiar obrazu
|
||||
cv2.imshow("bez zmian", input_vid) # wyswietlanie filmu wejsciowego bez zmian
|
||||
gray = cv2.cvtColor(input_vid, cv2.COLOR_BGR2GRAY)
|
||||
cv2.imshow("czarnobialy", gray) # wyswietlanie filmu w skali szarosci
|
||||
fgMask = sub.apply(gray) # uzycie background subtraction
|
||||
cv2.imshow("fgMask", fgMask)
|
||||
for i in cars:
|
||||
i.age_one()
|
||||
|
||||
if ret == True: #przetwarzanie kadru
|
||||
|
||||
#frame = cv2.resize(frame, (0, 0), None, size, size) # rozmiar obrazu. Bez zmian
|
||||
#cv2.imshow("bez zmian", frame) # wyswietlanie filmu wejsciowego bez zmian
|
||||
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
||||
#cv2.imshow("czarnobialy", gray) # wyswietlanie filmu w skali szarosci
|
||||
fgMask = sub.apply(frame) # uzycie background subtraction
|
||||
fgMask2 = sub.apply(frame)
|
||||
#cv2.imshow("fgMask", fgMask)
|
||||
# operacje morfologiczne. Wg tutoriala na docs.opencv.org. Opening, closing - usuwanie szumów
|
||||
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) # kernel to apply to the morphology
|
||||
closing = cv2.morphologyEx(fgMask, cv2.MORPH_CLOSE, kernel)
|
||||
#cv2.imshow("closing", closing)
|
||||
opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, kernel)
|
||||
#cv2.imshow("opening", opening)
|
||||
dilation = cv2.dilate(opening, kernel)
|
||||
#cv2.imshow("dilation", dilation)
|
||||
retvalbin, bins = cv2.threshold(dilation, 220, 255, cv2.THRESH_BINARY) # Thresholding/binaryzacja obrazu usuwanie cieni
|
||||
#cv2.imshow('bins',bins)
|
||||
# obrysowywanie
|
||||
contours, hierarchy = cv2.findContours(bins, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # RETR_EXTERNAL - bierz pod uwage najbardziej 'zewnetrzne' kontury
|
||||
#Binarization
|
||||
ret,imBinary = cv2.threshold(fgMask,200,255,cv2.THRESH_BINARY)
|
||||
#cv2.imshow("binarny", imBinary)
|
||||
|
||||
minContourSize = 400
|
||||
maxContourSize = 50000
|
||||
kernelOpening = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernelSize, kernelSize)) # kernels to apply to the morphology
|
||||
kernelClosing = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
|
||||
#Opening is just another name of erosion followed by dilation.
|
||||
#It is useful in removing noise
|
||||
mask = cv2.morphologyEx(imBinary,cv2.MORPH_OPEN,kernelOpening)
|
||||
#cv2.imshow("opening", mask)
|
||||
|
||||
for i in range(len(contours)): # przejdz wszystkie kontury w kadrze
|
||||
if hierarchy[0, i, 3] == -1: # uzycie hierarchii zeby uwzgledniac tylko "rodzicow" (najbardziej zewnetrzne kontury)
|
||||
area = cv2.contourArea(contours[i])
|
||||
if minContourSize < area < maxContourSize: # nie obrysowuj zbyt duzych i malych obiektow
|
||||
# obliczanie centoidu konturu (czyli srodka) za pomoca tzw "momentow"
|
||||
centroid = contours[i]
|
||||
moments = cv2.moments(centroid)
|
||||
cx = int(moments['m10'] / moments['m00'])
|
||||
cy = int(moments['m01'] / moments['m00'])
|
||||
#Closing is reverse of Opening, Dilation followed by Erosion.
|
||||
#It is useful in closing small holes inside the foreground objects, or small black points on the object.
|
||||
mask = cv2.morphologyEx(mask,cv2.MORPH_CLOSE,kernelClosing)
|
||||
cv2.imshow("closing", mask)
|
||||
|
||||
# punkty graniczne (bounding points) konturu. x,y to wspolrzedne lewego gornego rogu, w,h to szerokosc i wysokosc prostokata
|
||||
x, y, w, h = cv2.boundingRect(centroid)
|
||||
# utworz prostokat wokol konturu
|
||||
cv2.rectangle(input_vid, (x, y), (x + w, y + h), (255, 0, 0), 2)
|
||||
# kontury (obrysowywanie)
|
||||
contours,hierarchy=cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE) # RETR_EXTERNAL - bierz pod uwage najbardziej 'zewnetrzne' kontury
|
||||
|
||||
cv2.imshow("wykryte pojazdy", input_vid)
|
||||
# kontury zajmujace zbyt duza lub mala czesc kadru beda ignorowane
|
||||
maxContourSize = frameArea / 4
|
||||
minContourSize = frameArea / 400
|
||||
|
||||
for j in range(len(contours)): # przejdz wszystkie kontury w kadrze
|
||||
area = cv2.contourArea(contours[j])
|
||||
#print("wielkosc konturu:",area)
|
||||
if minContourSize < area < maxContourSize: # zbyt duze i male obiekty sa ignorowane
|
||||
#### Sledzenie konturow ######
|
||||
centroid = contours[j]
|
||||
moments = cv2.moments(centroid)
|
||||
cx = int(moments['m10'] / moments['m00'])
|
||||
cy = int(moments['m01'] / moments['m00'])
|
||||
|
||||
# punkty graniczne (bounding points) konturu. x,y to wspolrzedne lewego gornego rogu, w,h to szerokosc i wysokosc prostokata
|
||||
x, y, w, h = cv2.boundingRect(centroid)
|
||||
|
||||
new = True #przyjmij ze kontur to nowy pojazd
|
||||
if cy in range(upLimit,downLimit): # sprawdz czy jest wart sledzenia (czyli miedzy szarymi liniami limitujacymi)
|
||||
for i in cars:
|
||||
# jesli odnajdziesz sledzony kontur o bardzo zblizonych koordynatach,
|
||||
#przymij ze to ten sam i zaktualizuj jego polozenie
|
||||
if abs(x - i.getX()) <= w and abs(y - i.getY()) <= h: #abs function calculates an absolute value of each matrix element.
|
||||
new = False
|
||||
i.updateCoords(cx, cy)
|
||||
#sprawdz czy prekroczyl mete
|
||||
if i.going_UP(lineLower,lineUpper) == True:
|
||||
counter_up+=1
|
||||
print("Pojazd o ID:",i.getId(),'przekroczyl linie mety w gore o czasie:', time.strftime("%c"))
|
||||
elif i.going_DOWN(lineLower,lineUpper) == True:
|
||||
counter_down+=1
|
||||
print("Pojazd o ID:", i.getId(), 'przekroczyl linie mety w dol o czasie:', time.strftime("%c"))
|
||||
break
|
||||
#jesli kierunek ruchu jest znany i linia mety zostala przekroczona, przestan sledzic i usun z listy
|
||||
if i.getState() == '1':
|
||||
if i.getDir() == 'down'and i.getY() > downLimit:
|
||||
i.setDone()
|
||||
elif i.getDir() == 'up'and i.getY() < upLimit:
|
||||
i.setDone()
|
||||
if i.timedOut():
|
||||
index=cars.index(i)
|
||||
cars.pop(index)
|
||||
del i
|
||||
|
||||
if new == True: #Jesli kontur nie byl dotychczas sledzony, dodaj nowy samochod do listy
|
||||
newCar=vehicles.Car(id,cx,cy,maxAllowedAge)
|
||||
cars.append(newCar)
|
||||
id+=1
|
||||
|
||||
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
|
||||
|
||||
#for i in cars:
|
||||
#cv2.putText(frame, str(i.getId()), (i.getX(), i.getY()), font, 0.3, i.getRGB(), 1, cv2.LINE_AA) #wypisywanie id
|
||||
|
||||
|
||||
key = cv2.waitKey(60)
|
||||
if key == 27: #Wyjdz po nacisnieciu escape
|
||||
|
||||
|
||||
str_up='W GORE: '+str(counter_up)
|
||||
str_down='W DOL: '+str(counter_down)
|
||||
frame = cv2.polylines(frame,[points_lineLower],False,lineLower_color,thickness=2)
|
||||
frame = cv2.polylines(frame,[points_LineUpper],False,lineUpper_color,thickness=2)
|
||||
frame = cv2.polylines(frame,[points_upLimit],False,(255,255,255),thickness=1)
|
||||
frame = cv2.polylines(frame,[points_downLimit],False,(255,255,255),thickness=1)
|
||||
cv2.putText(frame, str_up, (10, 40), font, 0.5, (255, 255, 255), 2, cv2.LINE_AA) #biale tlo zeby licznik byl wyrazniejszy
|
||||
cv2.putText(frame, str_up, (10, 40), font, 0.5, lineUpper_color, 1, cv2.LINE_AA)
|
||||
cv2.putText(frame, str_down, (10, 90), font, 0.5, (255, 255, 255), 2, cv2.LINE_AA) #biale tlo zeby licznik byl wyrazniejszy
|
||||
cv2.putText(frame, str_down, (10, 90), font, 0.5, lineLower_color, 1, cv2.LINE_AA)
|
||||
cv2.imshow('Frame',frame)
|
||||
|
||||
key = cv2.waitKey(60)
|
||||
if key == 27: # Wyjdz po nacisnieciu escape
|
||||
break
|
||||
|
||||
else:
|
||||
break
|
||||
|
||||
timestr = time.strftime("%Y_%m_%d-%H_%M_%S")
|
||||
f = open("traffic logs/"+vid_name+" "+timestr+".txt","w+")
|
||||
f.write("Natężenie ruchu:\r\nliczba samochodów jadących w górę: %d\rliczba samochodów jadących w dół: %d" %(counter_up, counter_down))
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
0
traffic logs/dummy.txt
Normal file
0
traffic logs/dummy.txt
Normal file
83
vehicles.py
Normal file
83
vehicles.py
Normal file
@ -0,0 +1,83 @@
|
||||
from random import randint
|
||||
import time
|
||||
|
||||
class Car:
|
||||
tracks=[]
|
||||
def __init__(self,id,xi,yi,max_age):
|
||||
self.id = id
|
||||
self.x = xi
|
||||
self.y = yi
|
||||
self.tracks = []
|
||||
self.R = randint(0,255)
|
||||
self.G = randint(0,255)
|
||||
self.B = randint(0,255)
|
||||
self.done = False
|
||||
self.state = '0' # 0 - wymaga dalszego sledzenia, 1 - przekroczyl mete, zostal policzony i mozna go bedzie usunac
|
||||
self.age = 0 # o
|
||||
self.max_age = max_age
|
||||
self.dir = None
|
||||
|
||||
def getRGB(self):
|
||||
return (self.R,self.G,self.B)
|
||||
|
||||
def getId(self):
|
||||
return self.id
|
||||
|
||||
def getX(self): # szerokosc
|
||||
return self.x
|
||||
|
||||
def getY(self): # wysokosc
|
||||
return self.y
|
||||
|
||||
def getState(self):
|
||||
return self.state
|
||||
|
||||
def getDir(self):
|
||||
return self.dir
|
||||
|
||||
#stare wspolrzedne dodaj do listy "tropu" pojazdu, a nastepnie aktualizuj
|
||||
def updateCoords(self, xNew, yNew):
|
||||
self.age = 0
|
||||
self.tracks.append([self.x, self.y])
|
||||
self.x = xNew
|
||||
self.y = yNew
|
||||
|
||||
def setDone(self):
|
||||
self.done = True
|
||||
|
||||
def timedOut(self):
|
||||
return self.done
|
||||
|
||||
def going_UP(self, mid_start, mid_end):
|
||||
if len(self.tracks)>=2:
|
||||
if self.state=='0':
|
||||
if self.tracks[-1][1]<mid_end and self.tracks[-2][1]>=mid_end:
|
||||
self.state='1'
|
||||
self.dir='up'
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def going_DOWN(self,mid_start,mid_end):
|
||||
if len(self.tracks)>=2:
|
||||
if self.state=='0':
|
||||
if self.tracks[-1][1]>mid_start and self.tracks[-2][1]<=mid_start:
|
||||
self.state='1'
|
||||
self.dir='down'
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def age_one(self):
|
||||
self.age+=1
|
||||
if self.age>self.max_age:
|
||||
self.done=True
|
||||
return True
|
Loading…
Reference in New Issue
Block a user