计算机视觉
第四章 形态变换
一、仿射变换
1. 什么是仿射变换
- 仿射变换是指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够保持图像的平直性和平行性。平直性是指图像经过仿射变换后,直线仍然是直线;平行性是指图像在完成仿射变换后,平行线仍然是平行线。
2. 平移
- 改变图像的x和y坐标,将所有x坐标的像素增加就是向右平移,减小就是向左平移,将所有y坐标的像素增加就是向下平移,减小就是向上平移
3. 镜像
- 水平镜像:改变的是每个像素的x坐标,x坐标关于y轴对称
- 垂直镜像:保持x轴坐标不变,改变它的y坐标
4. 旋转
5. 透视变换
- 透视变换是将图片投影到一个新的视平面,也称作投影映射。它是二维(x,y)到三维(X,Y,Z),再到另一个二维(x’,y’)空间的映射。
- 相对于仿射变换,它提供了更大的灵活性,将一个四边形区域映射到另一个四边形区域(不一定是平行四边形),透视变换可用于图像形状校正。
二、算数运算
1. 图像加法
2. 图像减法
- 图像减法是找出两幅图像的差异,可以在连续图像中实现消除背景和运动检测
三、图像缩放
1. 缩放
2. 图像缩小
- 图像缩小可以通过删除矩阵中的元素来实现,例如:下面的例子进行隔行、隔列删除后,高度、宽度均减小为原来的一半
3. 图像放大
- 最邻近插值法放大后有锯齿状
四、腐蚀与膨胀
1. 图像腐蚀
- 腐蚀是最基本的形态学操作之一,它能够将图像的边界点消除,使图像沿着边界向内收缩,也可以将小于指定结构体元素的部分去除。腐蚀用来“收缩”或者“细化”二值图像中的前景,借此实现去除噪声、元素分割等功能。
2. 图像膨胀
- 图像膨胀是指根据原图像的形状,向外进行扩充。如果图像内两个对象的距离较近,那么在膨胀的过程中,两个对象可能会连通在一起。膨胀操作对填补图像分割后图像内所存在的空白相当有帮助。
3. 图像开运算
- 开运算进行的操作是先将图像腐蚀,再对腐蚀的结果进行膨胀。开运算可以用于去噪、计数等。
- 开运算可用于取出主题图像之间细小的连接
4. 图像闭运算
- 闭运算是先膨胀、后腐蚀的运算,它有助于关闭前景物体内部的小孔,或去除物体上的小黑点,还可以将不同的前景图像进行连接。
5. 形态学梯度
- 形态学梯度运算是用图像的膨胀图像减腐蚀图像的操作,该操作可以获取原始图像中前景图像的边缘。
6. 礼帽运算
- 礼帽运算是用原始图像减去其开运算图像的操作。礼帽运算能够获取图像的噪声信息,或者得到比原始图像的边缘更亮的边缘信息。
7. 黑帽运算
- 黑帽运算是用闭运算图像减去原始图像的操作。黑帽运算能够获取图像内部的小孔,或前景色中的小黑点,或者得到比原始图像的边缘更暗的边缘部分。
五、图像形态操作
1. 图像翻转
# 图像翻转
import cv2
im = cv2.imread("../data/Linus.png")
cv2.imshow("im", im)
# 0-垂直镜像
im_flip0 = cv2.flip(im, 0)
cv2.imshow("im_flip0", im_flip0)
# 1-水平镜像
im_flip1 = cv2.flip(im, 1)
cv2.imshow("im_flip1", im_flip1)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
2. 图像位置变换
# 图像仿射变换(旋转、平移)
import numpy as np
import cv2
def translate(im, x, y):
"""
对图像进行平移变换
:param im: 原始图像数据
:param x: 水平方向平移的像素
:param y: 垂直方向平移的像素
:return: 返回平移后的图像数据
"""
h, w = im.shape[:2] # 取出原图像的高度、宽度
# 定义平移矩阵
M = np.float32([[1, 0, x],
[0, 1, y]])
# 调用warpAffine函数实现平移变换
shifted = cv2.warpAffine(im, # 原始图像
M, # 平移矩阵
(w, h)) # 输出图像大小
return shifted
def rotate(im, angle, center=None, scale=1.0):
"""
图像旋转变换
:param im: 原始图像
:param angle: 旋转角度
:param center: 旋转中心
:param scale: 缩放比例
:return: 返回经过旋转后的图像
"""
h, w = im.shape[:2] # 获取图像高度、宽度
# 计算旋转中心
if center is None:
center = (w / 2, h / 2)
# 生成旋转矩阵
M = cv2.getRotationMatrix2D(center, angle, scale)
# 调用warpAffine函数实现旋转变换
rotated = cv2.warpAffine(im, M, (w, h))
return rotated
if __name__ == "__main__":
# 读取原始图像
im = cv2.imread("../data/Linus.png")
cv2.imshow("im", im)
# 向下移动50像素
shifted = translate(im, 0, 50)
cv2.imshow("shifted_1", shifted)
# 向左移动40像素,向下移动50像素
shifted = translate(im, -40, 50)
cv2.imshow("shifted_2", shifted)
# 逆时针旋转45度
rotated = rotate(im, 45)
cv2.imshow("rotated_1", rotated)
# 顺时针旋转90度
rotated = rotate(im, -90)
cv2.imshow("rotated_2", rotated)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
3. 图像缩放
# 图像缩放示例
import cv2
im = cv2.imread("../data/Linus.png")
cv2.imshow("im", im)
h, w = im.shape[:2] # 获取图像高度、宽度
# 缩小
dst_size = (int(w/2), int(h/2)) # 计算缩放后的图像宽度、高度
resized = cv2.resize(im, dst_size)
cv2.imshow("reduce", resized)
# 放大
dst_size = (200, 300) # 缩放尺寸,宽200,高300
resized = cv2.resize(im,
dst_size,
interpolation=cv2.INTER_NEAREST) # 最邻近插值
cv2.imshow("NEAREST", resized)
resized = cv2.resize(im,
dst_size,
interpolation=cv2.INTER_LINEAR) # 双线性插值
cv2.imshow("LINEAR", resized)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
4. 图像裁剪
# 图像裁剪(利用数组切片操作实现)
import numpy as np
import cv2
# 随机裁剪
def random_crop(im, w, h):
# 随机产生裁剪起点的x, y坐标
start_x = np.random.randint(0, im.shape[1]) # 裁剪起始的x坐标
start_y = np.random.randint(0, im.shape[0]) # 裁剪起始的y坐标
new_img = im[start_y:start_y + h, start_x:start_x + w] # 切片
return new_img
# 中心裁剪
def center_crop(im, w, h):
start_x = int(im.shape[1] / 2) - int(w / 2) # 裁剪起始的x坐标
start_y = int(im.shape[0] / 2) - int(h / 2) # 裁剪起始的y坐标
new_img = im[start_y:start_y + h, start_x:start_x + w] # 切片
return new_img
if __name__ == "__main__":
im = cv2.imread("../data/banana_1.png", 1)
new_img = random_crop(im, 200, 200) # 随机裁剪
cv2.imshow("random_crop", new_img)
new_img2 = center_crop(im, 200, 200) # 随机裁剪
cv2.imshow("center_crop", new_img2)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
5. 图像相加
# 图像相加
import cv2
a = cv2.imread("../data/lena.jpg", 0)
b = cv2.imread("../data/lily_square.png", 0)
# 图像直接相加,会导致图像越加越白,越加越亮
dst1 = cv2.add(a, b)
cv2.imshow("dst1", dst1)
# 图像按权重相加
dst2 = cv2.addWeighted(a, 0.6, # 图像1和权重
b, 0.4, # 图像2和权重
0) # 亮度调节量
cv2.imshow("dst2", dst2)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
6. 图像相减
# 图像相减
import cv2
a = cv2.imread("../data/3.png", 0)
b = cv2.imread("../data/4.png", 0)
dst = cv2.subtract(a, b) # 图像相减
cv2.imshow("a", a)
cv2.imshow("b", b)
cv2.imshow("dst", dst)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
7. 图像透视变换
# 透视变换
import cv2
import numpy as np
im = cv2.imread("../data/pers.png")
rows, cols = im.shape[:2] # 取出高度、宽度
print(rows, cols) # 206 184
cv2.imshow("im", im)
# 指定映射坐标
pts1 = np.float32([[58, 2], [167, 9], [8, 196], [126, 196]]) # 原坐标点
pts2 = np.float32([[16, 2], [167, 8], [8, 196], [169, 196]]) # 目标点坐标
# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)
# 执行变换
dst = cv2.warpPerspective(im, # 原始图像
M, # 变换矩阵
(cols, rows)) # 输出图像大小
cv2.imshow("dst", dst)
# 将矩形变换成平行四边形
M = cv2.getPerspectiveTransform(pts2, pts1)
# 执行变换
dst2 = cv2.warpPerspective(im, # 原始图像
M, # 变换矩阵
(cols, rows)) # 输出图像大小
cv2.imshow("dst2", dst2)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
8. 图像腐蚀
# 图像腐蚀
import cv2
import numpy as np
im = cv2.imread("../data/5.png")
cv2.imshow("im", im)
# 腐蚀
kernel = np.ones((3, 3), np.uint8) # 腐蚀核
erosion = cv2.erode(im, # 原始图像
kernel, # 腐蚀核
iterations=3) # 迭代次数
cv2.imshow("erosion", erosion)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
9. 图像膨胀
# 图像膨胀
import cv2
import numpy as np
im = cv2.imread("../data/6.png")
cv2.imshow("im", im)
# 膨胀
kernel = np.ones((3, 3), np.uint8) # 膨胀核
dilation = cv2.dilate(im, # 图像
kernel, # 膨胀核
iterations=5) # 迭代次数
cv2.imshow("dilation", dilation)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
10. 图像开运算
# 图像开运算
import cv2
import numpy as np
im1 = cv2.imread("../data/7.png")
im2 = cv2.imread("../data/8.png")
# 执行开运算
k = np.ones((10, 10), np.uint8) # 计算核
r1 = cv2.morphologyEx(im1, cv2.MORPH_OPEN, k)
r2 = cv2.morphologyEx(im2, cv2.MORPH_OPEN, k)
cv2.imshow("im1", im1)
cv2.imshow("im2", im2)
cv2.imshow("r1", r1)
cv2.imshow("r2", r2)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
11. 图像闭运算
# 图像开运算
import cv2
import numpy as np
im1 = cv2.imread("../data/9.png")
im2 = cv2.imread("../data/10.png")
# 执行开运算
k = np.ones((8, 8), np.uint8) # 计算核
r1 = cv2.morphologyEx(im1, cv2.MORPH_CLOSE, k, iterations=2)
r2 = cv2.morphologyEx(im2, cv2.MORPH_CLOSE, k, iterations=2)
cv2.imshow("im1", im1)
cv2.imshow("im2", im2)
cv2.imshow("r1", r1)
cv2.imshow("r2", r2)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
12. 形态学梯度
# 形态学梯度:膨胀的图像减腐蚀的图像
import cv2
import numpy as np
o = cv2.imread("../data/6.png")
k = np.ones((3, 3), np.uint8) # 计算核
r = cv2.morphologyEx(o, cv2.MORPH_GRADIENT, k) # 计算形态学梯度
cv2.imshow("o", o)
cv2.imshow("r", r)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口