如何使用 OpenCV 和 Python 在视频流中逐帧处理视频图像

Posted

技术标签:

【中文标题】如何使用 OpenCV 和 Python 在视频流中逐帧处理视频图像【英文标题】:How to process images of a video, frame by frame, in video streaming using OpenCV and Python 【发布时间】:2013-09-28 02:12:22 【问题描述】:

我是 OpenCV 的初学者。我想对上传到我的服务器的视频帧进行一些图像处理。我只想读取可用的帧并将它们写入目录。然后,等待视频的另一部分上传,并将帧写入目录。而且,我应该等待每一帧都完全上传,然后将其写入文件。

您能告诉我如何使用 OpenCV (Python) 做到这一点吗?

编辑 1: 我编写了这段代码来从文件中捕获视频,而新数据被附加到文件的末尾。换句话说,out.mp4 文件不是完整的视频,另一个程序正在其上写入新帧。我要做的是,等待其他程序写入新帧,然后读取它们并显示它们。

这是我的代码:

import cv2
cap = cv2.VideoCapture("./out.mp4")

while True:
    if cap.grab():
        flag, frame = cap.retrieve()
        if not flag:
            continue
        else:
            cv2.imshow('video', frame)
    if cv2.waitKey(10) == 27:
        break

所以问题出在cap.grab() 电话上!无框时返回False!即使我等待很长时间,它也不会再捕获帧。

【问题讨论】:

请添加更详细的描述。在上传期间或之后“对帧进行一些图像处理”? “可用框架”它们应该在哪里以及如何可用? '等待视频的其他部分'所以只是追加?... @RobertCaspary 感谢您的评论。 “对帧进行一些图像处理”:假设我想将帧写入目录中的文件。 'available frames':假设视频有 100 帧,但只有 40 帧被上传,所以可用帧是前 40 帧。到目前为止,我已将它们保存到特定目录中的文件中。 '等待视频的其他部分':等待第 41 帧上传,然后将其保存到另一个文件,然后是第 42 帧,依此类推。清楚了吗? 【参考方案1】:

阅读VideoCapture的文档后。我发现你可以告诉VideoCapture,下次我们调用VideoCapture.read()(或VideoCapture.grab())时要处理哪个帧。

问题是当你想read()一个没有准备好的框架时,VideoCapture对象卡在那个框架上并且永远不会继续。所以你必须强制它从上一帧重新开始。

这里是代码

import cv2

cap = cv2.VideoCapture("./out.mp4")
while not cap.isOpened():
    cap = cv2.VideoCapture("./out.mp4")
    cv2.waitKey(1000)
    print "Wait for the header"

pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
while True:
    flag, frame = cap.read()
    if flag:
        # The frame is ready and already captured
        cv2.imshow('video', frame)
        pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
        print str(pos_frame)+" frames"
    else:
        # The next frame is not ready, so we try to read it again
        cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1)
        print "frame is not ready"
        # It is better to wait for a while for the next frame to be ready
        cv2.waitKey(1000)

    if cv2.waitKey(10) == 27:
        break
    if cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) == cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT):
        # If the number of captured frames is equal to the total number of frames,
        # we stop
        break

【讨论】:

这行得通,但在某个随机点,尽管输入流继续,但帧停止出现。还是有东西挂在这里 对于 OpenCV 3.0 以上版本,将 cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) 更改为 cap.get(cv2.CAP_PROP_POS_FRAMES)【参考方案2】:

使用这个:

import cv2
cap = cv2.VideoCapture('path to video file')
count = 0
while cap.isOpened():
    ret,frame = cap.read()
    cv2.imshow('window-name', frame)
    cv2.imwrite("frame%d.jpg" % count, frame)
    count = count + 1
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows() # destroy all opened windows

【讨论】:

我相信你的最后一行应该是:cv2.destroyAllWindows() 如果不返回则必须添加:继续【参考方案3】:

根据 OpenCV 3.0 及更高版本的最新更新,您需要在 Mehran 的代码中更改 Property Identifiers 如下:

