简体   繁体   English

使用 opencv 线程捕获空白图像

[英]blank image capture with opencv threading

I am trying to write the frame captured from my laptop camera in to a circular buffer.我正在尝试将从笔记本电脑相机捕获的帧写入循环缓冲区。 I wanted to create a thread to handle this task (in an asynchronous way).我想创建一个线程来处理这个任务(以异步方式)。 When i try to get the last frame stored with get_last() method and show it, black screen is displayed.当我尝试获取使用get_last()方法存储的最后一帧并显示它时,会显示黑屏。 I have spent quite some time figuring out the reason, but all in vein.我花了相当长的时间找出原因,但一切都在脉络中。 IMHO there should be a small issue with this code, but cannot see it.恕我直言,这段代码应该有一个小问题,但看不到它。 Any help will be highly appreciated.任何帮助将不胜感激。 Complete working code is shown below:完整的工作代码如下所示:

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]')

The simplest solution that worked for me was just to add cv.waitKey(1) after imshow:对我有用的最简单的解决方案就是在 imshow 之后添加cv.waitKey(1)

 if frame is not None:
        print('showing frame')
        cv2.imshow('Frame', frame)
        cv2.waitKey(1):

I think that's an issue with Opencv highgui module - it's a GUI and has its own thread, too, sometimes it could hang the application.我认为这是 Opencv highgui 模块的问题 - 它是一个 GUI,也有自己的线程,有时它可能会挂起应用程序。 The gray screen appears when trying to update a Highgui window/cv2.imshow() too quickly, I've encountered it in C++ as well.尝试过快更新 Highgui 窗口/cv2.imshow() 时会出现灰屏,我在 C++ 中也遇到过。 I guess something about locking the memory of the GUI thread and the image.我猜想锁定GUI线程和图像的memory。

BTW, you could also add waiting in the capturing thread (if you don't need maximum framerate).顺便说一句,您还可以在捕获线程中添加等待(如果您不需要最大帧速率)。

PS. PS。 Before realizing it could be solved with that line, I experimented with other possible issues: a lock.acquire/release, a global buffer, sending a buffer container as a parameter.在意识到可以用那条线解决之前,我尝试了其他可能的问题:lock.acquire/release、全局缓冲区、发送缓冲区容器作为参数。 However the global also was showing gray screen (although during the capturing it displayed captured images).然而,全局也显示灰屏(尽管在捕获期间它显示捕获的图像)。 It finally worked with buffer sent as a parameter, when I added cv2.waitKey(...) and I realized that it may be enough anyway.当我添加 cv2.waitKey(...) 时,它终于与作为参数发送的缓冲区一起工作,我意识到无论如何它可能就足够了。

The other experiments:其他实验:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM