I’m after constantly reading images from an OpenCV camera in Python and reading from the main program the latest image. This is needed because of problematic HW.
After messing around with threads and getting a very low efficiency (duh!), I’d like to switch to multiprocessing.
Here’s the threading version:
JavaScript
x
45
45
1
class WebcamStream:
2
# initialization method
3
def __init__(self, stream_id=0):
4
self.stream_id = stream_id # default is 0 for main camera
5
6
# opening video capture stream
7
self.camera = cv2.VideoCapture(self.stream_id)
8
self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 3840)
9
self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 2880)
10
11
if self.camera.isOpened() is False:
12
print("[Exiting]: Error accessing webcam stream.")
13
exit(0)
14
15
# reading a single frame from camera stream for initializing
16
_, self.frame = self.camera.read()
17
18
# self.stopped is initialized to False
19
self.stopped = True
20
21
# thread instantiation
22
self.t = Thread(target=self.update, args=())
23
self.t.daemon = True # daemon threads run in background
24
25
# method to start thread
26
def start(self):
27
self.stopped = False
28
self.t.start()
29
30
# method passed to thread to read next available frame
31
def update(self):
32
while True:
33
if self.stopped is True:
34
break
35
_, self.frame = self.camera.read()
36
self.camera.release()
37
38
# method to return latest read frame
39
def read(self):
40
return self.frame
41
42
# method to stop reading frames
43
def stop(self):
44
self.stopped = True
45
And –
JavaScript
1
5
1
if __name__ == "__main__":
2
main_camera_stream = WebcamStream(stream_id=0)
3
main_camera_stream.start()
4
frame = main_camera_stream.read()
5
Can someone please help me translate this to multiprocess land ?
Thanks!
Advertisement
Answer
I’ve written several solutions to similar problems, but it’s been a little while so here we go:
I would use shared_memory
as a buffer to read frames into, which can then be read by another process. My first inclination is to initialize the camera and read frames in the child process, because that seems like it would be a “set it and forget it” kind of thing.
JavaScript
1
44
44
1
import numpy as np
2
import cv2
3
from multiprocessing import Process, Queue
4
from multiprocessing.shared_memory import SharedMemory
5
6
def produce_frames(q):
7
#get the first frame to calculate size of buffer
8
cap = cv2.VideoCapture(0)
9
success, frame = cap.read()
10
shm = SharedMemory(create=True, size=frame.nbytes)
11
framebuffer = np.ndarray(frame.shape, frame.dtype, buffer=shm.buf) #could also maybe use array.array instead of numpy, but I'm familiar with numpy
12
framebuffer[:] = frame #in case you need to send the first frame to the main process
13
q.put(shm) #send the buffer back to main
14
q.put(frame.shape) #send the array details
15
q.put(frame.dtype)
16
try:
17
while True:
18
cap.read(framebuffer)
19
except KeyboardInterrupt:
20
pass
21
finally:
22
shm.close() #call this in all processes where the shm exists
23
shm.unlink() #call from only one process
24
25
def consume_frames(q):
26
shm = q.get() #get the shared buffer
27
shape = q.get()
28
dtype = q.get()
29
framebuffer = np.ndarray(shape, dtype, buffer=shm.buf) #reconstruct the array
30
try:
31
while True:
32
cv2.imshow("window title", framebuffer)
33
cv2.waitKey(100)
34
except KeyboardInterrupt:
35
pass
36
finally:
37
shm.close()
38
39
if __name__ == "__main__":
40
q = Queue()
41
producer = Process(target=produce_frames, args=(q,))
42
producer.start()
43
consume_frames(q)
44