简体   繁体   中英

How to return a Boolean value from one function to another via multiprocessing?

I have four functions; three camera functions to (take a picture save the image, save the path to a CSV file), the fourth function is to grab data from a serial connection via an arduino . Each function works as intended independently and via normal multiprocessing (without join() ). I cannot use the join() method because of the way the opencv function work. I understand that the join method works, where it waits for the child processes to complete before running it again.

I need to be able to return a value (Boolean: True/ False or 0/1) from the arduino function to the camera function before starting again. Arduino code takes the longest and needs time to run. generic code below

import cv2
import multiprocessing
import Serial


def camera1():
    global cap1
    cap1 = cv2.VideoCapture(0)
    while True:
        _, frame1 = cap1.read()
        cv2.imshow('frame1', frame1)

        k = cv2.waitKey(5)
        if k == 27:
            break
       """
       Saves image and add to csv file
       while loop checking for ard_serial is complete to repeat
       """
    cap1.release()


def camera2():
    global cap2
    cap2 = cv2.VideoCapture(1)
    while True:
        _, frame2 = cap2.read()
        cv2.imshow('frame2', frame2)

        k = cv2.waitKey(5)
        if k == 27:
            break
       """
       Saves image and add to csv file
       while loop checking for ard_serial is complete to repeat
       """
    cap2.release()



def camera3():
    global cap3
    cap3 = cv2.VideoCapture(2)
    while True:
        _, frame3 = cap3.read()
        cv2.imshow('frame3', frame3)

        k = cv2.waitKey(5)
        if k == 27:
            break
       """
       Saves image and add to csv file
       while loop checking for ard_serial is complete to repeat
       """
    cap3.release()


def ard_serial():
   """
   Serial Stuff happens here
   When Complete sends value to cam functions
   to start again.
   """

if __name__ == '__main__':
   for _ in range(20)
       p1 = multiprocessing.Process(target=camera1)
       p1.start()
       p2 = multiprocessing.Process(target=camera2)
       p2.start()
       p3 = multiprocessing.Process(target=camera3)
       p3.start()
       p4 = multiprocessing.Process(target=ard_serial)
       p4.start()
       """
       p1.join()
       p2.join()
       p3.join()
       p4.join()
       """

I need to have all four functions to start at the same time and have the cam functions wait for the arduino function to finish before starting again. What can I use for this? I wasn't sure if I have to use Queue or something different. Plus most examples have just one worker function that returns something. I need one function to send a return value to another function. join() method won't work because of the potentially never ending while loop, until it is complete

The easiest way is to use events for signaling between the different processes.

Events are a very basic way for sync processing. They can be set (=True) or cleared (=False). They also have a wait-function that blocks until the event is set to True. As they are thread-safe, they can be shared between processes.

Documentation Event

Something like:

import cv2
import multiprocessing
import Serial


def camera1(e):
    global cap1
    cap1 = cv2.VideoCapture(0)
    while True:
        e.wait()
        _, frame1 = cap1.read()
        cv2.imshow('frame1', frame1)

        k = cv2.waitKey(5)
        if k == 27:
            break
       """
       Saves image and add to csv file
       while loop checking for ard_serial is complete to repeat
       """
    cap1.release()


def camera2(e):
    global cap2
    cap2 = cv2.VideoCapture(1)
    while True:
        e.wait()
        _, frame2 = cap2.read()
        cv2.imshow('frame2', frame2)

        k = cv2.waitKey(5)
        if k == 27:
            break
       """
       Saves image and add to csv file
       while loop checking for ard_serial is complete to repeat
       """
    cap2.release()



def camera3(e):
    global cap3
    cap3 = cv2.VideoCapture(2)
    while True:
        e.wait()
        _, frame3 = cap3.read()
        cv2.imshow('frame3', frame3)

        k = cv2.waitKey(5)
        if k == 27:
            break
       """
       Saves image and add to csv file
       while loop checking for ard_serial is complete to repeat
       """
    cap3.release()


def ard_serial(e):
   """
   Serial Stuff happens here
   When Complete sends value to cam functions
   to start again.
   """
        e.clear()
        #do your stuff
        e.set()

if __name__ == '__main__':
   e = multiprocessing.event()
   for _ in range(20)
       p1 = multiprocessing.Process(target=camera1, args=[e,])
       p1.start()
       p2 = multiprocessing.Process(target=camera2, args=[e,])
       p2.start()
       p3 = multiprocessing.Process(target=camera3, args=[e,])
       p3.start()
       p4 = multiprocessing.Process(target=ard_serial, args=[e,])
       p4.start()
       """
       p1.join()
       p2.join()
       p3.join()
       p4.join()
       """

I'm not sure if you need multiprocessing at all. the following code might help highlight/solve some of the issues you're having:

import cv2

caps = {}
for i in range(3):
    cap = cv2.VideoCapture(i)
    # make sure we don't get too far behind
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
    caps[i] = cap

I start by opening all the capture devices and setting their buffer size to 1 frame. otherwise if you're waiting for serial activity before frames you'll tend to get older/buffered frames rather than a more recent one that you actually want.

next we run our main loop

frame = 0
while True:
    frame += 1

    # TODO: wait/check/handle for Serial activity

    # clear out any old/buffered frames
    for cap in caps.values():
        cap.read()

    # read recent frames
    for i, cap in caps.items():
        _, img = cap.read()
        # save to a file and display in window
        cv2.imwrite(f'output/{frame:06}-{i}.jpeg', img)
        cv2.imshow(f'cap {i}', img)

    # handle GUI events/check for keys
    if cv2.waitKey(1) == 27:
        break

you didn't include any actual code that you want for checking serial activity, but you should be able to use any blocking functions there. when serial code finishes, it reads and discards buffered frames from all cameras, then saves the subsequent frames out to disk. note that all the clearing should all happen at the same time so the (asynchronous) camera devices can start streaming their next frame together, and then we go over all devices again to pick up frames when they're ready

given what you've written above, I think this should be a reasonable template for solving your problem. it would of course be possible to use multiprocessing , but I think it just complicates what you're doing here for no benefit

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM