本文主要内容来自于 OpenCV-Python 教程 的 OpenCV 中的 GUI 功能 部分,这个部分的主要内容如下:
通常,我们必须用摄像头捕捉实时流。OpenCV 提供了一个非常简单的接口来做这些。让我们从摄像头采集一段视频(我使用我笔记本电脑上内置的 webcam),把它转换为灰度视频并显示。只是一个入门的简单任务。
要捕捉视频,我们需要创建一个 VideoCapture 对象。它的参数可以是设备索引或视频文件的文件名。设备索引只是一个用于指定使用那个摄像头的数字。通常连接了一个摄像头(就我而言)。因而,我简单地传入 0 (或 -1)。你可以通过传入 1 选择第二个摄像头等等。随后你可以一帧一帧地捕捉图像。最后,不要忘记释放 capture。
#!/use/bin/env python
import sys
import numpy as np
import cv2 as cv
def main():
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
sys.exit()
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# if frame is read correctly ret is True
if not ret:
print("Can't receive frame() (stream end?). Exiting ...")
break
# Our operations on the frame come here
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# Display the resulting frame
cv.imshow('frame', gray)
if cv.waitKey(1) == ord('q'):
break
cap.release()
cv.destroyAllWindows()
if __name__ == "__main__":
main()
cap.read()
返回一个布尔值 (True
/False
)。如果正确地读取了帧,它为 True
。因此可以通过检查这个返回值来确认视频是否结束。
有时,cap 可能还没有初始化捕捉。在那种情况下,这段代码将显示错误。我们可以通过 cap.isOpened() 方法检查它是否初始化。如果它是 True
,则 OK。否则使用 cap.open()
打开它。
我们还可以使用 cap.get(propId) 方法访问这个视频的一些功能,其中 propId 是一个从 0 到 68 的数字。每个数字表示视频的一个属性(如果它适用于该视频的话)。完整的描述可以在这里找到:cv::VideoCapture::get()。这些值中的一些可以使用 cap.set(propId, value) 来修改。value 是想要的新值。
比如,我们可以通过 cap.get(
cv.CAP_PROP_FRAME_WIDTH
)
和 cap.get(
cv.CAP_PROP_FRAME_HEIGHT
)
检查帧的宽度和高度。它默认给出了 640x480。但我们想要把它修改为 320x240。则使用 ret = cap.set(
cv.CAP_PROP_FRAME_WIDTH
,320)
和 ret = cap.set(
cv.CAP_PROP_FRAME_HEIGHT
,240)
。如:
width = cap.get(cv.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv.CAP_PROP_FRAME_WIDTH)
fps = cap.get(cv.CAP_PROP_FPS)
print("FPS:{}, width x height: {} x {}".format(fps, width, height))
可以得到如下输出:
FPS:30.0, width x height: 640.0 x 640.0
注意:如果遇到了错误,则可以使用任何其它的摄像头应用程序(比如 Linux 下的 Cheese)来确认摄像头是否工作良好。
播放视频文件与从摄像头采集类似,只是把摄像头索引改为视频文件的文件名。同样在显示视频帧的时候,传入适当的时间调用 cv.waitKey()
。如果时间值太低,则视频会非常快,如果它太高,则视频会非常慢(好吧,这就是我们可以慢动作显示视频的方式)。一般情况下 25 毫秒就不错。
def play_video_file():
cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
cap = cv.VideoCapture(cv.samples.findFile("vtest.avi"))
while cap.isOpened():
ret, frame = cap.read()
# if frame is read correctly ret is True
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
cv.imshow('frame', gray)
if cv.waitKey(25) == ord('q'):
break
cap.release()
cv.destroyAllWindows()
cap.get(propId) 可用的 propId
由一些枚举值定义,这其中部分适用于摄像头的 VideoCapture
,部分则适用于视频文件的 VideoCapture
。对于视频文件,我们可以通过给 cap.get(propId) 传入 cv.CAP_PROP_FRAME_COUNT
获得视频文件的视频帧总数。
注意,请确保安装了适当版本的 ffmpeg 或 gstreamer。有时使用 video capture 比较头疼,这大多数是由于 ffmpeg/gstreamer 的错误安装。
我们捕捉了视频,并能一帧一帧地处理它,但我们还想保存视频。对于图像,它很简单:使用 cv.imwrite()
就好。在这里,需要做更多的工作。
这次我们创建一个 VideoWriter 对象。我们应该指定输出文件名(比如:output.avi)。然后我们应该指定 FourCC 码(下一段会有详细说明)。应该传入每秒多少帧 (fps) 以及帧大小。最后一个是 isColor 标记。如果它是 True
,则编码器期望是彩色帧,否则,它使用灰度帧。
FourCC 是一个用于指定视频编解码器的 4 字节码。在其官网 fourcc.org 可以找到可用的编解码器的列表。它是平台独立的。以下编解码器对我来说很好用。
以 cv.VideoWriter_fourcc('M','J','P','G')
或 cv.VideoWriter_fourcc(*'MJPG')
的形式为 MJPG 传 FourCC
码。
如下的代码从摄像头捕捉图形,在垂直方向翻转每一帧,并保存视频。
def save_video_file():
cap = cv.VideoCapture(0)
# Define the codec and create VideoWriter object
fourcc = cv.VideoWriter_fourcc(*'XVID')
out = cv.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
frame = cv.flip(frame, 0)
# write the flipped frame
out.write(frame)
cv.imshow('frame', frame)
if cv.waitKey(1) == ord('q'):
break
# Release everything if job is finished
cap.release()
out.release()
cv.destroyAllWindows()
Done.
参考文档 Getting Started with Videos