使用cvSetCaptureProperty中的CV_CAP_PROP_POS_帧获取单个帧

使用cvSetCaptureProperty中的CV_CAP_PROP_POS_帧获取单个帧,c,opencv,video-processing,C,Opencv,Video Processing,通过设置CV\u CAP\u PROP\u POS\u FRAMES属性,然后像这样读取帧,我试图跳转到特定帧: cvSetCaptureProperty( input_video, CV_CAP_PROP_POS_FRAMES, current_frame ); frame = cvQueryFrame( input_video ); 我面临的问题是,OpenCV 2.1为当前帧的12个连续值返回相同的帧,而我希望读取每个帧,而不仅仅是关键帧。谁能告诉我怎么了 我做了一些研究,发现问题是由

通过设置
CV\u CAP\u PROP\u POS\u FRAMES
属性,然后像这样读取帧,我试图跳转到特定帧:

cvSetCaptureProperty( input_video, CV_CAP_PROP_POS_FRAMES, current_frame );
frame = cvQueryFrame( input_video );
我面临的问题是,OpenCV 2.1为当前帧的12个连续值返回相同的帧,而我希望读取每个帧,而不仅仅是关键帧。谁能告诉我怎么了


我做了一些研究,发现问题是由解压算法引起的

类似MPEG的算法(包括HD、et-all)不单独压缩每个帧,而是不时地保存一个关键帧,然后只保存最后一帧和后续帧之间的差异

您报告的问题是由于选择帧时,解码器(可能是ffmpeg)会自动前进到下一个关键帧


那么,有办法解决这个问题吗?我不想要只关键帧,而是每个单独的帧。

CV\u CAP\u PROP\u POS\u帧跳到关键帧。我也遇到了同样的问题,并使用这个(python-)代码解决了这个问题。这可能不是完全有效的,但是完成工作:

def seekTo(cap, position):
  positiontoset = position
  pos = -1
  cap.set(cv.CV_CAP_PROP_POS_FRAMES, position)
  while pos < position:
    ret, image = cap.read()
    pos = cap.get(cv.CV_CAP_PROP_POS_FRAMES)
    if pos == position:
      return image
    elif pos > position:
      positiontoset -= 1
      cap.set(cv.CV_CAP_PROP_POS_FRAMES, positiontoset)
      pos = -1
def seekTo(盖,位置):
位置设置=位置
位置=-1
封盖套件(cv.cv\U封盖\U道具\U位置\U框架、位置)
而pos<位置:
ret,image=cap.read()
pos=cap.get(cv.cv\u cap\u PROP\u pos\u框架)
如果位置==位置:
返回图像
elif pos>位置:
位置设置-=1
盖组件(cv.cv\U盖组件\U位置框架,位置设置)
位置=-1

我不知道这对于您的目的是否足够精确,但我已经成功地获取了MPEG视频中的某个特定点,方法是获取帧速率,将帧数转换为时间,然后前进到时间。像这样:

cv::VideoCapture sourceVideo("/some/file/name.mpg");
double frameRate = sourceVideo.get(CV_CAP_PROP_FPS);
double frameTime = 1000.0 * frameNumber / frameRate;
sourceVideo.set(CV_CAP_PROP_POS_MSEC, frameTime);

由于OpenCV中的这一限制,最好改用FFMPEG。是一个很好的包装器库

# Get nth frame from a video
from moviepy.video.io.ffmpeg_reader import FFMPEG_VideoReader
cap = FFMPEG_VideoReader("movie.mov",True)
cap.initialize()
cap.get_frame(n/FPS)

表演也很棒。使用
get\u frame
搜索第n帧是O(1),如果请求(几乎)连续帧,则使用加速。我在同时加载三个720p视频时获得了比实时效果更好的效果。

我在OpenCV 3/Python 3上成功地使用了以下功能:

 # Skip to 150 frame then read the 151th frame
 cap.set(cv2.CAP_PROP_POS_FRAMES, 150))
 ret, frame = cap.read()

经过几年的假设,这是一个无法解决的bug,我想我已经找到了一种在速度和正确性之间保持良好平衡的使用方法

先前的解决方案建议在读取帧之前使用
CV\u CAP\u PROP\u POS\u MSEC
属性:

cv::VideoCapture sourceVideo("/some/file/name.mpg");
const auto frameRate = sourceVideo.get(CV_CAP_PROP_FPS);

void readFrame(int frameNumber, cv::Mat& image) {
  const double frameTime = 1000.0 * frameNumber / frameRate;
  sourceVideo.set(CV_CAP_PROP_POS_MSEC, frameTime);
  sourceVideo.read(image);
}
它确实返回预期的帧,但问题是使用
CV\u CAP\u PROP\u POS\u MSEC
可能非常慢,例如用于视频转换

注意:为了简单起见,使用全局变量


另一方面,如果您只想按顺序读取视频,则完全不需要查找就可以读取帧

for (int frameNumber = 0; frameNumber < nFrames; ++frameNumber) {
  sourceVideo.read(image);
}

我还没有找到任何解决办法。我所做的是避免OpenCv,并在Matlab中执行任务,该任务给出了每个帧,但以低速为代价。请在OpenCv中找到问题的解决方案:-/我也有同样的问题。虽然这个答案并没有解决问题,但我发现缺少一点:帧速率是以秒为单位的,应该以毫秒为单位:
double frameTime=1000.0*frameNumber/frameRate很有道理,@cbuchart。我已经更新了答案。你能告诉我为什么这个答案不适用于你吗?它似乎缺少一个关键帧。即使我制作一个sourceVideo.set(CV_CAP_PROP_POS_MSEC,0.0)并从那里开始,它只会给我错误的帧(带有“ghost”效果)这里的关键是
cv2。CAP_PROP_POS_帧
在开始时不再具有
CV_
,这是关于
CAP_PROP_POS_框架
的什么原因导致它无法使用?我只是想知道为什么你喜欢使用
CV\u CAP\u PROP\u POS\u MSEC
来代替。@MassDotNet
CAP\u PROP\u POS\u FRAMES
在使用关键帧对视频进行编码时无法正常工作(详细信息请参阅)。
cv::VideoCapture sourceVideo("/some/file/name.mpg");
const auto frameRate = sourceVideo.get(CV_CAP_PROP_FPS);
const int lastFrameNumber = -2; // guarantee seeking the first time

void readFrame(int frameNumber, cv::Mat& image) {
  if (lastFrameNumber + 1 != frameNumber) { // not the next frame? seek
    const double frameTime = 1000.0 * frameNumber / frameRate;
    sourceVideo.set(CV_CAP_PROP_POS_MSEC, frameTime);
  }

  sourceVideo.read(image);
  lastFrameNumber = frameNumber;
}