OpenCV VideoCapture 仅在读取 5 次后更新
我遇到了一个非常奇怪的错误,这个问题困扰了我几年的研究。我正在用Python和OpenCV2从网络摄像头读取图像数据。但问题是,图像总是滞后5帧。换句话说,每次调用read()时,得到的图像比实时画面慢了5帧。
我用的一个临时解决办法是每次抓取4帧,然后再读取第5帧来获取更新的图像,但这样做会严重影响我的性能。
这是我用来显示网络摄像头图像的代码:
frame = self.getGoodFrame()
if self.DEBUG:
window = cv2.namedWindow("Angles")
imgHSV = cv2.cvtColor(frame, cv2.cv.CV_BGR2HSV)
... Reseach specific code I shouldn't be giving out here ...
... It finds the center of a few bright colors in an image
if self.DEBUG:
debugImage = numpy.zeros((self.CAMERA_HEIGHT, self.CAMERA_WIDTH), numpy.uint8) #blank image
... Then we draw some stuff to the image to be displayed ...
cv2.imshow("Angles", debugImage)
cv2.waitKey(1)
raw_input()
还有getGoodFrame()这个函数:
def getGoodFrame(self):
MIN_READS_FOR_GOOD_FRAME = 4
for i in xrange(MIN_READS_FOR_GOOD_FRAME):
successful_read = self.capture.grab()
successful_read, frame = self.capture.read()
if not successful_read:
print "Unable to read from webcam, exiting."
return frame
你会注意到我有一个raw_input()的调用。这让我可以通过在控制台按几次回车来查看需要读取多少帧。这显示出确实有5帧的延迟。
我觉得这不是硬件问题,因为我在多个摄像头和USB线缆上都遇到过这个问题。不过,我还没有在其他机器上尝试重现这个错误。
2 个回答
1
问题出在我的硬件处理画面的方式上。我没能完全搞明白,但我找到的解决办法非常简单,就是并行处理。我修改了代码,开了一个线程,不停地更新一个变量,这个变量用来存储当前的画面。然后,当我需要当前画面时,只需查看这个变量的值。
需要注意的是,由于缓冲的原因,这个方法仍然会落后5次读取的调用,但因为我在一个独立的线程里持续进行读取,所以更新速度非常快。这是因为我每秒可以进行很多次读取。得到的图像和实时画面几乎没有差别。
我写的这个Python类如下。虽然代码不算优雅,但确实能用。为了做好这件事,我会(也一定会)添加一些优雅的方式来退出这个无限循环。不过现在对我来说,这个方法已经让我的图像检测代码速度提高了超过100倍,这让我非常兴奋!:)
class webcamImageGetter:
def __init__(self):
self.currentFrame = None
self.CAMERA_WIDTH = #webcam width
self.CAMERA_HEIGHT = #webcam height
self.CAMERA_NUM = 0
self.capture = cv2.VideoCapture(0) #Put in correct capture number here
#OpenCV by default gets a half resolution image so we manually set the correct resolution
self.capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,self.CAMERA_WIDTH)
self.capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT,self.CAMERA_HEIGHT)
#Starts updating the images in a thread
def start(self):
Thread(target=self.updateFrame, args=()).start()
#Continually updates the frame
def updateFrame(self):
while(True):
ret, self.currentFrame = self.capture.read()
while (self.currentFrame == None): #Continually grab frames until we get a good one
ret, frame = self.capture.read()
def getFrame(self):
return self.currentFrame
使用这个类时,你需要先初始化它,然后调用实例的start方法。这样,当你之后调用getFrame()时,就能得到来自摄像头的最新画面。太棒了!
2
默认的缓冲区设置为4.0,而不是1.0。
要解决这个问题:
cap.set(38,1)