import numpy as np
import cv2 as cv
import  time
class Car:
    def __init__(self,c_id,c_x,c_y,direction,c_count,c_start_time,c_over_time,c_v) :
        self.c_id = c_id
        self.c_x=c_x
        self.c_y=c_y
        self.direction = direction
        self.c_count = c_count
        self.c_start_time = c_start_time
        self.c_over_time = c_over_time
        self.c_v = c_v
    def updateCoords(self,x,y) :
        self.c_x= x
        self.c_y=y

count_up = 0
count_down = 0
cars = []
pid = 1
max_v = 0
distance = 10
# Read video
vc = cv.VideoCapture(R "C:\Users\zn\Desktop\ SURVEILLANCE Video _1.mp4")
XVID is mPEG-4 encoding type
fourcc = cv.VideoWriter_fourcc(*'XVID')
# Save video
out = cv.VideoWriter('output.avi',fourcc,15, (1920.1080))
# Dynamic target detection algorithm
# history: the number of frames used for training the background. The default is 500 frames. If the learningRate is not set manually, the history is used to calculate the current learningRate.
# varThreshold: Variance threshold used to determine whether the current pixel is foreground or background. Generally, the default value is 16. If the light changes significantly, such as the water surface under the sun, it is recommended to set it to 25 and 36. It is not too troublesome to try specific values, because the higher the value, the lower the sensitivity.
# detectShadows: indicates whether to detectShadows. Set this parameter to true and false to not detectShadows. Detection shadows will increase program time complexity.
BS = cv.createBackgroundSubtractorMOG2(detectShadows=True)
while (vc.isOpened()):
    ret, frame = vc.read()
    # cv.imshow("frame01",frame)
    # CV ::cvtColor() is used to convert images from one color space to another.
    gray = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
    # ret, gray = CV. Threshold (gray, 127255, CV. THRESH_BINARY)
    fgmask = BS.apply(gray)
    # CV. MedianBlur Median filtering, image blur processing
    image = cv.medianBlur(fgmask,5)
    # cv.imshow("BS",fgmask)
    The # *getStructuringElement* function returns the structure element with the specified shape and size
    element = cv.getStructuringElement(cv.MORPH_RECT,(5.5));Create a structure
    # Using the function morphologyEx, it is convenient to perform a series of expansion-corrosion combinations on the image. It is used to remove noise
    image2 = cv.morphologyEx(image, cv.MORPH_CLOSE,element,iterations=5);# close operation
    # image3 = cv.erode(image2, element)
    image3 = cv.morphologyEx(image2, cv.MORPH_OPEN, element, iterations=5)
    # cv.imshow('frame1', image3)
    # CV. FindContours detects the contours of the object
    contours, hierarchy = cv.findContours(image3, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    # Void CV ::putText(CV :: mat&img, // Image to draw const string& text, // Text to draw CV ::Point origin, // lower left corner of the text boxintFontFace, // Font (e.g. CV ::FONT_HERSHEY_PLAIN) double fontScale, // Size factor, the larger the value, the larger the text CV ::Scalar color, // the color of the lines (RGB)int thickness = 1// Line widthint lineType = 8, // linear (4Neighborhood or8Neighborhood, default8Neighborhood)bool bottomLeftOrigin = false // true='origin at lower left'
	);
# CV. Line - Draw a line segment between two points' pt1 'and' pT2 'on image' img '
# - 'img' : Image to draw line segments on
# - 'pt1' : the first point of the line segment
# - 'pt2' : the second point of the line segment
# - 'color' : the color of the line segment
# - 'thickness' : thickness of a line segment
# - 'lineType' : indicates the lineType
# - 'shift' : Coordinates to decimal places
    cv.line(frame, (0.700), (1920.700), (0.255.0), 3)
    cv.line(frame, (0.400), (1920.400), (0.255.0), 3)
    cv.line(frame, (0.800), (1920.800), (255.255.255), 2)
    cv.line(frame, (0.300), (1920.300), (255.255.255), 2)
    cv.putText(frame,"Up:"+str(count_up),(1100.100),cv.FONT_HERSHEY_COMPLEX,2, (255.0.0),3)
    cv.putText(frame, "Down:" + str(count_down),(700.100), cv.FONT_HERSHEY_COMPLEX, 2, (255.0.0), 3)
    cv.putText(frame, "max_v:" + str('%.2f' %(max_v*3.6)) +'km/h', (50.100), cv.FONT_HERSHEY_COMPLEX, 1.5, (255.0.0), 2)
    null = True # If no cars are detected in this frame, empty the cars, reduce the error, and set the initial variable null to True
    for cnt in contours:
        # CV. BoundingRect take the smallest rectangle and wrap it around the shape you find
        x, y, w, h = cv.boundingRect(cnt)
        cx = int(x + w / 2)
        cy = int(y + h / 2)
        if 300<int(y+(h/2))"800 and 400<int(x+(w/2))"1800:
            # CV. ContourArea is mainly used to calculate the area of image contour
            if cv.contourArea(cnt) < 13000 or w < 100 or h < 100:
                continue
            null = False # Will not empty when there is a car
            new = True  Whether to create a vehicle
            for i in cars:
                if  abs(cx-i.c_x) <100 and abs(cy - i.c_y)<100:# Find the closest vehicle from the previous frame
                    # cv.putText(frame, 'cid:' + str(i.c_id), (x, y-10), cv.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0), 2)
                    # cv.putText(frame, "now_v:" + str('%.4f' % (i.c_v)) + 'm/s', (x, y-10),
                    # cv.FONT_HERSHEY_COMPLEX, 1,
                    # (255, 0, 0), 2)
                    new = False
                    i.updateCoords(cx,cy)# Update vehicle location information
                    if 700<=i.c_y<=720 and i.direction =='down' and i.c_count ==False:
                        i.c_over_time = time.time()
                        i.c_v = distance/(i.c_over_time - i.c_start_time)
                        if i.c_v>max_v:
                            max_v = i.c_v
                        count_down+=1
                        i.c_count=True
                    if 380<=i.c_y<=400 and i.direction =='up' and (i.c_count == False):
                        i.c_over_time = time.time()
                        i.c_v = distance/ (i.c_over_time - i.c_start_time)
                        if i.c_v > max_v:
                            max_v = i.c_v
                        count_up+=1
                        i.c_count=True
                if i.c_y>720 or i.c_y<380:
                    cars.remove(i) Delete the object when it exceeds a certain range

            if new == True and 340<cy<760: Create object if certain conditions are met
                start_time = time.time()
                p = Car(pid, cx, cy, 'unknow'.False, start_time ,0.0)
                if p.c_x <1000:
                    p.direction = 'down'
                else:
                    p.direction = 'up'
                cars.append(p)
                pid += 1
            cv.circle(frame, (cx, cy), 5, (0.0.255), -1)
            cv.rectangle(frame, (x, y), (x + w, y + h), (0.0.255), 3)
    if null == True:    # No cars in this frame, clear cars
        cars = []
    # cv.putText(frame, 'cars:' + str(len(cars)), (100, 100), cv.FONT_HERSHEY_COMPLEX, 2, (255, 0, 0), 3)
    cv.imshow("frame",frame)
    out.write(frame)
    #cv.imshow('frame2', image3)
    # print (max_v * 3.6)
    The # cv.waitKey **(**int k**) function refreshes the image, where k is in milliseconds, indicating the refresh frequency
    k = cv.waitKey(30) & 0xff
    if k == 27:
        break
vc.release()
cv.destroyAllWindows()
Copy the code