OpenCV基础
1. 窗口创建
OpenCV(open source computer vision library)是一个基于BSD许可(开源)发行的跨平台计算机视觉库 |
- OpenCV窗口创建函数:cv.namedWindow()
- OpenCV窗口大小重设:cv.resizeWindow()
- 实验代码
import cv2 as cv
# 创建窗口(窗口大小自动)
cv.namedWindow('new', cv.WINDOW_AUTOSIZE)
# cv.WINDOW_AUTOSIZE不支持重设窗口大小
cv.imshow('new', 0)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
- 实验代码
import cv2 as cv
# cv.WINDOW_NORMAL支持窗口大小重新设置
cv.namedWindow('new', cv.WINDOW_NORMAL)
cv.resizeWindow("new", 640, 480)
cv.imshow('new', 0)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
2. 图像读取
- 图像读取:cv.imread(图片路径)
OpenCV读取的图像格式是BGR(不是RGB)
图像显示:imshow(窗口命名, 读取的图片)
waitKey()函数:等待用户触发函数waitKey(0) 函数无限长,等待用户按下任意键后继续执行(返回按键ASCII码)
waitKey(5000) 函数等待5000ms后自动关闭窗口(期间用户可按下任意键,返回按键ASCII码),返回-1
此函数容易导致Python无响应,需加上destroyAllWindows()函数
destroyAllWindows()删除窗口
- 拓展:Python中计算ASCII码的函数ord(‘字符’)
- 实验代码
# 图像读取
import cv2 as cv
img = cv.imread('../picture/08.jpg')
cv.imshow("img", img)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
cv.imread()的三种读取模式
cv.IMREAD_COLOR:读取彩色图像,任何图像的透明度都会被忽略(OpenCV默认模式)(1)
cv.IMREAD_GRAYSCALE:以灰度模式加载图像(亦可以直接给0)
cv.IMREAD_UNCHANGED:被读取的图像,包括 alpha 通道(-1)
- 实验代码
# 图像读取
import cv2 as cv
import numpy as np
# 彩色图cv.IMREAD_COLOR等价于1
img_color = cv.imread('../picture/08.jpg', cv.IMREAD_COLOR)
# 灰度图cv.IMREAD_GRAYSCALE等价于0
# cv.cvtColor转化为三通道
img_gray = cv.cvtColor(cv.imread('../picture/08.jpg', 0), cv.COLOR_GRAY2RGB)
# 包含alpha通道的彩色图cv.IMREAD_UNCHANGED等价于-1
img_unchanged = cv.imread('../picture/08.jpg', cv.IMREAD_UNCHANGED)
# 拼接显示
imgs = np.hstack((img_color, img_gray, img_unchanged))
cv.imshow("img", imgs)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
3. OpenCV图像基本操作
3.1 颜色转换cv.cvtColor()
OpenCV中的颜色转换模型:RGB模型、HSV模型、Lab模型、YUV模型、GRAY模型等 |
- RGB模型: OpenCV (BGR) --蓝色(Blue),绿色(Green),红色(Red)
- HSV模型:HSV模型更加符合人类感知颜色的方式(颜色、深浅以及亮暗)–色度(Hue),饱和度(Saturation),亮度(Value)
- Lab生理特征的颜色模型:L表示亮度(Luminosity),a和b是两个颜色通道,两者的取值区间都是由-128到+127,其中a通道数值由小到大对应的颜色是从绿色变成红色,b通道数值由小到大对应的颜色是由蓝色变成黄色,颜色空间为一个球体
- YUV模型:电视信号系统所采用的颜色编码方式–亮度(Y),红色分量与亮度的信号差值(U),蓝色与亮度的差值(V)
- GRAY灰度图像的模型:灰度图像只有单通道,灰度值根据图像位数不同由0到最大依次表示由黑到白(相同尺寸相同压缩格式所占容量小,易于采集,便于传输)
- 实验代码
# 查看颜色转换方式
import cv2 as cv
print("OpenCV版本", cv.__version__)
flags = [i for i in dir(cv) if i.startswith('COLOR_')]
print("颜色转换方式总数:", len(flags), "\n", flags)
- 实验结果
3.2 1/3灰度级图像(灰度图像)
- 实验代码
import cv2 as cv
import numpy as np
# 灰度图像(各个像素值的1/3)
ratio = 1.0 / 3.0
img = cv.imread('../picture/08.jpg')
# 数据类型转换
int32_img = img.astype(np.int32)
# 将各个通道的数据除以1/3叠加后转换成uint8即可得到灰度图像
img_gray = (ratio * (int32_img[..., 0] + int32_img[..., 1] + int32_img[..., 2])).astype(np.uint8)
cv.imshow('gray', img_gray)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
4. 像素操作
OpenCV(open source computer vision library)彩色图像(h * w * c的矩阵)--h为图像高(相当于矩阵的行),w为图像宽(相当于矩阵列),c为通道数 |
- 实验代码
import cv2 as cv
import numpy as np
img = cv.imread("../picture/08.jpg")
h, w, c = img.shape
# 图像基本属性
print("图像高:", h, "\n图像宽:", w, "\n通道数(RGB三通道):", c)
print("图像大小(像素总数:h*w*c)=", img.size)
print("像素数据类型:", img.dtype)
# 访问单像素单个通道值
print("访问第99(从0开始)行,99列R通道值:", img.item(100, 100, 2))
# 修改值
img.itemset((100, 100, 2), 100)
print("第99行,99列R通道值(修改后):", img.item(100, 100, 2))
- 实验结果
4.0 图像通道拆分
当使用OpenCV的 imshow(某通道) 函数,默认三通道相同,即查看R通道时为imshow(R,G,B) 实际为 imshow(R,R,R)–> 三个通道值相同时,显示为灰度图
合并出红色通道的图:merge(R, 零矩阵, 零矩阵)
- 实验代码
import cv2 as cv
import numpy as np
img = cv.imread("../picture/08.jpg")
# 通道拆分合并
B, G, R = cv.split(img)
# 创建与img相同大小的零矩阵
zeros = np.zeros(img.shape[:2], dtype="uint8")
# 图像拼接显示
imgs = np.hstack((cv.merge([B, zeros, zeros]),
cv.merge([zeros, G, zeros]),
cv.merge([zeros, zeros, R])))
cv.imshow("imgs", imgs)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
5. 图像几何变换
5.1 resize缩放
缩放即调整图片的大小,属于广义上的仿射变换,包括平移(transform)、旋转(rotate)等 |
cv.resize() 函数(指定缩放后的图像大小)
cv2.resize(InputArray src, OutputArray dst, Size, fx, fy, interpolation)
参数 | 含义 |
---|---|
InputArray src | 输入原图 |
OutputArray dst | 输出图像(一般不传参或者设成 None) |
Size | 输出图像尺寸 |
fx, fy | x 和 y 方向上的缩放比例 |
interpolation | 插值方式表示代码(int 数值,一般用 OpenCV 内置的参数代号以提高可读性) |
- 实验代码
import cv2 as cv
img = cv.imread('../picture/03.jpg')
print("原图大小:", img.shape)
cv.imshow("img", img)
"""
fx, fy为缩放比例(0.5倍(缩小为原图的一半),2倍放大)
"""
dst = cv.resize(img,None,fx=0.5, fy=0.5, interpolation = cv.INTER_CUBIC)
print("长宽缩小为原图1/2(仅取整数):", dst.shape)
# 显示图像
cv.imshow("dst" , dst)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
原图大小: (675, 1200, 3)
长宽缩小为原图1/2(仅取整数): (338, 600, 3)
5.2 warpAffine仿射变换
仿射变换(Affine Transformation) 在向量空间中进行一次线性变换(乘以一个矩阵)和一次平移(加上一个向量),变换到另一个向量空间的过程(线性变换和平移变换的叠加) 性质不变性: (1)凸性 (2)共线性:若几个点变换前在一条线上,则仿射变换后仍然在一条线上 (3)平行性:若两条线变换前平行,则变换后仍然平行 (4)共线比例不变性:变换前一条线上两条线段的比例,在变换后比例不变 |
- cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
参数 | 含义 |
---|---|
src | 输入原图 |
M | 变换矩阵 (2*3的矩阵) |
dsize | 输出图像大小 |
flags | 插入值方法(int 类型) |
borderMode | 边界像素模式(int) |
borderValue | 边界填充值 |
flages方式: 默认flags=cv2.INTER_LINEAR(线性插值) cv2.INTER_NEAREST(最近邻插值) cv2.INTER_AREA (区域插值) cv2.INTER_CUBIC(三次样条插值) cv2.INTER_LANCZOS4(Lanczos插值) |
获取仿射变换矩阵
- cv2.getAffineTransform(pts1,pts2) 函数
参数 | 含义 |
---|---|
pts1 | 选取的原图像的三个点坐标 |
pts2 | 变换后相应三个点的坐标 |
- 实验代码
import cv2 as cv
import numpy as np
img = cv.imread('../picture/14.jpg')
height, width = img.shape[:2]
# 在原图像和目标图像上各选择三个点
src = np.float32([[0, 0], [0, height], [width, 0]])
dst = np.float32([[0, 0], [100, height - 100], [width - 100, 100]])
# 得到变换矩阵
transform = cv.getAffineTransform(src, dst)
print("变换矩阵M:", transform.shape)
# 进行仿射变换
dst = cv.warpAffine(img, transform, (width, height))
# 显示
imgs = np.hstack([img, dst])
cv.imshow("imgs", imgs)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
5.2.1 仿射变换 平移(transform)
- 实验代码
import cv2 as cv
import numpy as np
img = cv.imread('../picture/13.jpg')
# 获取图像的长宽
height, width = img.shape[:2]
# 平移指定像素(向右,向下各平移50像素)
tx, ty = 50, 50
# 创建平移矩阵
translation_matrix = np.array([[1, 0, tx], [0, 1, ty]], dtype=np.float32)
# 将平移应用于图像
translated_img = cv.warpAffine(src=img,
M=translation_matrix,
dsize=(width, height))
print("原图大小:", img.shape)
print("平移后的大小:", translated_img.shape)
imgs = np.hstack((img, translated_img))
cv.imshow('imgs', imgs)
cv.waitKey(0)
- 实验结果
原图大小: (519, 533, 3)
平移后的大小: (519, 533, 3)
5.2.2 仿射变换 旋转(rotation)
以图像的中心为原点,旋转一定的角度(图像上的所有像素都将旋转一个相同的角度) |
① 构建旋转矩阵进行任意角度旋转getRotationMatrix2D()
- cv2.getRotationMatrix2D(center, angle, scale)
参数 | 含义 |
---|---|
center | 图片的旋转中心 |
angle | 旋转角度 |
scale | 缩放比例 |
scale 0.5表示缩小为原来的一半,也能表示旋转方向,正数表示逆时针,负数表示顺时针旋转
- 实验代码
import cv2 as cv
import numpy as np
img = cv.imread('../picture/14.jpg')
rows, cols = img.shape[:2]
# 构建旋转矩阵(逆时针旋转45度,且缩小为原图的一半)
M = cv.getRotationMatrix2D((cols / 2.0, rows / 2.0), 45, -0.5)
img_rotate = cv.warpAffine(img, M, (cols, rows), borderValue=(0, 0, 0))
imgs = np.hstack((img, img_rotate))
cv.imshow('imgs', imgs)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
② 利用图像矩阵进行转置特定旋转transpose
- cv2.transpose( src[, dst] )
参数 | 含义 |
---|---|
src | 要转置矩阵的图像 |
dst | 与原图像大小和深度相同的输出图像 |
- 即只进行图像矩阵的行列转换
- 实验代码
import cv2 as cv
import numpy as np
img = cv.imread('../picture/14.jpg')
# 只对图像(矩阵)进行转置(行列变换),使用不灵活
img_transpose = cv.transpose(img)
print("原图尺寸:", img.shape)
print("进行转置:", img_transpose.shape)
cv.imshow('img_transpose', img_transpose)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
③ 图像翻转flip
- cv2.flip(filename, flipcode)
参数 | 含义 | ||
filename | 要操作的图像 | ||
flipcode | 翻转方式 | 1 | 水平翻转 |
0 | 垂直翻转 | ||
-1 | 水平垂直翻转 |
- 实验代码
# 利用翻转函数旋转
import cv2 as cv
import numpy as np
img = cv.imread('../picture/14.jpg')
# 翻转
img_flip = cv.flip(img, 1)
imgs = np.hstack((img, img_flip))
cv.imshow('imgs', imgs)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果
5.3 warpPerspective透视变换
仿射变换可以将矩形映射为任意平行四边形,透视变换可以将任意四边形映射成矩形 |
- cv2.warpPerspective(src, M, dsize, [, flags[, borderMode[, borderValue]]])
参数 | 含义 |
---|---|
src | 输入原图 |
M | 变换矩阵 (3*3的矩阵) |
dsize | 输出图像大小 |
flags | 插入值方法(int 类型) |
borderMode | 边界像素模式(int) |
borderValue | 边界填充值 |
获取透视矩阵
- cv2.getPerspectiveTransform(src, dst) 函数
src表示输入图像的四个顶点坐标
dst表示输出图像的四个顶点坐标
- 实验代码
import cv2 as cv
import numpy as np
img = cv.imread('../picture/14.jpg')
height, width = img.shape[:2]
# 得到变换矩阵
transform = cv.getAffineTransform(np.float32([[0, 0], [0, height], [width, 0]]),
np.float32([[0, 0], [100, height - 100], [width - 100, 100]]))
# 进行仿射变换
img_affine = cv.warpAffine(img, transform, (width, height), borderValue=(255, 255, 255))
# 左上角,右上角,左下角,右下角
p1 = np.float32([[0, 0],
[width - 100, 100],
[100, height - 100],
[width, height]])
p2 = np.float32([[0, 0],
[width, 0],
[0, height],
[width, height]])
# 生成透视矩阵
M = cv.getPerspectiveTransform(p1, p2)
img_perspective = cv.warpPerspective(img_affine, M, (width, height))
cv.imshow('img', img)
cv.imshow('img_affine', img_affine)
cv.imshow('img_perspective', img_perspective)
cv.waitKey(0)
cv.destroyAllWindows()
- 实验结果