OpenCV has an example for multithreaded video processing in their github repo.
https://github.com/opencv/opencv/blob/master/samples/python/video_threaded.py
Import ThreadPool from multiprocessing.pool and kick off a new thread for every cpu core. OpenCV has a function called getNumberOfCPUs()
Example:
from __future__ import print_function
import numpy as np
import cv2 as cv
from multiprocessing.pool import ThreadPool
from collections import deque
from common import clock, draw_str, StatValue
import video
class DummyTask:
def __init__(self, data):
self.data = data
def ready(self):
return True
def get(self):
return self.data
if __name__ == '__main__':
import sys
print(__doc__)
try:
fn = sys.argv[1]
except:
fn = 0
cap = video.create_capture(fn)
def process_frame(frame, t0):
# some intensive computation...
frame = cv.medianBlur(frame, 19)
frame = cv.medianBlur(frame, 19)
return frame, t0
threadn = cv.getNumberOfCPUs()
pool = ThreadPool(processes = threadn)
pending = deque()
threaded_mode = True
latency = StatValue()
frame_interval = StatValue()
last_frame_time = clock()
while True:
while len(pending) > 0 and pending[0].ready():
res, t0 = pending.popleft().get()
latency.update(clock() - t0)
draw_str(res, (20, 20), "threaded : " + str(threaded_mode))
draw_str(res, (20, 40), "latency : %.1f ms" % (latency.value*1000))
draw_str(res, (20, 60), "frame interval : %.1f ms" % (frame_interval.value*1000))
cv.imshow('threaded video', res)
if len(pending) < threadn:
ret, frame = cap.read()
t = clock()
frame_interval.update(t - last_frame_time)
last_frame_time = t
if threaded_mode:
task = pool.apply_async(process_frame, (frame.copy(), t))
else:
task = DummyTask(process_frame(frame, t))
pending.append(task)
ch = cv.waitKey(1)
if ch == ord(' '):
threaded_mode = not threaded_mode
if ch == 27:
break
cv.destroyAllWindows()
You should be able to use that example code and place your image processing in the process_frame function.
Add a counter to in your loop and call cv2.imshow when count == X
Answer from Michael James on Stack Overflowpython - Run processes in parallel while capturing video with opencv - Stack Overflow
How many parallel VideoCapture's can one camera handle? - Python - OpenCV
python - Using multiprocessing with opencv to run a function in parallel with inputs of frames from different cameras - Stack Overflow
multithreading - Multi-threading in image processing - video python opencv - Stack Overflow
Working on the assumption that the detection algorithm is CPU-intensive, you need to be using multiprocessing instead of multithreading since multiple threads will not run Python bytecode in parallel due to contention for the Global Interpreter Lock. You should also get rid of all the calls to sleep. It is also not clear when you run multiple threads or processes the way you are doing it what guarantees that the frames will be output in the correct order, that is, the processing of the second frame could complete before the processing of the first frame and get written to the detection_buffer first.
The following uses a processing pool of 6 processes (there is no need now for an implicit input queue).
from multiprocessing import Pool, Queue
import time
import cv2
# intialize global variables for the pool processes:
def init_pool(d_b):
global detection_buffer
detection_buffer = d_b
def detect_object(frame):
time.sleep(1)
detection_buffer.put(frame)
def show():
while True:
print("show")
frame = detection_buffer.get()
if frame is not None:
cv2.imshow("Video", frame)
else:
break
if cv2.waitKey(1) & 0xFF == ord('q'):
break
return
# required for Windows:
if __name__ == "__main__":
detection_buffer = Queue()
# 6 workers: 1 for the show task and 5 to process frames:
pool = Pool(6, initializer=init_pool, initargs=(detection_buffer,))
# run the "show" task:
show_future = pool.apply_async(show)
cap = cv2.VideoCapture(0)
futures = []
while True:
ret, frame = cap.read()
if ret:
f = pool.apply_async(detect_object, args=(frame,))
futures.append(f)
time.sleep(0.025)
else:
break
# wait for all the frame-putting tasks to complete:
for f in futures:
f.get()
# signal the "show" task to end by placing None in the queue
detection_buffer.put(None)
show_future.get()
print("program ended")
for me what I've done is building 2 threads for 2 funtions and use one queue:
- to get the frame and process it
- to dispaly
the cap variable was inside my process function.
def process:
cap = cv2.VideoCapture(filename)
ret, frame = cap.read()
while ret:
ret, frame = cap.read()
#detection part in my case I use tensorflow then
# end of detection part
q.put(result_of_detection)
def Display():
while True:
if q.empty() != True:
frame = q.get()
cv2.imshow("frame1", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if __name__ == '__main__':
# start threads
p1 = threading.Thread(target=process)
p2 = threading.Thread(target=Display)
p1.start()
p2.start()
it works just fine for me
hope I helped :D
Also, I think this page could may help: https://pyimagesearch.com/2015/12/21/increasing-webcam-fps-with-python-and-opencv/