OpenCV
窗口显示¶
namedWindow(winname[, flags]) -> None
若该名窗口不存在,则创建一个新窗口flags
: 默认为cv2.WINDOW_AUTOSIZE
或cv2.WINDOW_KEEPRATIO
或cv2.WINDOW_GUI_EXPANDED
WINDOW_NORMAL
允许任意调节窗口大小,WINDOW_AUTOSIZE
自动调整为图片大小且不可改变WINDOW_FREERATIO
允许改变窗口长宽比例,WINDOW_KEEPRATIO
保持窗口比例不变WINDOW_GUI_NORMAL
窗口没有状态栏和工具栏,WINDOW_GUI_EXPANDED
使用新的增强 GUI
destroyWindow(winname) -> None
摧毁指定名字的窗口,若不存在则报错destroyAllWindows() -> None
摧毁所有窗口
imshow(winname, mat) -> None
会自动创建窗口,必须跟随waitKey()
或pollKey()
waitKey([, delay]) -> retval
等待按键并返回按键编码,或等待delay
个毫秒并返回 -1
图像处理¶
图像属性¶
im.dtype
数据类型im.itemsize
每个元素的字节数im.size
总元素数im.nbytes
所占字节数,等于 im.itemsize * im.sizeim.shape
格式为 (行数, 列数, 通道数)im.ndim
数组维数,等于 len(im.shape)
基本 I/O¶
imread(filename[, flags]) -> retval
- 通过文件内容决定图像格式,而不是扩展名
flags
: 默认为cv2.IMREAD_COLOR
IMREAD_COLOR
: 用 BGR 模式加载图像,透明度会被忽略IMREAD_GRAYSCALE
: 用灰度模式加载图像IMREAD_UNCHANGED
: 若包含 alpha 通道则会保留
imwrite(filename, img) -> retval
- 通过文件扩展名决定图像保存格式
- 若保存成功,则返回 True
算术操作¶
- 若数据类型为
CV_8U
,则使用+
-
*
运算符会对结果进行求模 - 当使用
mask
时,运算只会在掩膜的非零值处发生,其余会被置零
加减运算
add(src1, src2[, dst[, mask[, dtype]]]) -> dst
- dst = saturate(src1 + src2)
src1
src2
: 数组或标量,标量的形式只能为一个数或一个四元组。若为四元组,则参与运算的元素由图像通道数决定mask
: 类型需为CV_8UC1
或CV_8SC1
dtype
: 输出数组的数据类型
subtract(src1, src2[, dst[, mask[, dtype]]]) -> dst
- dst = saturate(src1 - src2)
addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) -> dst
- dst = saturate(src1 * alpha + src2 * beta + gamma)
位运算
bitwise_not(src[, dst[, mask]]) -> dst
非运算bitwise_and(src1, src2[, dst[, mask]]) -> dst
与运算bitwise_or(src1, src2[, dst[, mask]]) -> dst
或运算bitwise_xor(src1, src2[, dst[, mask]]) -> dst
异或运算src1
src2
: 数组或标量,标量的形式只能为一个数或一个元组。若为元组,则元素数可为 1 或 4 或通道数。在参与运算前,标量会先转换为图像的数据类型mask
: 类型只能为单通道整数数组
颜色转换¶
split(m[, mv]) -> mv
merge(mv[, dst]) -> dst
m
: 多通道图像mv
: 由单通道图像组成的元组,每个单通道图像的大小和深度相同
b, g, r = cv2.split(im)
out = cv2.merge([r, g, b])
cvtColor(src, code[, dst[, dstCn=0]]) -> dst
- 若图像新增一个 alpha 通道,则通道值会被设为该数据类型的最大值,即 CV_8U - 255,CV_16U - 65535,CV_32F - 1
src
: 类型仅能为CV_8U
CV_16U
或CV_32F
code
: 转换码,可为cv2.COLOR_BGR2RGB
cv2.COLOR_GRAY2BGR
等dstCn
: 输出图像的通道数,若为 0,则从输入图像和转换码推断出来
阈值处理¶
threshold(src, thresh, maxval, type[, dst]) -> retval, dst
thresh
: 阈值maxval
: 最大值,在某些阈值处理方法中会用到type
: 阈值处理方法
阈值处理方法有以下几种:
cv2.THRESH_BINARY
:
\[\texttt{dst}(x,y) = \left\{ \begin{aligned} & \texttt{maxval} & \texttt{if src(x,y) > thresh} \\ & \texttt{0} & \texttt{otherwise} \end{aligned} \right.\]
cv2.THRESH_BINARY_INV
:
\[\texttt{dst}(x,y) = \left\{ \begin{aligned} & \texttt{0} & \texttt{if src(x,y) > thresh} \\ & \texttt{maxval} & \texttt{otherwise} \end{aligned} \right.\]
cv2.THRESH_TRUNC
:
\[\texttt{dst}(x,y) = \left\{ \begin{aligned} & \texttt{threshold} & \texttt{if src(x,y) > thresh} \\ & \texttt{src(x, y)} & \texttt{otherwise} \end{aligned} \right.\]
cv2.THRESH_TOZERO
:
\[\texttt{dst}(x,y) = \left\{ \begin{aligned} & \texttt{src(x, y)} & \texttt{if src(x,y) > thresh} \\ & \texttt{0} & \texttt{otherwise} \end{aligned} \right.\]
cv2.THRESH_TOZERO_INV
:
\[\texttt{dst}(x,y) = \left\{ \begin{aligned} & \texttt{0} & \texttt{if src(x,y) > thresh} \\ & \texttt{src(x, y)} & \texttt{otherwise} \end{aligned} \right.\]
几何变换¶
调整尺寸¶
resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) -> dst
dsize
: 输出图像尺寸,格式为 (宽度, 高度)。若为 None,则从 fx 和 fy 计算出来fx
: x 轴缩放因数fy
: y 轴缩放因数interpolation
: 插值方法,默认为cv2.INTER_LINEAR
cv2.INTER_NEAREST
最近邻插值cv2.INTER_LINEAR
双线性插值cv2.INTER_CUBIC
双立方插值,放大图像时效果最好cv2.INTER_AREA
区域插值,缩小图像时效果最好
cv2.resize(src, (1920, 1080), interpolation=cv2.INTER_CUBIC)
cv2.resize(src, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
翻转¶
flip(src, flipCode[, dst]) -> dst
翻转图像flipCode
: 翻转码- 若为 0,则上下翻转
- 若为正整数,则左右翻转
- 若为负整数,则上下翻转和左右翻转同时进行
仿射变换¶
warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) -> dst
对图像应用变换矩阵:(\(\begin{aligned} \texttt{dst}(x,y) = \texttt{src} \left(M_{11}x + M_{12}y + M_{13}, M_{21}x + M_{22}y + M_{23} \right.) \end{aligned}\)\)M
: \(2\times 3\) 变换矩阵dsize
: 输出图像的尺寸,格式为 (宽度, 高度)flags
: 插值方法或标志cv2.WARP_INVERSE_MAP
,代表逆变换borderMode
: 像素外推方法,默认为cv2.BORDER_CONSTANT
cv2.BORDER_CONSTANT
:iiiiii|abcdefgh|iiiiiii
cv2.BORDER_REPLICATE
:aaaaaa|abcdefgh|hhhhhhh
cv2.BORDER_REFLECT
:fedcba|abcdefgh|hgfedcb
cv2.BORDER_WRAP
:cdefgh|abcdefgh|abcdefg
cv2.BORDER_TRANSPARENT
:uvwxyz|abcdefgh|ijklmno
cv2.BORDER_REFLECT_101
cv2.BORDER_REFLECT101
cv2.BORDER_DEFAULT
:gfedcb|abcdefgh|gfedcba
borderValue
: 在cv2.BORDER_CONSTANT
中作为边界外像素值,默认为 0
-
getRotationMatrix2D(center, angle, scale) -> retval
计算得到一个 2D 旋转仿射矩阵:\[\alpha = \texttt{scale} \cdot \cos{\texttt{angle}} \\ \beta = \texttt{scale} \cdot \sin{\texttt{angle}} \\ \begin{bmatrix} \alpha & \beta & (1-\alpha) \cdot \texttt{center.x} - \beta \cdot \texttt{center.y} \\ \beta & \alpha & \beta \cdot \texttt{center.x} + (1-\alpha) \cdot \texttt{center.y} \end{bmatrix}\]center
: 旋转中心,格式为 (x, y)angle
: 旋转角度,正数为逆时针方向scale
: 缩放因数
getAffineTransform(src, dst) -> retval
用三对点计算得到仿射矩阵src
: \(3\times 2\) 矩阵,存放源图像的三对点dst
: \(3\times 2\) 矩阵,存放目标图像的三对点
def rotate(src, center, angle, scale=1, color=0):
h, w = src.shape[:2]
bound_h = scale * (h * abs(np.cos(angle * np.pi / 180)) +
w * abs(np.sin(angle * np.pi / 180)))
bound_w = scale * (h * abs(np.sin(angle * np.pi / 180)) +
w * abs(np.cos(angle * np.pi / 180)))
M = cv2.getRotationMatrix2D(center, angle, scale)
M[0, 2] += (bound_w - w) / 2
M[1, 2] += (bound_h - h) / 2
size = (int(bound_w), int(bound_h))
dst = cv2.warpAffine(src, M, size, borderValue=color)
return dst
def translate(src, x, y, color=0):
M = np.array([[1.0, 0, x],
[0, 1.0, y]])
h, w = src.shape[:2]
bound_h = h + y if y > 0 else h
bound_w = w + x if x > 0 else w
size = (int(bound_w), int(bound_h))
dst = cv2.warpAffine(src, M, size, borderValue=color)
return dst
透视变换¶
-
warpPerspective(src, M, dsize[,dst[, flags[, borderMode[, borderValue]]]]) -> dst
对图像应用变换矩阵:\[\begin{aligned} \texttt{dst}(x,y) = \texttt{src}\left( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}}, \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right) \end{aligned}\]M
: \(3\times 3\) 变换矩阵dsize
: 输出图像的尺寸
getPerspectiveTransform(src, dst) -> retval
用四对点计算得到投影矩阵src
: \(4\times 2\) 矩阵,存放源图像的四对点dst
: \(4\times 2\) 矩阵,存放目标图像的四对点
重映射¶
-
remap(src, map1, map2, interpolation[, dst[, borderMode[, borderValue]]]) -> dst
对图像应用通用几何变换:\[\texttt{dst}(x,y) = \texttt{src}(map_x(x,y), map_y(x,y))\]map1
: 第一个映射,返回值为 (x,y) 点或 x 值,类型为CV_16SC2
CV_32FC1
或CV_32FC2
map2
: 第二个映射,返回值为 y 值,类型为CV_16UC1
CV_32FC1
或 Noneinterpolation
: 插值方法
图像滤波¶
通用滤波¶
filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) -> dst
用卷积核对图像进行卷积ddepth
: 输出图像的深度,若为 -1 则与输入相同kernel
: 卷积核anchor
: 指定卷积核内的滤波点的相对位置,应该位于卷积核内,默认值为 (-1, -1),表示在内核中心delta
: 结果加上的值cv2.filter2D(src, -1, kernel)
cv2.filter2D(src, -1, kernel, delta=5)
平滑图像¶
-
blur(src, ksize[, dst[, anchor[, borderType]]]) -> dst
均值滤波\[K = \frac{1}{width * height} \begin{bmatrix} 1 & 1 & \cdots & 1 \\ 1 & 1 & \cdots & 1 \\ \vdots & \vdots & \ddots & \vdots \\ 1 & 1 & \cdots & 1 \\ \end{bmatrix}\]ksize
: 卷积核的尺寸,可以为任意二元组anchor
: 锚点,默认值为 (-1, -1),指卷积核中点borderType
: 像素外推方法
-
boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]]) -> dst
方框滤波\[K = \alpha \begin{bmatrix} 1 & 1 & \cdots & 1 \\ 1 & 1 & \cdots & 1 \\ \vdots & \vdots & \ddots & \vdots \\ 1 & 1 & \cdots & 1 \\ \end{bmatrix} \\~\\ \alpha = \left\{ \begin{aligned} &\frac{1}{width * height} &\text{when normalize=true} \\ &1 &\text{otherwise} \\ \end{aligned} \right. \]ddepth
: 输出图像的深度,若为 -1 则与输入相同ksize
: 卷积核的尺寸,可以为任意二元组normalize
: 指定是否规范化,默认为 True
GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst
高斯滤波ksize
: 高斯核的尺寸,宽和高必须全为奇数。若全为零,则会从 sigma 算出sigmaX
: x 方向的高斯标准差sigmaY
: y 方向的高斯标准差,若为零则与 sigmaX 相等,若全为零则会从 ksize 算出
getGaussianKernel(ksize, sigma[, ktype]) -> retval
- 返回一个大小为 \(\texttt{ksize}\times 1\) 的矩阵,存放高斯滤波器的系数
ksize
: 孔径的宽高,必须为一个大于 0 的奇数sigma
: 高斯标准差,若非正数,则等于 0.3 * ((ksize - 1) * 0.5 - 1) + 0.8- 若想得到 \(\texttt{ksize} \times \texttt{ksize}\) 的 2D 高斯核,可以使用
kernel = cv2.getGaussianKernel(ksize, 0); kernel = kernel * kernel.T
medianBlur(src, ksize[, dst]) -> dst
中值滤波ksize
: 孔径的宽高,必须为一个大于 1 的奇数- 对边界像素,会使用
cv2.BORDER_REPLICATE
bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst
双边滤波d
: 像素邻域的直径,若非正则会从 sigmaSpace 算出sigmaColor
: 颜色空间中的标准差,值越大,像素邻域内更远的颜色将混合在一起sigmaSpace
: 坐标空间中的标准差,值越大,更远的像素将相互影响。当 d > 0 时,d 指定了邻域的大小,sigmaSpace 不起作用,否则 d 与 sigmaSpace 成比例
边缘检测¶
-
Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]) -> dst
用扩展 Sobel 运算符,计算图像的指定阶导数\[\texttt{dst} = \frac{\partial^{dx+dy} \texttt{src}}{\partial x^{dx} \partial y^{dy}} \]dx
: x 方向的导数的阶dy
: y 方向的导数的阶ksize
: 卷积核的尺寸,只能为 1, 3, 5 或 7,默认为 3。当 kernel = 1 时,实际尺寸为 \(3\times 1\) 或 \(1\times 3\)scale
: 缩放因数,默认为 1delta
: 偏移值,默认为 0cv2.Soble(src, -1, 1, 0)
使用的卷积核是 \(\begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix}\)
-
Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]]) -> dst
计算图像的拉普拉斯算子\[\texttt{dst} = \Delta \texttt{src} = \frac{\partial^{2} \texttt{src}}{\partial x^2} + \frac{\partial^{2} \texttt{src}}{\partial y^2} \]ksize
孔径的宽高,只能为大于 0 的奇数,默认为 1,此时使用的卷积核为 \(\begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \\ \end{bmatrix}\)
图像匹配¶
SIFT 算法¶
sift = cv2.SIFT_create()
keypoints = sift.detect(im)
keypoints, descriptors = sift.compute(im, keypoints)
keypoints, descriptors = sift.detectAndCompute(im, None)
SIFT 关键点的属性有:
pt
关键点坐标size
关键点邻域直径angle
关键点的方向response
关键点的响应强度,可用于后续排序octave
关键点所在的图像金字塔的层组class_id
用于聚类的 id
sift.detect(image[, mask]) -> keypoints
- keypoints[i] 为第 i 个关键点
- mask 指定了寻找关键点的区域
sift.detect(images[, masks]) -> keypoints
- keypoints[i] 为 image[i] 的关键点
- mask[i] 为 image[i] 的掩膜
描述符匹配¶
bf = cv2.BFMatcher_create()
matches = bf.match(descriptors1, descriptors2)
matches = bf.knnMatch(descriptors1, descriptors2, 2)
匹配的属性有
queryIdx
关键点在 keypoints1 中的索引trainIdx
关键点在 keypoints2 中的索引imgIdx
当前匹配点对应训练图像的索引distance
关键点之间的欧氏距离
match(queryDescriptors, trainDescriptors[, mask]) -> matches
- 对查询集中的每个描述符,找到 1 个最佳匹配项
queryDescriptors
: 查询描述符集trainDescriptors
: 训练描述符集matches
: 每一项都是对应查询点与其最佳匹配项的匹配
knnMatch(queryDescriptors, trainDescriptors, k[, mask[, compactResult]]) -> matches
- 对查询集中的每个描述符,找到 k 个最佳匹配项
matches
: 每一项都是一个列表,包含对应查询点与其 k 个最佳匹配项的匹配
绘制关键点与匹配¶
drawKeypoints(image, keypoints, outImage[, color[, flags]]) -> outImage
- 绘制一张图上的关键点
color
: 关键点的颜色,默认为随机选择out = cv2.drawKeypoints(im, kpts, None)
drawMatches(img1, keypoints1, img2, keypoints2, matches1to2, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]]) -> outImg
drawMatches(img1, keypoints1, img2, keypoints2, matches1to2, outImg, matchesThickness[, matchColor[, singlePointColor[, matchesMask[, flags]]]]) -> outImg
drawMatchesKnn(img1, keypoints1, img2, keypoints2, matches1to2, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]]) -> outImg
- 绘制两张图之间的匹配
out = cv2.drawMatches(im1, kpts1, im2, kpts2, matches, None)
视频¶
视频捕获¶
打开与关闭视频¶
VideoCapture(filename[, apiPreference]) -> retval
打开一个视频或一个捕获设备cap.isOpened() -> retval
检测是否打开成功cap.release() -> None
释放视频流
读取帧¶
cap.read([, image]) -> retval, image
读取一帧
获得与设置视频属性¶
cap.get(propId) -> retval
返回指定属性cap.set(propId, value) -> retval
设置指定属性
cv2.CAP_PROP_POS_MSEC
当前视频所在位置,以毫秒计cv2.CAP_PROP_POS_FRAMES
下一帧的索引,从零开始计cv2.CAP_PROP_POS_AVI_RATIO
当前视频的相对位置,0 代表开头,1 代表结尾cv2.CAP_PROP_FRAME_WIDTH
帧的宽度cv2.CAP_PROP_FRAME_HEIGHT
帧的高度cv2.CAP_PROP_FRAME_COUNT
帧的总数cv2.CAP_PROP_FPS
帧率cv2.CAP_PROP_FOURCC
编解码器的四字符代码
视频写入¶
创建与保存视频¶
VideoWriter(filename, fourcc, fps, frameSize, isColor=ture) -> retval
初始化视频写入器fourcc
: 用于压缩帧的编解码器的四字符代码,若为 -1,会列出所有可选项cv2.VideoWriter_fourcc(*"mp4v"/"avc1"/"avc3")
可用于 mp4 视频cv2.VideoWriter_fourcc(*"XVID"/"MJPG"/"h264")
可用于 avi 视频cv2.VideoWriter_fourcc(*"I420")
可用于.avi
未压缩视频
fps
: 帧率frameSize
: 帧的尺寸,格式为 (宽, 高),必须全为整数isColor
: 若非零,则会以彩色模式编码视频
video.isOpened() -> retval
检测是否初始化成功video.release() -> None
关闭视频写入器
写入帧¶
write(image) -> None
写入一帧,image 需为 BGR 模式且尺寸必须一致
绘制¶
矩形¶
rectangle(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) -> img
pt1
: 一个顶点pt2
: 另一个顶点color
: 颜色(RGB 模式)或亮度(灰度模式)thickness
: 线的厚度,负数意味着填满
文本¶
putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) -> img
org
: 文本的左下角位置fontFace
: 字体类型fontScale
: 缩放因数,用以乘上字体的基本大小color
: 文本颜色(RGB 模式)thickness
: 厚度lineType
: 线条类型bottomLeftOrigin
: 若为 True,则图像的数据原点设为左下角
lineType
cv2.LINE_4
4 连通线条(默认值),线条的像素相互连接cv2.LINE_8
8 连通线条,可以更精确地绘制斜线cv2.LINE_AA
抗锯齿线条,会进行平滑处理,使线条的边缘更柔和
fontFace
cv2.FONT_HERSHEY_SIMPLEX
普通大小的无衬线字体cv2.FONT_HERSHEY_PLAIN
小号无衬线字体cv2.FONT_HERSHEY_DUPLEX
普通大小的无衬线字体,更加复杂cv2.FONT_HERSHEY_COMPLEX
普通大小的衬线字体cv2.FONT_HERSHEY_TRIPLEX
普通大小的衬线字体,更加复杂cv2.FONT_HERSHEY_COMPLEX_SMALL
小号衬线字体cv2.FONT_HERSHEY_SCRIPT_SIMPLEX
手写风格字体cv2.FONT_HERSHEY_SCRIPT_COMPLEX
手写风格字体,更加复杂cv2.FONT_ITALIC
斜体字体标记