I need some help in speeding up the merging process from two camera sources. The merge_fn is like kind of a panorama generation function and it takes a very minimal time. The frame rate is reduced because I am reading the camera sources one by one and I need to speed up that process (like separate threads?).
how to parallelize that?
my code:
import numpy as np
import cv2
leftStream = cv2.VideoCapture(0)
rightStream = cv2.VideoCapture(1)
def merge_fn(left, right):
pass
while True:
_, left = leftStream.read()
_, right = rightStream.read()
merge = merge_fn(left, right)
cv2.imshow("Merge", merge)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Release the windows and the cameras
leftStream.release()
rightStream.release()
cv2.destroyAllWindows()
CodePudding user response:
Worked well for me.
from multiprocessing import Process, Pipe
import cv2
import numpy as np
def start_camera_1(chi_c, camera):
cam = cv2.VideoCapture(camera)
while True:
ret, frame = cam.read()
if ret:
chi_c.send(frame)
def start_camera_2(chi_c, camera):
cam = cv2.VideoCapture(camera)
while True:
ret, frame = cam.read()
if ret:
chi_c.send(frame)
def start_stream():
par_c_1, chi_c_1 = Pipe()
par_c_2, chi_c_2 = Pipe()
process = Process(target=start_camera_1,
args=(chi_c_1, 0))
process.start()
process = Process(target=start_camera_2,
args=(chi_c_2, 1))
process.start()
while True:
result_1 = par_c_1.recv()
result_2 = par_c_2.recv()
frame = np.hstack((result_1, result_2))
frame = cv2.resize(frame, (1600, 900)) # resize according to your need
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == '__main__':
start_stream()
CodePudding user response:
Here's a threaded version that acquires from two separate cameras in two separate threads and then stacks the images side-by-side:
#!/usr/bin/env python3
import cv2
import time
import threading
import numpy as np
class VideoStream():
"""
Class that acquires video frames continuously, as fast as possible on a
separate thread and makes them available to caller, via 'latestFrame()'
method.
"""
def __init__(self, width=1920, height=1080, stream=0):
self.width = width
self.height = height
self.stream = stream
self.frame = None
self.thread = threading.Thread(target=self.acquireFrames, args=())
self.thread.daemon = True
self.thread.start()
def acquireFrames(self):
cap = cv2.VideoCapture(self.stream)
if cap.isOpened():
cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
while True:
ret, self.frame = cap.read()
if not ret:
print(f'ERROR: Stream: {stream}, error reading frame')
def latestFrame(self):
if not self.frame is None:
return self.frame
# Return blank frame if none available
return np.zeros((self.height, self.width, 3), dtype=np.uint8)
def main():
# Start streaming from two cameras
Stream0 = VideoStream(stream=0)
Stream1 = VideoStream(stream=1)
frames = 0
t0 = time.time()
while True:
# Grab latest frame from each camera
frame0 = Stream0.latestFrame()
frame1 = Stream1.latestFrame()
# Stack frames side-by-side
combined = np.hstack((frame0, frame1))
cv2.imshow('Streams', combined)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Show frame rate in case anyone is interested
frames = 1
if frames % 100 == 0:
elapsed = time.time() - t0
print(f'FPS: {int(frames/elapsed)}')
cv2.destroyAllWindows()
if __name__ == '__main__':
main()