OpenCV-Python学习(八):图像的几何变换及形态学操作
2020-06-25 本文已影响0人
星光下的胖子
目录:
- 1.resize/transpose/flip
- 2.2.仿射变换(线性变换): 包括 平移、缩放、旋转、倾斜、翻转/镜像
- 3.透视变换(非线性变换): 一般用于矫正变形的图像
- 4.形态学操作:膨胀/腐蚀/开/闭/梯度/礼帽/黑帽
一、resize/transpose/flip
函数:
1)图像缩放: resize()函数
resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)
dsize: 输出图像的大小,如 Size(width, height)。
若dsize=0,则需指定fx和fy的值,且fx>0,fy>0。
此时, dsize = Size(round(fx*src.cols), round(fy*src.rows))
fx=0.5,fy=0.5与dsize=(cols//2, rows//2)效果一样。
interpolation: 指定插值的方式。图像缩放后,需要重新计算像素,这个参数指定重新计算像素的方式。
有以下几种插值类型:
INTER_LINEAR: 双线性插值(默认)
INTER_NEAREST: 最邻近插值
INTER_CUBIC: 基于4x4像素邻域内的三次样条插值
INTER_LANCZOS4: 基于8x8像素邻域内的Lanczos插值
2)转置: transpose()函数
transpose(src, dst=None)
3)翻转/镜像: flip()函数
flip(src, flipCode, dst=None)
flipCode: 控制翻转效果。
flipcode = 0:绕x轴翻转,即上下颠倒
flipcode > 0(如1):绕y轴翻转,翻转
flipcode < 0(如-1):绕x,y轴同时翻转,即上下+左右翻转
1.图片缩放——resize():
import cv2
img = cv2.imread("image/1.jpg")
rows, cols, channels = img.shape
# 图片缩放: resize()
resie_1 = cv2.resize(img, dsize=(cols // 2, rows //2))
resie_2 = cv2.resize(img, dsize=(0, 0), fx=2, fy=2)
# 几种插值方式:
# 1.双线性插值(默认)
linear = cv2.resize(img, dsize=(cols // 2, rows //2), interpolation=cv2.INTER_LINEAR)
# 2.最邻近插值
nearest = cv2.resize(img, dsize=(cols //2, rows //2), interpolation=cv2.INTER_NEAREST)
# 3.基于4x4像素邻域内的三次样条插值
cubic = cv2.resize(img, dsize=(cols//2, rows // 2), interpolation=cv2.INTER_CUBIC)
# 4.基于8x8像素邻域内的Lanczos插值
lanczos = cv2.resize(img, dsize=(cols//2, rows // 2), interpolation=cv2.INTER_LANCZOS4)
cv2.imshow("image", img)
cv2.imshow("resie_1", resie_1)
cv2.imshow("resie_2", resie_2)
cv2.imshow("linear", linear)
cv2.imshow("nearest", nearest)
cv2.imshow("cubic", cubic)
cv2.imshow("lanczos", lanczos)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.转置——transpose():
import cv2
src = cv2.imread("image/1.jpg")
dst = cv2.transpose(src)
cv2.imshow("src", src)
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.翻转/镜像——flip():
import cv2
src = cv2.imread("image/1.jpg")
# 翻转: flipCode用来控制翻转效果
dst1 = cv2.flip(src, flipCode=0) # flipCode=0:绕x轴翻转,即上下颠倒
dst2 = cv2.flip(src, flipCode=1) # flipcode>0:绕y轴翻转,翻转
dst3 = cv2.flip(src, flipCode=-1) # flipcode<0:绕x,y轴同时翻转,即上下+左右翻转
cv2.imshow("src", src)
cv2.imshow("dst1", dst1)
cv2.imshow("dst2", dst2)
cv2.imshow("dst3", dst3)
cv2.waitKey(0)
cv2.destroyAllWindows()
二、仿射变换(线性变换): 包括 平移、缩放、旋转、倾斜、翻转/镜像
任意一个二维图像,乘以一个仿射矩阵,就能的得到仿射变换后的图像。
仿射矩阵变换效果如下图所示:
函数:
1.调用warpAffine()函数进行仿射变换:
dst = warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None)
参数:
M: 仿射变换矩阵
dsize: 指定输出图片的大小
2.对于旋转操作, 一般调用getRotationMatrix2D()函数获取仿射矩阵:
M = getRotationMatrix2D(center, angle, scale)
参数:
center是旋转的中心点;
angle是旋转角度(正数表示逆时针),如angle=15表示逆时针旋转15度;
scale标量是缩放因子,0.5表示缩小,2表示放大一倍,-2表示放大一倍后再做(上下+左右)翻转。
示例:
import cv2
import numpy
img = cv2.imread("image/2.jpg")
rows, cols, channels = img.shape
# 1.创建仿射变换矩阵
# 1)平移
M1 = numpy.float32([[1, 0, 20], [0, 1, 80]]) # 沿x轴平移+20,沿y轴平移+80
# 2)缩放
M2 = numpy.float32([[0.8, 0, 0], [0, 0.5, 0]]) # x轴变为0.8倍,y轴变为0.5倍
# 3)旋转:调用getRotationMatrix2D()获取仿射矩阵
M3 = cv2.getRotationMatrix2D((cols//2, rows//2), 15, scale=0.5) # angle=15表示逆时针旋转15度。scale=0.5表示缩小到原来的一半。
# 4)倾斜
M4 = numpy.float32([[1, 0.5, 0], [0, 1, 0]])# 沿x轴倾斜0.5倍
M5 = numpy.float32([[1, 0, 0], [1, 1, 0]])# 沿y轴倾斜1倍
# 5)翻转/镜像
M6 = numpy.float32([[-0.5, 0, cols //2], [0, 0.5, 0]]) # x轴变为0.5倍并绕y转翻转,y轴变为0.5倍,最后沿x轴平移(cols//2)个像素单位
M7 = numpy.float32([[-1, 0, cols], [0, -1, rows]]) # 绕y转翻转、绕x转翻转,最后沿x轴平移cols个像素单位、沿y轴平移rows个像素单位
# 2.进行仿射变换
dst1 = cv2.warpAffine(img, M1, dsize=(cols, rows)) # 平移
dst2 = cv2.warpAffine(img, M2, dsize=(cols, rows)) # 缩放
dst3 = cv2.warpAffine(img, M3, dsize=(cols, rows)) # 旋转
dst4 = cv2.warpAffine(img, M4, dsize=(cols * 2, rows * 2)) # 倾斜
dst5 = cv2.warpAffine(img, M5, dsize=(cols * 2, rows * 2)) # 倾斜
dst6 = cv2.warpAffine(img, M6, dsize=(cols, rows)) # 翻转/镜像
dst7 = cv2.warpAffine(img, M7, dsize=(cols, rows)) # 翻转/镜像
cv2.imshow("img pic", img)
cv2.imshow("dst1 pic", dst1)
cv2.imshow("dst2 pic", dst2)
cv2.imshow("dst3 pic", dst3)
cv2.imshow("dst4 pic", dst4)
cv2.imshow("dst5 pic", dst5)
cv2.imshow("dst6 pic", dst6)
cv2.imshow("dst7 pic", dst7)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
三、透视变换(非线性变换): 一般用于矫正变形的图像
函数:
1.获取透视变换矩阵M:
M = getPerspectiveTransform(src, dst, solveMethod=None)
参数:
src:源图像中四边形顶点的坐标。
dst:目标图像中对应的四边形顶点的坐标。
2.调用warpPerspective()函数进行透视变换:
dst = warpPerspective(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None)‘
参数:
M: 透视变换矩阵
dsize: 指定输出图片的大小
示例:
import cv2
import numpy
src = cv2.imread("image/2.jpg")
rows, cols, channel = src.shape
print(cols, rows) # 200 201
# 1.获取透视变换矩阵M: getPerspectiveTransform(src, dst)
pts1 = numpy.array([[25, 30], [179, 25], [12, 188], [189, 190]], dtype=numpy.float32)
pts2 = numpy.float32([[0, 0], [200, 0], [0, 200], [200, 200]])
M = cv2.getPerspectiveTransform(pts1, pts2)
# 2.进行透视变换: warpPerspective(src, M, dsize)
dst = cv2.warpPerspective(src, M, dsize=(200, 200))
cv2.imshow("src pic", src)
cv2.imshow("dst pic", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
四、形态学操作:膨胀/腐蚀/开/闭/梯度/礼帽/黑帽
函数:
1.构造一个特定形状和大小的结构元素(核),用于形态学操作。
kernel = getStructuringElement(shape, ksize, anchor=None)
参数:
shape: 核的形状。
MORPH_RECT = 0: 矩形
MORPH_CROSS = 1: 交叉形
MORPH_ELLIPSE = 2: 椭圆形
ksize: 核的结构大小
2.膨胀: 原图部分区域(A)与核(B)进行卷积,求局部最大值,并将局部最大值赋值给指定像素,从而增长高亮区域。
dilate(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
3.腐蚀: 与膨胀相反,用局部极小值替换当前像素,从而缩短高亮区域。
erode(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
4.更多形态学操作
morphologyEx(src, op, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
参数:
op: 形态学操作类型。
cv2.MORPH_DILATE: 膨胀。-->增长高亮部分。
cv2.MORPH_ERODE: 腐蚀。-->缩短高亮部分。
cv2.MORPH_GRADIENT: 梯度,(膨胀-腐蚀)。-->提取轮廓。
cv2.MORPH_OPEN: 开,先腐蚀在膨胀。-->去除噪点。
cv2.MORPH_CLOSE: 闭,先膨胀再腐蚀。-->填补漏洞。
cv2.MORPH_TOPHAT: 顶帽/礼帽,(原图-开)。-->获取噪点。
cv2.MORPH_BLACKHAT: 黑帽,(闭-原图)。-->获取漏洞。
示例:
import cv2
import matplotlib.pyplot as plt
img1 = cv2.imread("image/3.jpg")
img2 = cv2.imread("image/4.jpg")
# 1.获取指定形状和大小的结构元素(核): getStructuringElement(shape, ksize)
kernel = cv2.getStructuringElement(shape=cv2.MORPH_RECT, ksize=(3, 3)) # 矩形
cross_kernel = cv2.getStructuringElement(shape=cv2.MORPH_CROSS, ksize=(3, 3)) # 交叉形
ellipse_kernel = cv2.getStructuringElement(shape=cv2.MORPH_ELLIPSE, ksize=(3, 3)) # 椭圆形
# 2.形态学操作
dilate = cv2.dilate(img1, kernel) # 膨胀
erode = cv2.erode(img1, kernel) # 腐蚀
morph_dilate = cv2.morphologyEx(img1, cv2.MORPH_DILATE, kernel) # 膨胀
morph_erode = cv2.morphologyEx(img1, cv2.MORPH_ERODE, kernel) # 腐蚀
morph_gradient = cv2.morphologyEx(img1, cv2.MORPH_GRADIENT, kernel) # 梯度: 膨胀-腐蚀, 用于提取轮廓
morph_open = cv2.morphologyEx(img2, cv2.MORPH_OPEN, kernel) # 开: 先腐蚀再膨胀,用于去噪
morph_close = cv2.morphologyEx(img2, cv2.MORPH_CLOSE, kernel) # 闭: 先膨胀后腐蚀,用于填补漏洞
morph_tophat = cv2.morphologyEx(img2, cv2.MORPH_TOPHAT, kernel) # 顶帽/礼帽: 原图-开,用于获取噪点
morph_blackhat = cv2.morphologyEx(img2, cv2.MORPH_BLACKHAT, kernel) # 黑帽: 闭-原图,用于填补漏洞
# 结合matplotlib展示多张图片
titles = ['Image', 'DILATE', 'ERODE', 'MORPH_DILATE', 'MORPH_ERODE', 'MORPH_GRADIENT']
images = [img1, dilate, erode, morph_dilate, morph_erode, morph_gradient]
for i in range(6):
plt.subplot(2, 3, i + 1)
plt.imshow(images[i], cmap="gray")
plt.title(titles[i])
plt.xticks([])
plt.yticks([])
plt.show()
titles = ['Image', 'MORPH_OPEN', 'MORPH_CLOSE', 'MORPH_TOPHAT', 'MORPH_BLACKHAT']
images = [img2, morph_open, morph_close, morph_tophat, morph_blackhat]
for i in range(5):
plt.subplot(2, 3, i + 1)
plt.imshow(images[i], cmap="gray")
plt.title(titles[i])
plt.xticks([])
plt.yticks([])
plt.show()
结果如下: