以下内容中的页码均来自《OpenCV 4详解 : 基于Python》
目录
第2章 载入、显示与保存数据
2.2 图像的读取与显示
2.2.1 图像读取函数 cv.imread()
函数原型:img = cv.imread(filename [, flags])
filename
:需要读取的图像的路径,包含图像名称和图像文件扩展名flags
:读取图像的形式,默认按照彩色图像格式读取(可选择的标志见P27表2-2)
如果无法正确读取图像,返回None,可通过print(img)
查看得到的结果是否为None来判断是否成功读取了图像。
2.2.2 图像窗口函数 cv.namedWindow()
函数原型:None = cv.namedWindow(winname [, flags])
winname
:窗口名称,用作窗口的标识符,用于识别此窗口flags
:窗口属性设置标志(可选择的标志见P28表2-3)
flags标志可以设置多个,不同参数之间用“|”分隔,默认为根据图像大小显示窗口、保持图像比例、创建的窗口允许添加工具栏和状态栏
2.2.3 图像显示函数 cv.imshow()
函数原型:None = cv.imshow(winname, img)
winname
:要显示图像的窗口的名称img
:要显示的图像
为了让图像不是一闪而过的,需要在本函数后加上cv.waitKey()
函数,来将程序暂停一段时间,暂停时间可以以参数的形式赋值,单位为毫秒;参数默认值为0,表示等待用户按键结束该函数。
2.2.4 关闭窗口函数 cv.destroyWindow()/cv.destroyAllWindows()
函数原型:
None = cv.destroyWindow(winname)
None = cv.destroyAllWindows()
winname
:要关闭的窗口的名称
2.3 视频的加载与摄像头的调用
2.3.1 读取视频数据 cv.VideoCapture()
函数原型:
<VideoCapture object> = cv.VideoCapture()
<VideoCapture object> = cv.VideoCapture(filename [, apiPreference])
filename
:读取的视频文件的名称apiPreference
:读取数据时设置的属性
第一行中的VideoCapture函数需要在使用时通过open()
函数指出,如对象名为video,则用video.open("testvideo.mov")
来打开视频文件。
第二行中的VideoCapture函数在默认情况下自动搜索合适的视频属性标志,在使用时一般可以省略属性标志。
- 创建视频对象后,用
isOpened()
函数判断是否创建成功,成功返回True,失败返回False。如video.isOpened()
- 判断已经成功创建视频对象后,用
read()
函数读取一帧图像,如通过ret, img = viedo.read()
从video对象中读取一帧图像存放在img中,ret变量存储是否成功读取对象,成功为True,失败为False。也可以通过ret变量判断读取视频文件时是否已经到了结尾。 - 另外,可以通过
get(propId)
函数获取视频属性,如video.get(0)
,propId
的可选标志见P30表2-4
示例代码(来自书本,略有改动,后同):
import cv2 as cv
if __name__ == '__main__':
video = cv.VideoCapture('./videos/road.mp4')
# 判断是否成功创建视频流
while video.isOpened(): # video.isOpened()成功读取返回true,读取失败返回false
ret, frame = video.read() # frame中存储一帧的图像;ret读取成功为true,读取失败为false
if ret is True:
cv.imshow('Video', frame)
# 设置视频播放速度,设置值等于1000为原速度,高于1000会减慢,低于1000加快
# 此代码为按视频原速度播放,cv.CAP_PROP_FPS表示原视频的帧率
cv.waitKey(int(1000 / video.get(cv.CAP_PROP_FPS)))
# 按下q退出
if cv.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# 输出相关信息
print('视频中图像的宽度为:{}'.format(video.get(cv.CAP_PROP_FRAME_WIDTH)))
print('视频中图像的高度为:{}'.format(video.get(cv.CAP_PROP_FRAME_HEIGHT)))
print('视频帧率为:{}'.format(video.get(cv.CAP_PROP_FPS)))
print('视频总帧数为:{}'.format(video.get(cv.CAP_PROP_FRAME_COUNT)))
# 释放并关闭窗口
video.release()
cv.destroyAllWindows()
关于if __name__ == '__main__'
的解释点此查看
2.3.2 摄像头的直接调用 cv.VideoCapture()
函数原型:<VideoCapture object> = cv.VideoCapture(index [, apiPreference])
index
:摄像头的索引号,0表示使用计算机的默认摄像头apiPreference
:读取数据时设置的属性
示例代码与2.3.1基本相同,另可以在cv.imshow('Video', frame)
前添加frame = cv.flip(frame, 1)
对摄像头拍摄的图像进行水平翻转,翻转后的视频为镜像,若不添加上述代码也可,视频为非镜像状态。
2.4 数据的保存
2.4.1 保存图像 cv.imwrite()
函数原型:retval = cv.imwrite(filename, img [, params])
filename
:图像保存的路径和文件名,包含图像格式img
:将要保存的图像(Array类型的数组)params
:保存图片格式时的属性设置标志
如果成功保存,返回True,失败返回False
函数第三个参数一般不需要填写,第三个参数的设置方式如下:
# 将img以等级为95的图像质量保存
cv.imwrite(filename, img, [int(cv.IMWRITE_JPEG_QUALITY), 95])
# 将img以值为6的压缩级别进行保存
cv.imwrite(filename, img, [int(cv.IMWRITE_PNG_COMPRESSION), 6])
第三个参数的可选择标志见P33表2-5
2.4.2 保存视频 cv.VideoWriter()
函数原型:
<VideoWriter object> = cv.VideoWriter()
<VideoWriter object> = cv.VideoWriter(filename, fourcc, fps, frameSize [, isColor])
filename
:保存视频的路径和文件名fourcc
:压缩帧的4字符编/解码器选项fps
:保存视频的帧率,即每秒多少张图像frameSize
:视频帧的大小isColor
:表示是否以彩色形式保存视频,默认为彩色
第一行的VideoWriter函数与VideoCapture函数相同,后续需要通过open()
函数设置保存的文件名称等参数。
fourcc
参数可以设置的编解码器选项见P35表2-6,如果赋值为“-1”则会自动搜索合适的编解码器。
frameSize
参数一定要与图像的尺寸相同。
示例代码如下:
import cv2 as cv
if __name__ == '__main__':
# 设置编/解码方式
fourcc = cv.VideoWriter_fourcc(*'DIVX')
# 采用默认摄像头获取图像
video = cv.VideoCapture(0)
# cv.VideoWriter()第一种构造函数(两种方法效果相同)
# result = cv.VideoWriter()
# result.open('./videos/Save_video.avi', fourcc, 20.0, (640, 480))
# cv.VideoWriter()第二种构造函数
result = cv.VideoWriter('./videos/Save_video.avi', fourcc, 20.0, (640, 480))
# 判断是否成功创建视频流
while video.isOpened():
ret, frame = video.read()
if ret is True:
# 将每一帧图像进行水平翻转
frame = cv.flip(frame, 1)
# 将一帧一帧图像写入视频
result.write(frame)
cv.imshow('Video', frame)
cv.waitKey(25)
# 键盘按下q退出
if cv.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# 释放并关闭窗口
video.release()
result.release()
cv.destroyAllWindows()
2.4.3 保存和读取XML和YMAL文件 cv.FileStorage()
2.4.3.1 保存
首先进行初始化
函数原型:<FileStorage object> = cv.FileStorage(filename, flags [, encoding])
filename
:打开的文件名称flags
:对文件执行的操作类型标志(详见P37表2-7)encoding
:编码格式
该函数用于声明打开的文件名称和操作的类型。
filename
为字符串类型,文件的扩展名可以是“.xml”“.ymal”“.yml”。
flags
参数表示对文件执行读取操作、写入操作等。
打开文件后,可以使用isOpened()
来判断是否成功打开文件,成功打开返回True,打开失败返回False。
若cv.FileStorage()
函数中没有声明参数,可通过open()
函数单独声明,函数原型如下:
retval = cv.FileStorage.open(filename, flags [, encoding])
filename
:打开的文件名称flags
:对文件执行的操作类型标志(详见P37表2-7)encoding
:编码格式
成功打开文件后,使用cv.FileStorage.write()
函数将数据写入文件中,函数原型如下:
None = cv.FileStorage.write(name, val)
name
:写入文件中的变量名称val
:变量值(目前支持实数、字符串和矩阵)
2.4.3.2 读取
- 读取实数型
file.getNode('x').real()
- 读取字符串型
file.getNode('x').string()
- 读取矩阵型
file.getNode('x').mat()
对2.4.3的示例代码:
import cv2 as cv
import numpy as np
if __name__ == '__main__':
# 创建FileStorage对象file,用于写入数据
# 读者可以尝试将文件后缀名改为.yml或.yaml
# file = cv.FileStorage('./data/MyFile.yml', cv.FileStorage_WRITE)
# file = cv.FileStorage('./data/MyFile.yaml', cv.FileStorage_WRITE)
file = cv.FileStorage('./data/MyFile.xml', cv.FileStorage_WRITE)
# 写入数据
file.write('name', '张三')
file.write('age', 16)
file.write('date', '2019-01-01')
scores = np.array([[98, 99], [96, 97], [95, 98]])
file.write('scores', scores)
# 释放对象
file.release()
# 创建FileStorage对象file1,用于读取数据
file1 = cv.FileStorage('./data/MyFile.xml', cv.FileStorage_READ)
# 判断MyFile.xml文件是否成功打开
if file1.isOpened():
# 读取数据
name1 = file1.getNode('name').string()
age1 = file1.getNode('age').real()
date1 = file1.getNode('date').string()
scores1 = file1.getNode('scores').mat()
# 展示读取结果
print('姓名:{}'.format(name1))
print('年龄:{}'.format(age1))
print('记录日期:{}'.format(date1))
print('成绩单:{}'.format(scores1))
else:
print('Can\'t open MyFile.xml.')
# 释放对象
file1.release()
第3章 图像基本操作
3.1 颜色空间
3.1.1.6 不同颜色空间之间的互相转换 cv.cvtColor()
函数原型:dst = cv.cvtColor(src, code, [, dst [, dstCn]])
src
:待转换颜色空间的原始图像code
:颜色空间转换的标志(详见P44表3-1)dst
:颜色空间转换后的目标图像dstCn
:目标图像中的通道数,默认为0
3.1.2 多通道分离与合并 cv.split()/cv.merge()
3.1.2.1 分离 cv.split()
函数原型:mv = cv.split(m [, mv])
m
:待分离的多通道图像mv
:分离后的单通道图像
3.1.2.2 合并 cv.merge()
函数原型:dst = cv.merge(mv [, dst])
mv
:需要合并的图像dst
:合并后输出的图像
3.2 图像像素的操作
3.2.1 图像像素统计
3.2.1.1 寻找图像像素的最大值与最小值 cv.minMaxLoc()
函数原型:
minVal, maxVal, minLoc, maxLoc = cv.minMaxLoc(src [, mask])
src
:需要寻找最大值和最小值的图像(图像可表示为矩阵)mask
:图像掩模(用于在图像的指定区域内寻找最值,默认值为None,表示寻找范围为整个图像)minVal
:图像中的最小值maxVal
:图像中的最大值minLoc
:图像中的最小值在矩阵中的坐标maxLoc
:图像中的最大值在矩阵中的坐标
若图像中存在多个最值,则输出的最值位置为按行扫描从左至右第1次检测到的最值位置
3.2.1.1.1 图像矩阵形状调整函数 np.reshape()
函数原型:dst = np.reshape(array, shape [, order])
array
:需要调整尺寸和通道数的图像shape
:重塑后的矩阵的维度order
:读取/写入元素时的顺序
3.2.1.2 计算图像的均值和标准差 cv.mean()/cv.meanStdDev()
求均值函数原型:retal = cv.mean(src [, mask])
src
:待求均值的图像(其通道数为1~4的整数)mask
:图像掩模(不输出此参数时,表示取所有像素的均值)
同时求均值和标准差函数原型:
mean, stddev = cv.meanStdDev(src [, mean [, stddev [, mask]]])
src
:待求均值和标准差的图像mean
:图像每个通道的均值stddev
:图像每个通道的标准差mask
:图像掩模
3.2.2 两图像间的像素操作
3.2.2.1 两幅图像的比较运算 cv.max()/cv.min()
函数原型:
dst = cv.max(src1, src2 [, dst])
dst = cv.min(src1, src2 [, dst])
src1
:第1幅图像,可以是任意通道数的矩阵src2
:第2幅图像,尺寸、通道数及数据类型与第1个参数一致dst
:保留对应位置较大(较小)灰度值后的图像
判断每一个像素点,保留两幅图像中灰度值较大(较小)的像素点
3.2.2.2 两幅图像的逻辑运算 cv.bitwise_?()
函数原型:
与运算:dst = cv.bitwise_and(src1, src2 [, dst [, mask]])
或运算:dst = cv.bitwise_or(src1, src2 [, dst [, mask]])
异或运算:dst = cv.bitwise_xor(src1, src2 [, dst [, mask]])
非运算:dst = cv.bitwise_not(src [, dst [, mask]])
src1
:第1幅图像,可以是多通道图像数据src2
:第2幅图像,尺寸、通道数及数据类型与第1个参数一致dst
:逻辑运算输出结果mask
:掩模矩阵,用于设置图像或矩阵中逻辑运算的范围src
:输入的图像矩阵
ps:异或运算:相同为0,不相同为1
3.2.3 图像二值化
函数原型:retval, dst = cv.threshold(src, thresh, maxval, type [, dst])
src
:待二值化的图像,图像的数据类型只能是uint8或float32thresh
:二值化的阈值maxval
:二值化过程中的最大值。此参数只在两种二值化方法中发挥作用,但使用其他方法也需要输入此参数type
:选择图像的二值化方法的标志(可选择的标志见P57表3-2)dst
:二值化后的图像
局部自适应阈值的二值化函数原型:
dst = cv.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C [, dst])
src
:待二值化的图像,只能是8位单通道类型的图像maxValue
:二值化后的最大值,要求为非零数adaptiveMethod
:自适应确定阈值的方法,分为均值法(cv.ADAPTIVE_THRESH_MEAN_C
)和高斯法(cv.ADAPTIVE_THRESH_GAUSSIAN_C
)thresholdType
:选择图像二值化方法的标志,只能是cv.THRESH_BINARY
或cv.THRESH_BINARY_INV
blockSize
:自适应确定阈值的像素领域大小,一般取值为3、5、7C
:从平均值或者加权平均值中减去的常数,可正可负dst
:二值化后的图像,与输入图像具有相同的尺寸、数据类型
3.2.4 LUT cv.LUT()
函数原型:dst = cv.LUT(src, lut [, dst])
src
:输入的图像,仅支持8位lut
:256个灰度值的查找表dst
:输出图像
3.3 图像连接和图像变换
3.3.1 图像连接 cv.vconcat()/cv.hconcat()
图像垂直连接函数原型:dst = cv.vconcat(src [, dst])
src
:需要连接的图像(可以用矩阵表示)(要求均具有相同的长度、数据类型和通道数)dst
:连接后的图像(可以用矩阵表示)
图像水平连接函数原型:dst = cv.hconcat(src [, dst])
src
:需要连接的图像(可以用矩阵表示)(要求均具有相同的高度、数据类型和通道数)dst
:连接后的图像(可以用矩阵表示)
示例:img = cv.hconcat((img0, img1))
3.3.2 图像尺寸变换 cv.resize()
函数原型:dst = cv.resize(src, dsize [, dst [, fx [,fy [, interpolation]]]])
src
:输入的图像dsize
:输出图像的尺寸dst
:输出图像fx
:水平轴的比例因子,如果沿水平轴将图像放大为原来的2倍,则指定为2fy
:垂直轴的比例因子,如果沿垂直轴将图像放大为原来的2倍,则指定为2interpolation
:插值方法的标志(可以选择的标志见P66表3-3)
3.3.3 图像翻转变换 cv.flip()
函数原型:dst = cv.flip(src, flipCode [, dst])
src
:输入的图像flipCode
:翻转方式标志。数值大于0,绕y轴翻转;数值等于0,绕x轴翻转;数值小于0,绕两条轴翻转dst
:输出的图像
3.3.4 图像仿射变换(三点变换) cv.getRotationMatrix2D()/cv.warpAffine()/cv.getAffineTransform()
计算旋转矩阵的函数原型:retal = cv.getRotationMatrix2D(center, angle, scale)
center
:图像旋转的中心angle
:图像旋转的角度,正值代表逆时针旋转scale
:沿两条轴的缩放比例,可以实现旋转过程中的图像缩放。不需要缩放输入1
确定旋转矩阵后,进行仿射变换后实现图像的旋转。
仿射变换函数原型:
dst = cv.warpAffine(src, M, dsize [, dst [, flags [, borderMode [, borderValue]]]])
src
:输入的图像M
:2×3的变换矩阵(之前求得的旋转矩阵)dsize
:输出图像的尺寸dst
:放射变换后的输出图像,尺寸与dsize
相同flags
:插值方法的标志(详见P69表3-4)borderMode
:像素边界外推方法的标志borderValue
:填充边界使用的数值,默认为0
利用三点求变换矩阵函数原型:retval = cv.getAffineTransform(src, dst)
src
:原图像中3个像素的坐标dst
:目标图像中对应的3个像素的坐标
3.3.5 图像透视变换(四点变换) cv.getPerspectiveTransform()/cv.wrapPerspective()
利用四点求变换矩阵函数原型:retval = cv.getPerspectiveTransform(src, dst [, solveMethod)
src
:原图像中4个像素的坐标dst
:目标图像中对应的4个像素的坐标solveMethod
:选择计算透视变换矩阵方法的标志(详见P72表3-6),默认为最佳主轴元素的高斯消元法
透视变换矩阵函数原型dst = cv.wrapPerspective(src, M, dsize [, dst [, flags [, borderMode [, borderValue]]]])
src
:输入的图像M
:3×3的变换矩阵(之前求得的旋转矩阵)dsize
:输出图像的尺寸dst
:放射变换后的输出图像,尺寸与dsize
相同flags
:插值方法的标志(详见P69表3-4)borderMode
:像素边界外推方法的标志borderValue
:填充边界使用的数值,默认为0
3.3.6 极坐标变换
函数原型:dst = cv.warpPolar(src, dsize, center, maxRadius, flags [, dst])
src
:原图像dsize
:目标图像的大小center
:极坐标变换时极坐标在原图像中的原点maxRadius
:变换时边界圆的半径flags
:插值方法与极坐标映射方法的标志(插值方法见P66表3-3,极坐标映射方法见P74表3-7)dst
:极坐标变换后的输出图像