使用opencv线程捕获空白图像
blank image capture with opencv threading
我正在尝试将从我的笔记本电脑摄像头捕获的帧写入循环缓冲区。我想创建一个线程来处理这个任务(以异步方式)。当我尝试获取使用 get_last()
方法存储的最后一帧并显示它时,显示黑屏。我花了相当多的时间来找出原因,但都是在静脉中。恕我直言,这段代码应该有一个小问题,但看不到它。任何帮助将不胜感激。完整的工作代码如下所示:
import cv2
import sys
import time
import threading
class CamBuffer(threading.Thread):
def __init__(self, stream=0):
self.current = 0
self.max_size = 5
self.buffer = [None] * self.max_size
self.capture = cv2.VideoCapture(stream)
if not self.capture.isOpened():
print("Could not open video")
sys.exit()
print("Opened video")
self.running = True
super().__init__()
def run(self):
print('running thread')
while self.running:
print('capturing frame ', self.current)
_, frame = self.capture.read()
if _:
print('saving frame ', self.current)
self.buffer[self.current] = frame
self.current = self.current + 1
if (self.current >= self.max_size):
self.current = 0
self.capture.release()
print('stopped thread')
def terminate(self):
print('terminating thread')
self.running = False
def get_last(self):
current = 0
if self.current > 0:
current = self.current - 1
print('get_last()', current)
return self.buffer[current]
if __name__ == "__main__":
print('Frame buffer test')
stream = 0
cb = CamBuffer(stream)
cb.start()
time.sleep(1.25)
frame = cb.get_last()
if frame is not None:
print('showing frame')
cv2.imshow('Frame', frame)
time.sleep(3)
cb.terminate()
cv2.destroyAllWindows()
print('Frame buffer test [Done]')
对我有用的最简单的解决方案就是在 imshow 之后添加 cv.waitKey(1)
:
if frame is not None:
print('showing frame')
cv2.imshow('Frame', frame)
cv2.waitKey(1):
我认为这是 Opencv highgui 模块的问题 - 它是一个 GUI,也有自己的线程,有时它可能会挂起应用程序。尝试更新 Highgui window/cv2.imshow() 时出现灰屏,我在 C++ 中也遇到过。我猜想锁定 GUI 线程和图像的内存。
顺便说一句,您还可以在捕获线程中添加等待(如果您不需要最大帧率)。
PS. 在意识到可以用该行解决之前,我尝试了其他可能的问题:一个锁。acquire/release,一个全局缓冲区, 发送一个缓冲容器作为参数。然而,全局也显示灰色屏幕(尽管在捕获期间它显示捕获的图像)。当我添加 cv2.waitKey(...) 时,它最终使用作为参数发送的缓冲区工作,我意识到它可能已经足够了。
其他实验:
import cv2
import sys
import time
import threading
max_size = 5
buffer = [None] * max_size
frCopyGlobal = None
buff = [None] * max_size #call as param
class CamBuffer(threading.Thread):
def __init__(self, buff, stream=0):
self.current = 0
self.max_size = 5
self.buffer = [None] * self.max_size
self.capture = cv2.VideoCapture(stream, apiPreference=cv2.CAP_DSHOW)
if not self.capture.isOpened():
print("Could not open video")
sys.exit()
print("Opened video")
self.running = True
super().__init__()
def run(self):
print('running thread')
while self.running:
#lock.acquire()
print('capturing frame ', self.current)
_, frame = self.capture.read()
cv2.imshow("F", frame)
if _:
#print('saving frame ', self.current%self.max_size, self.current)
print('saving frame ', self.current)
frCopy = frame.copy()
self.buffer[self.current] = frCopy
frCopyGlobal = frame.copy()
buffer[self.current] = frCopyGlobal
buff[self.current] = frame.copy()
#self.buffer[self.current%self.max_size] = frame
#cv2.imshow("FBUFF", self.buffer[self.current%self.max_size])
cv2.imshow("FBUFF", self.buffer[self.current])
cv2.imshow("GLOBAL BUFF", buffer[self.current])
cv2.imshow("Param BUFF", buff[self.current])
self.current = self.current + 1
if (self.current >= self.max_size):
self.current = 0
cv2.waitKey(66)
#lock.release()
self.capture.release()
print('stopped thread')
def terminate(self):
print('terminating thread')
self.running = False
def get_last(self):
current = 0
if self.current > 0:
current = self.current - 1
print('get_last()', current)
for i in self.buffer:
cv2.imshow("THREAD: "+str(i), i)
for i in buffer:
cv2.imshow("GLOBAL: "+str(i), i)
return self.buffer[current]
if __name__ == "__main__":
lock = threading.Lock() #threading.Lock lock();
print('Frame buffer test')
stream = 0
cb = CamBuffer(buff, stream) # The buffer must be in common memory in order to read it from the calling thread
cb.start()
time.sleep(1.0)
for i in range(10):
try:
cv2.imshow("SAMPLE?", buff[1])
finally:
pass
cv2.waitKey(15)
time.sleep(1.25)
#cb.join()
#cb.sleep(1.)
#cb.terminate()
#frame = cb.get_last()
cb.running = False
###lock.acquire()
#frame = cb.buffer[0]
frame = buff[0]
#frame = buff[0]
frame = cb.buffer[0]
if frame is not None:
print('Showing frame from Thread')
cv2.imshow('PARAMETER BUFFER?', frame)
cv2.waitKey(500)
#frame = buffer[0] #Global
#if frame is not None:
# print('showing frame From GLOBAL')
# cv2.imshow('GLOBAL FRAME', frame)
###lock.release()
time.sleep(3)
cb.terminate()
cv2.destroyAllWindows()
print('Frame buffer test [Done]')
cb.join()
#exit(0)
我正在尝试将从我的笔记本电脑摄像头捕获的帧写入循环缓冲区。我想创建一个线程来处理这个任务(以异步方式)。当我尝试获取使用 get_last()
方法存储的最后一帧并显示它时,显示黑屏。我花了相当多的时间来找出原因,但都是在静脉中。恕我直言,这段代码应该有一个小问题,但看不到它。任何帮助将不胜感激。完整的工作代码如下所示:
import cv2
import sys
import time
import threading
class CamBuffer(threading.Thread):
def __init__(self, stream=0):
self.current = 0
self.max_size = 5
self.buffer = [None] * self.max_size
self.capture = cv2.VideoCapture(stream)
if not self.capture.isOpened():
print("Could not open video")
sys.exit()
print("Opened video")
self.running = True
super().__init__()
def run(self):
print('running thread')
while self.running:
print('capturing frame ', self.current)
_, frame = self.capture.read()
if _:
print('saving frame ', self.current)
self.buffer[self.current] = frame
self.current = self.current + 1
if (self.current >= self.max_size):
self.current = 0
self.capture.release()
print('stopped thread')
def terminate(self):
print('terminating thread')
self.running = False
def get_last(self):
current = 0
if self.current > 0:
current = self.current - 1
print('get_last()', current)
return self.buffer[current]
if __name__ == "__main__":
print('Frame buffer test')
stream = 0
cb = CamBuffer(stream)
cb.start()
time.sleep(1.25)
frame = cb.get_last()
if frame is not None:
print('showing frame')
cv2.imshow('Frame', frame)
time.sleep(3)
cb.terminate()
cv2.destroyAllWindows()
print('Frame buffer test [Done]')
对我有用的最简单的解决方案就是在 imshow 之后添加 cv.waitKey(1)
:
if frame is not None:
print('showing frame')
cv2.imshow('Frame', frame)
cv2.waitKey(1):
我认为这是 Opencv highgui 模块的问题 - 它是一个 GUI,也有自己的线程,有时它可能会挂起应用程序。尝试更新 Highgui window/cv2.imshow() 时出现灰屏,我在 C++ 中也遇到过。我猜想锁定 GUI 线程和图像的内存。
顺便说一句,您还可以在捕获线程中添加等待(如果您不需要最大帧率)。
PS. 在意识到可以用该行解决之前,我尝试了其他可能的问题:一个锁。acquire/release,一个全局缓冲区, 发送一个缓冲容器作为参数。然而,全局也显示灰色屏幕(尽管在捕获期间它显示捕获的图像)。当我添加 cv2.waitKey(...) 时,它最终使用作为参数发送的缓冲区工作,我意识到它可能已经足够了。
其他实验:
import cv2
import sys
import time
import threading
max_size = 5
buffer = [None] * max_size
frCopyGlobal = None
buff = [None] * max_size #call as param
class CamBuffer(threading.Thread):
def __init__(self, buff, stream=0):
self.current = 0
self.max_size = 5
self.buffer = [None] * self.max_size
self.capture = cv2.VideoCapture(stream, apiPreference=cv2.CAP_DSHOW)
if not self.capture.isOpened():
print("Could not open video")
sys.exit()
print("Opened video")
self.running = True
super().__init__()
def run(self):
print('running thread')
while self.running:
#lock.acquire()
print('capturing frame ', self.current)
_, frame = self.capture.read()
cv2.imshow("F", frame)
if _:
#print('saving frame ', self.current%self.max_size, self.current)
print('saving frame ', self.current)
frCopy = frame.copy()
self.buffer[self.current] = frCopy
frCopyGlobal = frame.copy()
buffer[self.current] = frCopyGlobal
buff[self.current] = frame.copy()
#self.buffer[self.current%self.max_size] = frame
#cv2.imshow("FBUFF", self.buffer[self.current%self.max_size])
cv2.imshow("FBUFF", self.buffer[self.current])
cv2.imshow("GLOBAL BUFF", buffer[self.current])
cv2.imshow("Param BUFF", buff[self.current])
self.current = self.current + 1
if (self.current >= self.max_size):
self.current = 0
cv2.waitKey(66)
#lock.release()
self.capture.release()
print('stopped thread')
def terminate(self):
print('terminating thread')
self.running = False
def get_last(self):
current = 0
if self.current > 0:
current = self.current - 1
print('get_last()', current)
for i in self.buffer:
cv2.imshow("THREAD: "+str(i), i)
for i in buffer:
cv2.imshow("GLOBAL: "+str(i), i)
return self.buffer[current]
if __name__ == "__main__":
lock = threading.Lock() #threading.Lock lock();
print('Frame buffer test')
stream = 0
cb = CamBuffer(buff, stream) # The buffer must be in common memory in order to read it from the calling thread
cb.start()
time.sleep(1.0)
for i in range(10):
try:
cv2.imshow("SAMPLE?", buff[1])
finally:
pass
cv2.waitKey(15)
time.sleep(1.25)
#cb.join()
#cb.sleep(1.)
#cb.terminate()
#frame = cb.get_last()
cb.running = False
###lock.acquire()
#frame = cb.buffer[0]
frame = buff[0]
#frame = buff[0]
frame = cb.buffer[0]
if frame is not None:
print('Showing frame from Thread')
cv2.imshow('PARAMETER BUFFER?', frame)
cv2.waitKey(500)
#frame = buffer[0] #Global
#if frame is not None:
# print('showing frame From GLOBAL')
# cv2.imshow('GLOBAL FRAME', frame)
###lock.release()
time.sleep(3)
cb.terminate()
cv2.destroyAllWindows()
print('Frame buffer test [Done]')
cb.join()
#exit(0)