书名:图像处理与计算机视觉实践——基于OpenCV与Python
ISBN:978-7-115-62454-3
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
著 吴 佳 于仕琪
责任编辑 赵祥妮
人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
读者服务热线:(010)81055410
反盗版热线:(010)81055315
“图像处理”和“计算机视觉”课程是人工智能专业的必修课,是计算机、智能科学、电子信息、软件工程等专业的选修课。
OpenCV是一个开源的计算机视觉库,高效地实现了大量图像处理和计算机视觉算法。本书基于成熟的OpenCV库,采用Python语言,通过大量的实际应用示例,介绍图像处理和计算机视觉算法。书中的示例以最近几年的最新科研进展为主,如人脸识别、目标跟踪、二维码识别、手势识别等。读者通过这些实用示例可以快速透彻理解算法理论,同时提高将理论应用于实践的能力。
本书提供配套的源代码,方便读者学习实践。本书可作为“图像处理”和“计算机视觉”课程的教材,适合图像处理领域的师生、从业人员、OpenCV初学者参考,也适合有一定Python语言基础的读者进阶学习。
基于计算机视觉和数字图像处理技术的应用已经深入我们工作与生活的很多方面,比如门禁、闸机系统的人脸识别、汽车的自动驾驶、工业生产中的自动质检、美颜、安防系统中的目标检测跟踪、医学影像的自动诊断等。构成这些技术的基础是数字图像处理和计算机视觉理论,高等院校的人工智能专业都开设了“数字图像处理”和“计算机视觉”这两门必修课,它们也是其他相关专业(如计算机、智能科学、电子信息、软件工程等)的选修课。将理论知识落地到实际应用中,需要学习者对理论有扎实的理解,同时具备很强的工程应用能力;较好的学习方法是在理论学习中结合实践,通过动手实现具体应用来理解理论知识并提高工程应用能力,避免“纸上谈兵”,这也是写作本书的出发点。
本书是一本实践性的教材,通过大量与知识点相关的示例和完整的应用示例来介绍数字图像处理和计算机视觉理论的基础知识,更重要的是训练学习者的实际开发能力,同时加深其对知识点的理解。本书所有的示例均采用Python语言并基于OpenCV库来实现。OpenCV是经典的图像处理和计算机视觉的开源软件工具,它涵盖了从图像处理的基础算法到复杂的计算机视觉、机器学习的高级算法,更包括了最新的与深度学习有关的内容,在学术界和工业界被广泛使用。OpenCV简单易用,同时也是高度优化的,有很多算法都可以直接用于实际产品。它的通用性强,用户不用担心更换了系统环境或硬件设备而需要耗费时间重新编码。Python语言是目前主流的编程语言,易于编写、易于调试。通过结合OpenCV和Python,学习者可以专注于理解关键理论知识,避免耗费很多时间在配置开发环境和调试程序上。
随着深度学习的兴起,计算机视觉领域的应用有了突飞猛进的发展,很多方向都实现了大规模应用。本书紧跟技术前沿,介绍的应用示例均以近几年的最新科研和研发进展为主,同时贴近实际应用场景,如人脸识别、目标跟踪、文本识别、QR码识别等,书中不再花篇幅介绍过时的算法。配套的示例代码资源可在异步社区下载。希望读者通过本书,可以在实践中加深对知识的理解,同时提高工程应用能力。
由于编写时间仓促,笔者水平有限,书中难免出现一些错误或不准确的地方,恳请读者批评指正,您可以给我们发送电子邮件。如果您有其他的一些建议或意见,也欢迎发送邮件给我们。联系电子邮箱为jia.wu@opencv.org.cn。
吴佳 于仕琪
本书提供如下资源:
● 本书源代码、素材文件
● 书中彩图文件
要获得以上资源,您可以扫描右方二维码,根据指引领取。
作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。
当您发现错误时,请登录异步社区(https://www.epubit.com/),按书名搜索,进入本书页面,点击“发表勘误”,输入勘误信息,点击“提交勘误”按钮即可(见下图)。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。
我们的联系邮箱是contact@epubit.com.cn。
如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。
如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们。
如果您所在的学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。
如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。
“异步社区”(www. epubit.com)是由人民邮电出版社创办的IT专业图书社区,于2015年8月上线运营,致力于优质内容的出版和分享,为读者提供高品质的学习内容,为作译者提供专业的出版服务,实现作者与读者在线交流互动,以及传统出版与数字出版的融合发展。
“异步图书”是异步社区策划出版的精品IT图书的品牌,依托于人民邮电出版社在计算机图书领域30余年的发展与积淀。异步图书面向IT行业以及各行业使用IT技术的用户。
OpenCV是Open Source Computer Vision Library的缩写,它是一个开放源代码的计算机视觉库(代码仓库地址https://github.com/opencv)。OpenCV提供了2500多个传统和主流的、从基本到高级的计算机视觉算法及机器视觉算法,稳定而高效。其底层使用C/C++实现,具有Python、Java、JavaScript等语言的接口,且Python版本用户的数量在不断增长。
OpenCV于1999年由Intel(英特尔)公司发起,2000年在CVPR会议(Conference on Computer Vision and Pattern Recognition,国际计算机视觉与模式识别会议)上正式以BSD(Berkely Software Distribution,伯克利软件发行版)许可证授权发行。用户可以在教育研究、个人项目或者商业产品中免费使用OpenCV,也就是说,用户可以对OpenCV做任何操作,包括修改OpenCV的源代码、将OpenCV嵌入自己开发的软件中、销售包含OpenCV的软件等,唯一的约束是要在软件的文档或者说明中注明使用了OpenCV并附上OpenCV的协议。从2020年10月发布的4.5版本开始,OpenCV改用Apache 2.0许可证,Apache 2.0许可证除了提供与BSD许可证相同的许可,还有专利相关的条款。OpenCV的协议保证了计算机视觉技术快速的传播,让更多人从OpenCV中受益。
OpenCV最初的开发工作是由Intel俄罗斯团队负责的,几经变化后在2020年形成图1-1所示的分布式开发团队,由美国、俄罗斯、中国的3个研发中心和OpenCV社区共同维持OpenCV的发展。
图1-1 OpenCV分布式开发团队
虽然OpenCV的底层是用C++实现的,但目前使用OpenCV Python接口的用户数量已超过使用其C++接口的用户数量。除了易于编写和调试,Python接口的OpenCV库安装起来也非常简单,在终端输入下面的命令即可安装OpenCV:
# 安装opencv库
pip install opencv-python
 
# 或者
# 同时安装opencv和opencv_contrib
pip install opencv-contrib-python本章及后面的章节将结合OpenCV来对图像处理和计算机视觉的基础算法与一些主流应用进行介绍,读者可通过使用OpenCV实现算法并观察结果,来全面理解这些算法知识,并学会应用理论知识。
我们在电子设备上看到的图像都可以称为数字图像,例如图1-2所示的Lena图像。
图1-2 Lena的数字图像
对计算机来说,这幅图像只是一些亮度不同的点。一幅尺寸为M×N的图像可以用M×N的矩阵(即M×N个点)表示,如图1-3所示。每个矩阵元素代表一个像素,元素的值表示这个位置图像的亮度,一般来说,值越大该点就越亮。放大图1-3(a)中白色方框区域可得到图1-3(b)所示效果,对应的像素的值为图1-3(c)中的值。通常,灰度图像用2维矩阵M×N表示,彩色(多通道)图像用3维矩阵M×N×3表示。对于图像显示来说,一般用无符号8位整数来表示像素亮度,取值范围为[0, 255]。
(a) (b) (c)
图1-3 数字图像的表示
图像数据按照自左向右、自上向下的顺序存储在计算机内存中,即以图像的左上角为原点(也有自左向右、自下向上的顺序,即以图像的左下角为原点)。图1-4表示的是单通道灰度图像数据在计算机中的存储顺序,Iij代表第i行第j列的像素值。图1-5表示的是3通道BGR彩色图像数据在计算机中的存储顺序,每个像素用3个值表示,即 。需要说明一下,OpenCV中RGB彩色图像的通道顺序为BGR。
。需要说明一下,OpenCV中RGB彩色图像的通道顺序为BGR。
图1-4 单通道灰度图像数据在计算机中的存储顺序
图1-5 3通道BGR彩色图像数据在计算机中的存储顺序
OpenCV提供了函数cv.imread()、cv.imshow()和cv.imwrite()来处理图像文件的读取、显示和写入。
使用cv.imread()函数将图像文件读入内存:
retval = cv.imread(filename[, flags])其中的主要参数介绍如下。
● filename:要读取的图像文件的文件名。
● flags:控制如何读入图像文件的标志。flags的取值和含义如表1-1所示。
● retval:读入的图像数据。
表1-1 参数flags的取值和含义
| flags取值 | 含义 | 
|---|---|
| cv.IMREAD_UNCHANGED | 保持图像原始形式不变 | 
| cv.IMREAD_GRAYSCALE | 将图像转换为单通道的灰度图像 | 
| cv.IMREAD_COLOR | 默认值。将图像转换为3通道的BGR图像 | 
| cv.IMREAD_ANYDEPTH | 当输入图像是16位或32位时读入后保持不变,否则转换为8位 | 
| cv.IMREAD_ANYCOLOR | 读入任意彩色格式 | 
| cv.IMREAD_LOAD_GDAL | 用GDAL加载图像 | 
| cv.IMREAD_REDUCED_GRAYSCALE_2 | 将图像转换为单通道灰度图像,并且尺寸缩小为原始的1/2 | 
| cv.IMREAD_REDUCED_COLOR_2 | 将图像转换为3通道的BGR图像,并且尺寸缩小为原始的1/2 | 
| cv.IMREAD_REDUCED_GRAYSCALE_4 | 将图像转换为单通道灰度图像,并且尺寸缩小为原始的1/4 | 
| cv.IMREAD_REDUCED_COLOR_4 | 将图像转换为3通道的BGR图像,并且尺寸缩小为原始的1/4 | 
| cv.IMREAD_REDUCED_GRAYSCALE_8 | 将图像转换为单通道灰度图像,并且尺寸缩小为原始的1/8 | 
| cv.IMREAD_REDUCED_COLOR_8 | 将图像转换为3通道的BGR图像,并且尺寸缩小为原始的1/8 | 
| cv.IMREAD_IGNORE_ORIENTATION | 不根据EXIF(Exchangeable Image File,可交换图像文件)的方向标记旋转图像 | 
flags的默认值为cv.IMREAD_COLOR,即将读入的图像转换为3通道BGR图像数据。假如图像文件为单通道的灰度图像,读入后会被强制转换为3通道。cv.IMREAD_GRAYSCALE则返回单通道图像数据,假如图像文件为多通道图像,读入后会被强制转换为单通道图像。
cv.imread()支持多种格式图像文件的读取,OpenCV支持读取的图像文件格式如表1-2所示。
表1-2 OpenCV支持读取的图像文件格式
| 图像文件格式 | 扩展名 | 
|---|---|
| Windows位图 | bmp, dib | 
| JPEG | jpeg, jpg, jpe | 
| JPEG 2000 | jp2 | 
| 便携式网络图像 | png | 
| WebP | webp | 
| 便携式图像格式 | pbm, pgm, ppm, pxm, pnm | 
| PFM | pfm | 
| Sun栅格 | sr, ras | 
| TIFF | tiff, tif | 
| OpenEXR图像 | exr | 
| Radiance HDR | hdr, pic | 
| GDAL支持的栅格和矢量地理空间数据的各种格式 | Raster和Vector图像文件的扩展名 | 
注意:想要OpenCV支持某种图像文件格式,需要有对应的文件格式库。只有在编译OpenCV时添加了相应的库,安装后OpenCV才能支持此格式。
成功读取图像文件后,可以使用OpenCV提供的GUI(Graphical User Interface,图形用户界面)用cv.imshow()将图像在窗口中显示出来,如图1-6所示。
图1-6 OpenCV图像在窗口显示
cv.imshow(winname, mat)其中的主要参数介绍如下。
● winname:图像显示窗口的名称。
● mat:要显示的图像数据。
前面提到对于图像显示来说,一般用无符号8位整数,取值范围为[0, 255]。根据mat的数据类型,cv.imshow()显示图像时会进行以下操作。
● 如果mat是8位无符号整数,则直接显示。
● 如果mat是16位无符号整数,则像素值域会做[0, 255*256]到[0, 255]的映射。
● 如果mat是32位或64位浮点数,则像素值域会做[0, 1]到[0, 255]的映射。
● 如果mat是32位整数,则需要用户根据应用上下文预先进行将像素值域映射到[0, 255]的处理。
通过函数cv.imshow()生成的窗口会根据显示的图像自动调整大小,用户不能手动改变窗口大小。如果想改变窗口大小,可以使用OpenCV提供的另一个函数cv.namedWindow()来生成窗口。
cv.namedWindow(winname[, flags])其中的主要参数介绍如下。
● winname:窗口名称。
● flags:窗口的属性。flags值对应的窗口属性如表1-3所示。
表1-3 flags值对应的窗口属性
| flags值 | 窗口属性 | 
|---|---|
| cv.WINDOW_AUTOSIZE | 生成的窗口根据显示的图像自动调整大小来显示原始图像,但受屏幕分辨率限制。用户不能手动改变窗口大小 | 
| cv.WINDOW_NORMAL | 用户可以手动调整窗口大小,且在此窗口显示的图像会进行缩放以适应窗口大小 | 
| cv.WINDOW_OPENGL | OpenGL支持的窗口 | 
| cv.WINDOW_FULLSCREEN | 全屏窗口 | 
| cv.WINDOW_FREERATIO | 改变窗口大小时,窗口宽高比例不受显示图像原始宽高比限制 | 
| cv.WINDOW_KEEPRATIO | 改变窗口大小时,窗口宽高比例受显示图像原始宽高比限制,不能改变 | 
| cv.WINDOW_GUI_NORMAL | 生成的窗口没有状态栏和工具栏 | 
| cv.WINDOW_GUI_EXPANDED | 新的增强的GUI | 
 flags的默认值为 cv.WINDOW_AUTOSIZE|cv.WINDOW_KEEPRATIO|cv.WINDOW_GUI_EXPANDED。
调用函数cv.imshow()后还需要紧接着调用函数cv.waitKey()来执行GUI的housekeeping任务,这样才能实际显示图像和响应鼠标、键盘事件,否则不会显示图像且窗口可能被锁住。函数cv.waitKey()的功能是等待键盘按键按下。
retval = cv.waitKey([delay])其中的主要参数介绍如下。
● delay:等待键盘事件的时间,单位为ms;如果值小于或等于0,则窗口会一直等待键盘按键按下。默认值为0。
● retval:如果指定的时间内没有按键按下,则返回-1,否则返回被按下按键的ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)。
函数cv.destroyWindow(winname)和cv.destroyAllWindows()用于销毁生成的窗口。
将图像数据写入文件,可使用cv.imwrite()函数:
retval = cv.imwrite(filename, img[, params])其中的主要参数介绍如下。
● filename:文件名。
● img:待写入的图像数据。
● params:指定文件格式。OpenCV可保存的文件格式如表1-4所示。
表1-4 OpenCV可保存的文件格式
| params | 含义 | 
|---|---|
| cv.IMWRITE_JPEG_QUALITY | JPEG图像质量,取值范围为[0, 100],数值越大图像质量越高,同时文件也越大。默认值为95 | 
| cv.IMWRITE_JPEG_PROGRESSIVE | 使用渐进式JPEG,取值为0或1。默认值为0,表示不使用 | 
| cv.IMWRITE_JPEG_OPTIMIZE | 启用优化,取值为0或1。默认值为0,表示不启用 | 
| cv.IMWRITE_JPEG_RST_INTERVAL | JPEG重启间隔,取值范围为[0, 65535]。 默认值为0,表示不重启 | 
| cv.IMWRITE_JPEG_LUMA_QUALITY | 分离亮度质量级别,取值范围为[0, 100]。默认值为-1,表示不使用 | 
| cv.IMWRITE_JPEG_CHROMA_QUALITY | 分离色度质量级别,取值范围为[0, 100]。默认值为-1,表示不使用 | 
| cv.IMWRITE_JPEG_SAMPLING_FACTOR | JPEG设置采样因子 | 
| cv.IMWRITE_PNG_COMPRESSION | PNG图像压缩级别,取值范围为[0, 9],值越大文件越小,但压缩所需的时间也越长。默认值为1(速度最佳的设置) | 
| cv.IMWRITE_PNG_STRATEGY | cv::ImwritePNGFlags之一,默认值为 IMWRITE_PNG_STRATEGY_ RLE | 
| cv.IMWRITE_PNG_BILEVEL | PNG二值级别,取值为0或1,默认值为0 | 
| cv.IMWRITE_PXM_BINARY | PPM、PGM或PBM文件以二进制还是纯文本存储的标志,取值为0或1。默认值为1,即以二进制方式存储 | 
| cv.IMWRITE_EXR_TYPE | EXR图像存储类型。1表示FP16,2表示FP32,默认值为2 | 
| cv.IMWRITE_EXR_COMPRESSION | 重写EXR存储类型(默认值为FLOAT (FP32)) | 
| cv.IMWRITE_WEBP_QUALITY | 重写EXR压缩类型(默认值为ZIP_COMPRESSION = 3)。WEBP表示质量,取值范围为[0, 100],数值越大图像质量越高 | 
| cv.IMWRITE_PAM_TUPLETYPE | PAM用来设置TUPLETYPE为相应的格式定义的字符串值 | 
| cv.IMWRITE_TIFF_RESUNIT | TIFF图像用于指定设置哪个分辨率(单位为dpi,即dot per inch,点每英寸) | 
| cv.IMWRITE_TIFF_XDPI | TIFF图像用于指定X轴方向分辨率(dpi) | 
| cv.IMWRITE_TIFF_YDPI | TIFF图像用于指定Y轴方向分辨率(dpi) | 
| cv.IMWRITE_TIFF_COMPRESSION | TIFF图像用于指定图像压缩策略 | 
| cv.IMWRITE_JPEG2000_COMPRESSION_X1000 | JPEG2000图像用于指定目标压缩率(乘1000)。取值范围为[0, 1000],默认值为1000 | 
存储的图像格式根据filename中的扩展名来决定,同时并不是所有的img都可以存为图像文件,目前只支持8位单通道和3通道(颜色顺序为BGR)矩阵。如果img为16位无符号整数类型,则需要存储为PNG、JPEG 2000或TIFF格式;若为32位浮点数类型,则需要存储为PFM、TIFF、OpenEXR或Radiance HDR格式。如果某格式的图像矩阵不支持保存为图像文件,可以先用cv.convertTo()函数或者cv.cvtColor()函数将矩阵转为可以保存的格式,再保存。另外需要注意的是,在保存文件时如果文件名已经存在,cv.imwrite()函数不会进行提醒,将直接覆盖以前的文件。
下面的例子展示了如何读入一幅彩色图像,读入的同时将原始图像转换为灰度图像,在窗口显示灰度图像,并将灰度图像保存到文件中。
import cv2 as cv
 
def main():
 
    # 读入图像, 同时转换为灰度图像
    im_grey = cv.imread("lena.jpg", cv.IMREAD_GRAYSCALE)
    
    # 将灰度图像写入文件
    cv.imwrite("lena_grey.jpg", im_grey)
 
    # 显示灰度图像
    cv.imshow("Lena", im_grey)
    cv.waitKey()
    # 销毁窗口
    cv.destroyAllWindows()
 
 
if __name__  == '__main__':
    main()
    将lena.jpg放在与例子相同的目录下,运行该例子的代码后,lena_grey.jpg将会出现在此目录。读入的原始图像如图1-2所示,转为灰度图像的显示窗口如图1-7所示。
图1-7 灰度图像显示窗口
在介绍OpenCV如何读写与显示视频文件之前,先介绍一下编解码器(codec)。如果是图像文件,我们可以根据文件扩展名得知图像的格式,但是此经验并不能推广到视频文件中,因为视频文件的格式主要由压缩算法决定。压缩算法称为编码器(coder),解压算法称为解码器(decoder),编解码算法统称为编解码器(codec)。视频文件能否读写,关键看是否有相应的编解码器。编解码器的种类非常多,常用的有MJPG、XVID、DIVX等。视频文件的扩展名(如avi等)往往只能表示这是一个视频文件,我们并不能由其得知实际的编解码器。
OpenCV提供了两个类来处理视频文件的读写。读视频文件的类是VideoCapture,写视频文件的类是VideoWriter。
VideoCapture类既可以从视频文件读取图像,也可以从摄像头读取图像,可以使用该类的构造函数打开视频文件或者摄像头。如果VideoCapture类对象已经创建,可以使用cv.VideoCapture.open()函数打开,该函数会自动调用cv.VideoCapture.release()函数,先释放已经打开的视频文件,再打开新视频文件。如果要读取一帧图像,可以使用cv.Video Capture.read()函数。
打开摄像头:
cv.VideoCapture(index[, apiPreference])其中的主要参数介绍如下。
● index:视频捕获设备的ID,0表示用默认后端打开默认摄像头。
● apiPreference:在有多个视频捕获后端时指定一个后端,如cv.CAP_DSHOW、cv.CAP_MSMF、cv.CAP_V4L等。默认值为cv.CAP_ANY。
打开视频文件:
cv.VideoCapture(filename[, apiPreference])其中的主要参数介绍如下。
● filename:视频文件,它可以是以下类别。
○ 视频文件名,如video.avi。
○ 图像序列,如img_%02.jpg,会逐一读取图像文件img_00.jpg、img_01.jpg、img_ 02.jpg……
○ 视频流的URL(Uniform Resource Locator,统一资源定位符)。
○ gst-launch格式的GStreamer pipeline字符串。
● apiPreference:在有多个视频捕获后端时指定一个后端,如cv::CAP_FFMPEG、cv::CAP_IMAGES、cv::CAP_DSHOW。默认值为cv.CAP_ANY。
下面的例子演示了使用VideoCapture类读视频文件。
import sys
import cv2 as cv
 
 
def main():
    # 打开第一个摄像头
    #cap = cv.VideoCapture(0)
    # 打开视频文件
    cap = cv.VideoCapture("slow_traffic_small.mp4")
 
    # 检查是否打开成功
    if cap.isOpened() == False:
        print('Error opening the video source. ')
        sys.exit()
 
    while True:
        # 读取1帧视频,存放到im
        ret, im = cap.read()
        if not ret:
            print('No image read. ')
            break
 
        # 显示视频帧
        cv.imshow('Live', im)
        # 等待30ms,如果有按键按下则退出循环
        if cv.waitKey(30) >= 0:
            break
 
    # 销毁窗口
    cv.destroyAllWindows()
    # 释放cap
    cap.release()
 
if __name__ == '__main__':
    main()图1-8为读取1帧视频后窗口显示的效果。
图1-8 读取1帧视频后窗口显示的效果
OpenCV提供了VideoWriter类来创建视频文件(写视频),在Linux系统中使用FFMPEG来写视频文件,Windows系统中使用FFMPEG、MSWF或者DSHOW,macOS系统中使用AVFoundation。与读视频文件不同的是,写视频文件需要在创建视频时设置一系列参数,包括文件名、编解码器、视频帧率、视频帧宽度和高度等。
首先创建VideoWriter类对象:
writer=cv.VideoWriter(filename, fourcc, fps, framesize[, iscolor])其中的主要参数介绍如下。
● filename:创建的视频文件名。
● fourcc:使用4个字符表示的编解码器,可以是cv.VideoWriter_fourcc ('M', 'J', 'P','G')、cv.VideoWriter_fourcc('X','V',' I','D')、cv.VideoWriter_fourcc ('D',' I','V','X')等。编解码器列表可以在MSDN[1](微软的一个期刊产品)查询。如果使用某种编解码器无法创建视频文件,请尝试其他的编解码器。
[1] 网址为https://docs.microsoft.com/en-us/windows/win32/medfound/video-fourccs
● fps:视频帧率。
● framesize:视频帧宽度和高度。
● iscolor:如果值非0,编码器将按彩色帧进行编码;否则按灰度帧进行编码。
● writer:创建的VideoWriter对象。
然后使用函数cv.VideoWriter.writer()将视频帧写入文件:
cv.VideoWriter.write(image)其中,image 表示待写入的视频帧数据,通常是BGR格式的彩色图像。需要注意,image的尺寸必须与前面的framesize一致。
下面的例子演示了如何写视频文件。本示例将生成一个视频文件,视频的第0帧是一个白色的“0”,第1帧是个白色的“1”,以此类推,共100帧。生成视频文件的播放效果如图1-9所示。
import sys
import numpy as np
import cv2 as cv
 
def main():
    # 设置视频帧的宽度和高度
    frame_size = (320, 240)
 
    # 设置视频帧率
    fps = 25
 
    # 视频编解码格式
    fourcc = cv.VideoWriter_fourcc('M', 'J', 'P', 'G')
 
    # 创建writer
    writer = cv.VideoWriter("myvideo.avi", fourcc, fps, frame_size)
    # 检查是否创建成功
    if writer.isOpened() == False:
        print("Error creating video writer.")
        sys.exit()
 
    for i in range(0, 100):
 
        # 设置视频帧画面
        im = np.zeros((frame_size[1], frame_size[0], 3), dtype=np.uint8)
 
        # 将数字绘制到画面上
        cv.putText(im, str(i), (int(frame_size[0]/3), int(frame_size[1]*2/3)),                                 cv.FONT_HERSHEY_SIMPLEX, 3.0, (255, 255, 255), 3)
 
        # 保存视频帧到文件myvideo.avi
        writer.write(im)
 
    # 释放writer
    writer.release()
 
 
if __name__  == '__main__':
    main()
 图1-9 生成视频文件的播放效果