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.
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.