cv2.cv.CV_CAP_PROP_POS_FRAMES

cv2.CAP_PROP_POS_FRAMES

同样适用于cv2.CAP_PROP_POS_FRAME_COUNT

希望对你有帮助。

【讨论】:

这没有回答问题。 如果包含指向更多信息的链接将不胜感激。【参考方案4】:

在 openCV 的文档中有一个 example 用于逐帧获取视频。它是用 c++ 编写的,但是很容易将示例移植到 python - 您可以搜索每个函数文档以查看如何在 python 中调用它们。

#include "opencv2/opencv.hpp"

using namespace cv;

int main(int, char**)

    VideoCapture cap(0); // open the default camera
    if(!cap.isOpened())  // check if we succeeded
        return -1;

    Mat edges;
    namedWindow("edges",1);
    for(;;)
    
        Mat frame;
        cap >> frame; // get a new frame from camera
        cvtColor(frame, edges, CV_BGR2GRAY);
        GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
        Canny(edges, edges, 0, 30, 3);
        imshow("edges", edges);
        if(waitKey(30) >= 0) break;
    
    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;

【讨论】:

非常感谢您的回答。我在python中做到了这一点。但问题是,当你调用 cap>>frame;它不会等待框架完全准备好!所以如果框架没有准备好,那么它将返回null。之后,它不会捕获任何其他帧。有意义吗? @Mehran 能这么温柔的分享一下python版本吗?【参考方案5】:

这就是我开始解决这个问题的方法:

    创建视频作者:

    import cv2.cv as cv
    videowriter = cv.CreateVideoWriter( filename, fourcc, fps, frameSize)
    

    Check here for valid parameters

    循环检索[1]并写入帧:

    cv.WriteFrame( videowriter, frame )
    

    WriteFrame doc

[1] zenpoy 已经指向正确的方向。您只需要知道您可以从网络摄像头或文件中检索图像 :-)

希望我理解正确的要求。

【讨论】:

【参考方案6】:

我找到的唯一解决方案不是将索引设置为前一帧并等待(然后 OpenCV 会停止读取帧,无论如何),而是再初始化一次捕获。所以,它看起来像这样:

cap = cv2.VideoCapture(camera_url)
while True:
    ret, frame = cap.read()

    if not ret:
        cap = cv.VideoCapture(camera_url)
        continue

    # do your processing here

而且效果很好!

【讨论】:

不错的解决方案。但是,重新初始化 Capture 的开销是多少?我们需要确保销毁和创建对象不会降低性能。 它不会降低性能 - 它会丢几帧。没有拖车或类似的东西,所以这对我们有用。 当流(在本例中为相机)始终从当前帧开始时,此解决方案有效。就我而言,该文件正在上传到服务器并保存到 out.mp4。因此,如果我重新初始化视频捕获,它将从视频的第一帧而不是最后一个可用帧开始。【参考方案7】:

这是 a.mp4 是视频文件的示例

import cv2
cap = cv2.VideoCapture('a.mp4')
count = 0
while cap.isOpened():
    ret,frame = cap.read()
    if not ret:
        continue
    cv2.imshow('window-name', frame)
    #cv2.imwrite("frame%d.jpg" % count, frame)
    count = count + 1
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

【讨论】:

你的伯爵在这里做什么? 计算帧数。 哦,好吧,你没有使用它们(打印或归还它们)所以我想也许你正在用计数做其他事情。

以上是关于如何使用 OpenCV 和 Python 在视频流中逐帧处理视频图像的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 opencv 和多线程 (logitech c920) 在 python 中捕获视频

如何在 OpenCV python 中读取视频流作为输入?

如何使用 python 和 openCV 从 .yuv 视频文件 (YUV420) 中提取帧?

使用Python,OpenCV反转视频

如何通过 OpenCV 和 Python 通过索引从视频中获取帧?

使用Python,OpenCV实现图像和实时视频流中的人脸模糊和马赛克