Search code examples
pythonpython-multiprocessingip-cameraautomatic-license-plate-recognitionyolov7

Running multiple processes in parallel to process frames of IP Cameras independently in Python


I am developing a Real Time License Plate Recognition System using YOLOv7 and Python. License plate recognition is done in two stage, using two YOLOv7 models, each of them working perfect.

In this system, I have to grab frames from IP cameras located in different places of parking lot and then check if any license plate exist in them for further processes. Based on this functionality, I decided to dedicate a Process to process each of the cameras, so that monitoring of each gateway be done in parallel and independent from other cameras, keeping real time behavior of system.

I have used Docker for deployment of this system, allowing easy installation and portability.

Here is the codes:

main.py

# Receiving urls
camera_urls = ['camera_1_url', 'camera_2_url']
for i, camera_url in enumerate(camera_urls):
    cameras.append(Process(target=camera_process, args=(i + 1, camera_url)))
for camera in cameras:
    camera.start()
for camera in cameras:
    camera.join()

camera_process.py

def camera_process(cam_id, url):
    cam = Camera(cam_id, url)
    plate_detector = PlateDetector(DETECTION_MODEL)
    plate_reader = PlateReader(OCR_MODEL)

    while True:
            
        if cam.stopped:
            cam.attempt_to_connect()

        im = cam.get_frame()
        if im is None:
            continue
        sleep(cam.FPS)

        detected, plate = plate_detector.detect(im)

        if detected:
            
            successful, prediction = plate_reader.predict(plate)

            if successful:
                send_plate(cam_id, url, prediction, plate) # send detected plate to core software to check for access

camera.py

class Camera:
    def __init__(self, id, src):
        self.src = src
        self.id = id
        self.FPS = setting.FPS 
        self.capture = cv2.VideoCapture(self.src)
        self.stopped = True
        self.attempt_to_connect()


    def update(self):
        while self.capture.isOpened():
            (self.status, self.frame) = self.capture.read()
            if not self.status:
                self.capture.release()
                break
            time.sleep(self.FPS)
        self.stopped = True


    def get_frame(self):
        return self.frame


    def attempt_to_connect(self):
        while not self.capture.isOpened():
            time.sleep(5)
            self.capture = cv2.VideoCapture(self.src)
        self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 2)

        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()
        self.stopped = False 

Problem When I run my program on a machine with 20 cores using single IP Camera, the performance of system is acceptable and fast. But when I add another camera, the performance decreases significantly. I doubt if both are running parallel, although 77 percent of my cpu is being used.

I tried running two separate Docker images, each process one of the urls, But the result was the same.

While i was searching for a solution, I faced this approach, Which doesn't create separate process for each camera and grabs frame in a loop. I'm not sure this is a good solution.

Now i don't know what to do to overcome this problem and achieve the performance to be same for different numbers of cameras.

Am I missing something? Is it related to GIL? Is there any other parallelism paradigms that I can use? Or Python is not a good choice for this functionality, and I have to switch to another programming language? (if yes, Which one?)

ANY help would be appreciated.


Solution

  • I just had to use torch.multiprocessing.Process class instead of using multiprocessing.Process. In the target function, I also added torch.set_num_threads(4). Now my program runs in parallel.