ich versuche gerade für die Filiale meines Vaters eine Art Personenzähler mittels eines Raspberry Pi und einer USB-Kamera zur realisieren. Rein zum Lernen, daher brauche ich auch keine anderen Vorschläge, wie Einkaufskörbe oder Bändchen um das max. betreten der Kunden zu überwachen.
Da ich noch nicht so gut im Python programmieren bin, habe ich mir aus "Modulen" eines bestehenden Programms ein wenig den Code abgeändert und nutze diesen.
Ziel des ganzen soll eine optische Erkennung der Kunden von oben sein.
Daraufhin wird diesen eine ID zugewiesen. Diese ID (Punkt) kann sich nun zwischen 2 Linien (programmiert) bewegen.
Wenn der Punkt von einer Seite kommend die zwei Linien durchbricht, wird entweder hoch oder runtergezählt.
Probleme habe ich mit der Stabilität des Programms und der Rechenleistung. Zumal das Programm momentan noch auf meinem Hauptrechner läuft und später mal auf dem Raspberry Pi laufen soll.
Falls mir jemand Tipps geben kann, was ich an dem Programm verändern soll, wäre ich ihm sehr dankbar. Mittels eines kleinen Testvideos hat es schonmal ganz gut funktioniert, jedoch ist bei einem livestream, die Datenmenge nicht mehr so ganz überschaubar. Evtl. muss ich da etwas an der FpS verstellen.
Ich packe den Code mal Hier rein, es sind 2 Dateien.
Datei 1 Person.py
Code: Alles auswählen
from random import randint
import time
class MyPerson:
tracks = []
def __init__(self, i, xi, yi, max_age):
self.i = i
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'
self.age = 0
self.max_age = max_age
self.dir = None
self.linija1 = None
self.linija2 = None
self.dingimas=0
def getRGB(self):
return (self.R,self.G,self.B)
def getTracks(self):
return self.tracks
def getDingimas(self):
return self.dingimas
def updateDingimas(self, x):
self.dingimas=x
def getId(self):
return self.i
def getState(self):
return self.state
def getDir(self):
return self.dir
def getX(self):
return self.x
def getY(self):
return self.y
def updateCoords(self, xn, yn):
self.age = 0
self.tracks.append([self.x,self.y])
self.x = xn
self.y = yn
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_start: #Überqueren der Linie
self.state = '1'
self.dir = 'up'
return True
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_end: #Überqueren der Linie
self.state = '1'
self.dir = 'down'
return True
else:
return False
else:
return False
def cross_bottom(self, bottom_line):
if self.tracks[0][1] < bottom_line < self.tracks[-1][1]: #Die Linie von unten überqueren
if self.linija1 != 'top':
self.linija1 = 'bottom'
else: self.linija2 = 'bottom'
if self.tracks[0][1] > bottom_line > self.tracks[-1][1]: #gekreuzte Linie ist vorbei
if self.linija1!='top':
self.linija1 = 'bottom'
else: self.linija2 = 'bottom'
def cross_top(self, top_line):
if self.tracks[0][1] < top_line < self.tracks[-1][1]: #Die Linie von oben überqueren
if self.linija1!='bottom':
self.linija1 = 'top'
else: self.linija2 = 'top'
if self.tracks[0][1] > top_line > self.tracks[-1][1]: #Die Linie von oben überqueren
if self.linija1!='bottom':
self.linija1 = 'top'
else: self.linija2 = 'top'
def kurEina(self,bottom_line,top_line):
if len(self.tracks) >= 2:
if self.dir == None:
self.cross_bottom(bottom_line)
self.cross_top(top_line)
if self.linija1== 'top' and self.linija2== 'bottom':
self.dir = 'down'
elif self.linija1== 'bottom' and self.linija2== 'top':
self.dir = 'up'
else:
return False
def age_one(self):
self.age += 1
if self.age > self.max_age:
self.done = True
return True
class MultiPerson:
def __init__(self, persons, xi, yi):
self.persons = persons
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
Code: Alles auswählen
import numpy as np
import cv2
import Person
import time
import imutils
import datetime
cap = cv2.VideoCapture("Ressources/Pedestrian_detector.mp4") #Webcam als Quelle nutzen
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows = True) #Hintergrundsubrathierer
kernelOp = np.ones((3,3),np.uint8)
kernelOp1 = np.ones((7,7),np.uint8)
kernelOp2 = np.ones((5,5),np.uint8)
kernelCl = np.ones((11,11),np.uint8)
kernelCl1 = np.ones((20,20),np.uint8)
kernelCl2 = np.ones((25,25),np.uint8)
#Variabeln
font = cv2.FONT_HERSHEY_SIMPLEX
persons = []
max_p_age = 5
pid = 1
areaTH = 5000
w_margin= 50
h_margin= 50
wmax= 500
#import pdb; pdb.set_trace() #Keine Ahnung warum hier der Debugger ist.
# Darstellungsvariabeln
cnt_up=0
cnt_down=0
line_down_color=(255,0,0)
line_up_color=(0,0,255)
pts_L1= np.array([[0, 320],[480, 320]])
pts_L2= np.array([[0, 400],[480, 400]])
counter=0
while(cap.isOpened()):
ret, frame = cap.read() #auslesen eines Frames
frame = imutils.resize(frame, width=min(640, frame.shape[1]))
fgmask = fgbg.apply(frame) #Benutzung des Subtrahierer
try:
ret,imBin= cv2.threshold(fgmask,200,255,cv2.THRESH_BINARY)
#Öffnen (erode->dilate) Ton entferen
mask0 = cv2.morphologyEx(imBin , cv2.MORPH_OPEN, kernelOp2)
#mask1 = cv2.morphologyEx(imBin , cv2.MORPH_OPEN, kernelOp1)
#mask2 = cv2.morphologyEx(imBin, cv2.MORPH_OPEN, kernelOp1)
#Closing (dilate -> erode) para juntar regiones blancas.
#mask3 = cv2.morphologyEx(mask , cv2.MORPH_CLOSE, kernelCl)
#mask4 = cv2.morphologyEx(mask1 , cv2.MORPH_CLOSE, kernelCl1)
mask = cv2.morphologyEx(mask0 , cv2.MORPH_CLOSE, kernelCl2)
except:
#Wenn keine weiteren Frames mehr folgen
print('EOF')
break
maskOriginal=mask
contours0, hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
# Falls die Kontur zu groß ist soll Sie halbiert werden
mask2_flag=0
for cnt in contours0:
area = cv2.contourArea(cnt)
if area > areaTH:
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
x,y,w,h = cv2.boundingRect(cnt)
if w > wmax:
mask2 = cv2.line(mask, ((x+w/2), 0), ((x+w/2),640),(0,0,0), 10)
mask2_flag=1
if mask2_flag==0:
mask2=mask
cv2.imshow('Mask su linija',mask2)
cv2.imshow('mask to open',mask0)
cv2.imshow('Mask pradinis tik veliau',maskOriginal)
cv2.imshow('pradinis substraction',imBin)
contours0, hierarchy = cv2.findContours(mask2,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for cnt in contours0:
cv2.drawContours(frame, cnt, -1, (0,255,0), 3, 8)
area = cv2.contourArea(cnt)
#################
# Prüfen ob die Person sich noch im Rahmen befindet, ansonsten Rahmen löschen
#################
for i in persons:
i.updateDingimas(i.getDingimas()+1) #Zählt wie viele Frames das Objekt hat (nicht aktualisiert)
if i.getDingimas() > 25:
persons.remove(i)
if area > areaTH:
#################
# Objekto sekimas
#################
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
x,y,w,h = cv2.boundingRect(cnt)
print('x{} y{} w{} h{}'.format( x, y, w, h))
new = True
for i in persons:
if abs(x-i.getX()) <= w_margin and abs(y-i.getY()) <= h_margin:
new = False
i.updateCoords(cx,cy)
i.updateDingimas(0) # nuresetina dingima
break
if new == True:
p = Person.MyPerson(pid,cx,cy, max_p_age)
persons.append(p)
pid += 1
cv2.circle(frame,(cx,cy), 5, (0,0,255), -1)
img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
cv2.drawContours(frame, cnt, -1, (0,255,0), 3)
cv2.imshow('img',img)
#########################
# Trajektorien-Abbildung
#########################
for i in persons:
if len(i.getTracks()) >= 2:
pts = np.array(i.getTracks(), np.int32)
pts = pts.reshape((-1,1,2))
frame = cv2.polylines(frame,[pts],False,i.getRGB())
# if i.getId() == 9:
# print str(i.getX()), ',', str(i.getY())
#################
# Prüfen ob die Linie überquert wurde #
#################
if i.getDir() == None:
i.kurEina( pts_L2[0,1] ,pts_L1[0,1]) # def kurEina(bSottom_line,top_line):
if i.getDir() == 'up':
cnt_up+=1
print('Timestamp: {:%H:%M:%S} UP {}'.format(datetime.datetime.now(), cnt_up))
elif i.getDir() == 'down':
cnt_down+=1
print('Timestamp: {:%H:%M:%S} DOWN {}'.format(datetime.datetime.now(), cnt_down))
cv2.putText(frame, str(i.getId()),(i.getX(),i.getY()),font,0.7,i.getRGB(),1,cv2.LINE_AA)
#########################
# Darstellung
#########################
str_up='UP: '+ str(cnt_up)
str_down='DOWN: '+ str(cnt_down)
frame = cv2.polylines( frame, [pts_L1], False, line_down_color,thickness=4)
frame = cv2.polylines( frame, [pts_L2], False, line_up_color,thickness=4)
cv2.putText(frame, str_up, (10,50), font,1,(0,0,255), 2,cv2.LINE_AA)
cv2.putText(frame, str_down, (10,100), font,1,(255,0,0), 2,cv2.LINE_AA)
cv2.imshow('Frame',frame)
#cv2.imwrite("img/frame %d.jpg" % counter, frame)
#counter=counter+1
#Verlassen mit Q odder ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows

Hoffe sehr das mir hier jemand weiterhelfen kann.
Liebe Grüße
Timo