13

我有这种情况,我使用 OpenCV 来检测镜头前的人脸并在这些人脸上进行一些 ML。我遇到的问题是,一旦我完成了所有处理,然后去抓取下一帧,我就会得到过去,而不是现在。意思是,我将读取缓冲区内的内容,而不是实际在相机前面的内容。因为在处理过程中我不在乎哪些面孔出现在镜头前,所以我关心现在在镜头前的是什么。

我确实尝试将缓冲区大小设置为1,这确实有很大帮助,但我仍然会获得至少 3 次缓冲区读取。将 FPS 设置为 1,也无助于 100% 消除这种情况。贝娄是我的流程。

let cv = require('opencv4nodejs');

let camera = new cv.VideoCapture(camera_port);

camera.set(cv.CAP_PROP_BUFFERSIZE, 1);
camera.set(cv.CAP_PROP_FPS, 2);
camera.set(cv.CAP_PROP_POS_FRAMES , 1);

function loop()
{
    //
    //  <>> Grab one frame from the Camera buffer.
    //
    let rgb_mat = camera.read();

    //  Do to gray scale

    //  Do face detection

    //  Crop the image

    //  Do some ML stuff

    //  Do whats needs to be done after the results are in.

    //
    //  <>> Release data from memory
    //
    rgb_mat.release();

    //
    //  <>> Restart the loop
    //
    loop();
}

我的问题是:

是否可以一起删除缓冲区?如果是这样,如何。如果没有,why将不胜感激。

4

3 回答 3

16

是否CAP_PROP_BUFFERSIZE支持显得相当操作系统和后端特定。例如,2.4 文档声明它“目前仅受 DC1394 [Firewire] v 2.x 后端支持”,而对于后端 V4L,根据代码,仅在 2018 年 3 月 9 日才添加支持。

禁用缓冲区的最简单的非易碎方法是使用单独的线程;有关详细信息,请参阅我在 Piotr Kurowski 的回答下的评论。这里使用单独线程实现无缓冲 VideoCapture 的 Python 代码:(我没有 opencv4nodejs 环境。)

import cv2, Queue, threading, time

# bufferless VideoCapture
class VideoCapture:

  def __init__(self, name):
    self.cap = cv2.VideoCapture(name)
    self.q = Queue.Queue()
    t = threading.Thread(target=self._reader)
    t.daemon = True
    t.start()

  # read frames as soon as they are available, keeping only most recent one
  def _reader(self):
    while True:
      ret, frame = self.cap.read()
      if not ret:
        break
      if not self.q.empty():
        try:
          self.q.get_nowait()   # discard previous (unprocessed) frame
        except Queue.Empty:
          pass
      self.q.put(frame)

  def read(self):
    return self.q.get()

cap = VideoCapture(0)
while True:
  frame = cap.read()
  time.sleep(.5)   # simulate long processing
  cv2.imshow("frame", frame)
  if chr(cv2.waitKey(1)&255) == 'q':
    break

读帧器线程被封装在自定义VideoCapture类中,与主线程的通信是通过队列进行的。

这个答案建议cap.grab()在阅读器线程中使用,但文档不保证grab()清除缓冲区,因此这在某些情况下可能有效,但在其他情况下无效。

于 2019-02-07T16:19:54.390 回答
1

在将每一帧读取为无后,我将上限值设置为无,我的问题以这种方式解决:

import cv2
from PyQt5.QtCore import QThread

if __name__ == '__main__':
while True:
    cap = cv2.VideoCapture(0)
    ret, frame = cap.read()
    cv2.imshow('A', frame)
    cv2.waitKey(0)

    print('sleep!')
    QThread.sleep(5)
    print('wake up!')
    cap = None
于 2020-06-12T15:50:49.420 回答
0

我有同样的问题,但在 C++ 中。我没有在 OpenCV 中找到合适的解决方案,但我找到了解决方法。该缓冲区累积了恒定数量的图像,例如 n 帧。因此,您可以在不分析的情况下读取 n 帧并再次读取帧。最后一帧将是来自相机的实时图像。就像是:

buffer_size = n;

for n+1
{
  // read frames to mat variable
}
// Do something on Mat with live image
于 2019-01-31T13:04:11.450 回答