'multiprocessing script using Pipes

When I try to run the following script, process 1 displays just 1 sec of video and get stuck. is there any problem with the code? My goal is to run two processes, one which display's the frames continuously and other process perform face detection and print the results whenever the process1 sets the event. Process 1 sets the event at regular intervals i.e, after every 20 or 30 frames.

def read(e,parent):

    fps,st,frames_to_count,cnt = (0,0,30,0)
    vid = cv2.VideoCapture('sample.mp4')
    wid = 640
    while(vid.isOpened()):
        res,frame = vid.read()
        if not res:
            break
        frame = imutils.resize(frame,width = wid)
        cv2.imshow('VIDEO',frame)
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break
        if cnt == frames_to_count:
            try:
                fps = round(frames_to_count/(time.time()-st))
                parent.send(frame)
                e.set()
                st=time.time()
                cnt=0
            except:
                pass
        cnt+=1
    cv2.destroyAllWindows()

def fd(e,child):

    face_cascade=cv2.CascadeClassifier("path to xml")
    while True:
        e.wait()
        faces=face_cascade.detectMultiScale(child.recv(),1.1,4)
        print(faces)
        e.clear()

def main():

    e = Event()
    (child,parent) = Pipe()
    p1 = Process(target=read, args=(e,parent))
    p2 = Process(target=fd, args=(e,child))
    p1.start() 
    p2.start()
    p1.join()
    p2.join()


if __name__ == "__main__":

  main()


Solution 1:[1]

See all my comments to your posted question. In the code below I have retained the Pipe that you are using but have specified duplex=False since you are not using the returned connections for two-way communication and have correspondingly renamed these connections from child and parent to the now more meaningful read_conn and send_conn. I have, of course, removed the Event instance.

Since fd appears to be in a loop that never terminates, main will never be able to join that process. Therefore, p2 should be created as a daemon process that will automatically terminate when all non-daemon processes and threads terminate.

def read(send_conn):

    fps,st,frames_to_count,cnt = (0,0,30,0)
    vid = cv2.VideoCapture('sample.mp4')
    wid = 640
    while(vid.isOpened()):
        res,frame = vid.read()
        if not res:
            break
        frame = imutils.resize(frame,width = wid)
        cv2.imshow('VIDEO',frame)
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break
        if cnt == frames_to_count:
            try:
                fps = round(frames_to_count/(time.time()-st))
                send_conn.send(frame)
                st=time.time()
                cnt=0
            except:
                pass
        cnt+=1
    cv2.destroyAllWindows()

def fd(recv_conn):

    face_cascade=cv2.CascadeClassifier("path to xml")
    while True:
        faces=face_cascade.detectMultiScale(recv_conn.recv(),1.1,4)
        print(faces)

def main():

    (recv_conn,send_conn) = Pipe(duplex=False)
    p1 = Process(target=read, args=(send_conn,))
    p2 = Process(target=fd, args=(recv_conn,), daemon=True)
    p1.start() 
    p2.start()
    p1.join()


if __name__ == "__main__":

    main()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Booboo