简体   繁体   English

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

[英]How to process images of a video, frame by frame, in video streaming using OpenCV and Python

I am a beginner in OpenCV.我是 OpenCV 的初学者。 I want to do some image processing on the frames of a video which is being uploaded to my server.我想对上传到我的服务器的视频的帧进行一些图像处理。 I just want to read the available frames and write them in a directory.我只想读取可用的帧并将它们写入目录中。 Then, wait for the other part of the video to be uploaded and write the frames to the directory.然后,等待视频的另一部分上传并将帧写入目录。 And , I should wait for each frame to be completely uploaded then write it to a file.并且,我应该等待每一帧完全上传然后将其写入文件。

Can you tell me how can I do it with OpenCV (Python)?你能告诉我如何用 OpenCV (Python) 做到这一点吗?

Edit 1: I wrote this code for capturing the video from a file, while new data are being appended at the end of the file.编辑 1:我编写了这段代码,用于从文件中捕获视频,同时将新数据附加到文件末尾。 In other words, the out.mp4 file is not a complete video and another program is writing new frames on it.换句话说, out.mp4文件不是一个完整的视频,另一个程序正在其上写入新的帧。 What I'm going to do is, wait for the other program to write new frames then read them and display them.我要做的是,等待其他程序写入新的帧,然后读取它们并显示它们。

Here is my code:这是我的代码:

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

So the problem is the cap.grab() call!所以问题是cap.grab()调用! When there is no frame, it will return False !当没有框架时,它将返回False And it won't capture frames anymore, even if I wait for a long time.即使我等了很长时间,它也不会再捕获帧了。

After reading the documentation of VideoCapture .阅读VideoCapture的文档后。 I figured out that you can tell VideoCapture , which frame to process next time we call VideoCapture.read() (or VideoCapture.grab() ).我发现您可以告诉VideoCapture ,下次我们调用VideoCapture.read() (或VideoCapture.grab() )时要处理哪个帧。

The problem is that when you want to read() a frame which is not ready, the VideoCapture object stuck on that frame and never proceed.问题在于,当您想要read()未准备好的帧时, VideoCapture对象会卡在该帧上并且永远不会继续。 So you have to force it to start again from the previous frame.所以你必须强制它从前一帧重新开始。

Here is the code这是代码

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

Use this:用这个:

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

According to the latest updates for OpenCV 3.0 and higher, you need to change the Property Identifiers as follows in the code by Mehran:根据 OpenCV 3.0 及更高版本的最新更新,您需要在 Mehran 的代码中更改属性标识符,如下所示:

cv2.cv.CV_CAP_PROP_POS_FRAMES

to

cv2.CAP_PROP_POS_FRAMES

and same applies to cv2.CAP_PROP_POS_FRAME_COUNT .同样适用于cv2.CAP_PROP_POS_FRAME_COUNT

Hope it helps.希望能帮助到你。

In openCV's documentation there is an example for getting video frame by frame.在 openCV 的文档中有一个逐帧获取视频的示例 It is written in c++ but it is very easy to port the example to python - you can search for each fumction documentation to see how to call them in python.它是用 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;
}

This is how I would start to solve this:这是我将如何开始解决这个问题:

  1. Create a video writer:创建视频编写器:

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

    Check here for valid parameters 在此处检查有效参数

  2. Loop to retrieve[1] and write the frames:循环检索 [1] 并写入帧:

     cv.WriteFrame( videowriter, frame )

    WriteFrame doc 写框架文档

[1] zenpoy already pointed in the correct direction. [1] zenpoy 已经指出了正确的方向。 You just need to know that you can retrieve images from a webcam or a file :-)您只需要知道您可以从网络摄像头或文件中检索图像:-)

Hopefully I understood the requirements correct.希望我理解正确的要求。

The only solution I have found is not to set the index to a previous frame and wait (then OpenCV stops reading frames, anyway), but to initialize the capture one more time.我找到的唯一解决方案不是将索引设置为前一帧并等待(然后 OpenCV 停止读取帧,无论如何),而是再次初始化捕获。 So, it looks like this:所以,它看起来像这样:

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

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

    # do your processing here

And it works perfectly!它完美无缺!

This is example where a.mp4 is the video file这是一个示例,其中 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()

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

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