如何使用 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 中捕获视频
如何使用 python 和 openCV 从 .yuv 视频文件 (YUV420) 中提取帧?