计算机视觉
第五章 图像梯度处理
一、什么是图像梯度
- 图像梯度计算的是图像变化的速度。对于图像的边缘部分,其灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情况下,图像梯度计算的是图像的边缘信息。
二、模板运算
- 模板(滤波器)是一个尺寸为n*n的小图像W(n一般取奇数,称为模板尺寸),每个位置上的值w被称为权重。在进行计算时,将模板的中心和像素P对齐,选取原始图像中和模板相同范围的邻域N的像素值作为输入。模板运算分为模板卷积、模板排序。
- 模板卷积的计算是将对齐后的对应位置像素相乘,再进行累加作为像素P位置的输出值。记原始图像的像素灰度值为s,计算后的值为d,则P点的输出值
d = ∑ w i s i ∑ w i d = \frac{\sum w_is_i}{\sum w_i} d=∑wi∑wisi
- 模板排序的计算时将邻域N的像素值进行排序,选择特定次序的灰度值,作为像素P位置的输出值,如最大值、最小值、中位数等。
三、均值滤波
- 均值滤波指模板权重都为1的滤波器。它将像素的邻域平均值作为输出结果,均值滤波可以起到图像平滑的效果,可以去除噪声,但随着模板尺寸的增加图像会变得更为模糊。经常被作为模糊化使用。
四、高斯滤波
- 为了减少模板尺寸增加对图像的模糊化,可以使用高斯滤波器,高斯滤波的模板根据高斯分布来确定模板系数,接近中心的权重比边缘的大。5的高斯滤波器如下所示:
五、中值滤波
- 中值滤波属于模板排序运算的滤波器。中值滤波器将邻域内像素排序后的中位数值输出代替原像素值。它在实现降噪操作的同时,保留了原始图像的锐度,不会修改原始图像的灰度值。
- 中值滤波的使用非常普遍,它对椒盐噪声的抑制效果很好,在抑制随机噪声的同时能有效保护边缘少受模糊。但中值滤波是一种非线性变化,它可能会破坏图像中线性关系,对于点、线等细节较多的图像和高精度的图像处理任务中并不太合适。
六、边沿检测
- 通过梯度计算可以获取图像中细节的边缘。为在锐化边缘的同时减少噪声的影响,通过改进梯度法发展出了不同的边缘检测算子:
- 一阶梯度:Prewitt梯度算子、Sobel梯度算子
- 二阶梯度:Laplacian梯度算子
- 边沿检测效果
七、锐化
- 图像锐化与图像平滑是相反的操作,锐化是通过增强高频分量来减少图像中的模糊,增强图像细节边缘和轮廓,增强灰度反差,便于后期对目标的识别和处理。锐化处理在增强图像边缘的同时也增加了图像的噪声。
- 将求取的边缘按照一定系数比例叠加到原始图像上,即可实现对图像的锐化操作。例如使用Laplacian梯度算子进行锐化操作的模板,其中A是大于等于1的系数:
八、代码
# 图像模糊化处理
import cv2
import numpy as np
im = cv2.imread("../data/lena.jpg", 0)
cv2.imshow("im", im)
# 中值滤波
im_median_blur = cv2.medianBlur(im, 5)
cv2.imshow("im_median_blur", im_median_blur)
# 均值滤波
im_mean_blur = cv2.blur(im, (3, 3))
cv2.imshow("im_mean_blur", im_mean_blur)
# 高斯滤波
im_gaussian_blur = cv2.GaussianBlur(im, (5, 5), 3)
cv2.imshow("im_gaussian_blur", im_gaussian_blur)
# 自定义高斯核执行滤波计算
gaussian_blur = np.array([
[1, 4, 7, 4, 1],
[4, 16, 26, 16, 4],
[7, 26, 41, 26, 7],
[4, 16, 26, 16, 4],
[1, 4, 7, 4, 1]
], np.float32) / 273
# 使用filter2D执行滤波计算
im_gaussian_blur2 = cv2.filter2D(im, # 原始图像
-1, # 目标图像深度,-1表示和原图像相同
gaussian_blur) # 滤波器
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
# 图像锐化
import cv2
import numpy as np
im = cv2.imread("../data/lena.jpg", 0)
cv2.imshow("im", im)
# 锐化算子1
sharpen_1 = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
im_sharpen1 = cv2.filter2D(im,
-1,
sharpen_1)
cv2.imshow("im_sharpen1", im_sharpen1)
# 锐化算子2
sharpen_2 = np.array([[0, -1, 0],
[-1, 8, -1],
[0, 1, 0]]) / 4.0
im_sharpen2 = cv2.filter2D(im,
-1,
sharpen_2)
cv2.imshow("im_sharpen2", im_sharpen2)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
第六章 图像轮廓
一、什么是图像轮廓
- 边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。图像轮廓是将边缘连接起来形成的一个整体,用于后续的计算。
- 图像轮廓是图像中非常重要的一个特征信息,通过对图像轮廓的操作,我们能够获取目标图像的大小、位置、方向等信息。
- 图像轮廓操作包括:查找轮廓、绘制轮廓、轮廓拟合等。
二、查找和绘制轮廓
- 一个轮廓对应着一系列的点,这些点以某种方式表示图像中的一条曲线,将这些点绘制成不同样式的线条,就是轮廓查找与绘制
三、轮廓拟合
- 在计算轮廓时,可能并不需要实际的轮廓,而仅需要一个接近于轮廓的近似多边形,绘制这个近似多边形称之为轮廓拟合
四、矩形包围框
五、最小包围圆形
六、最优拟合椭圆
七、逼近多边形
八、代码
1. 查找并绘制轮廓
# 查找并绘制轮廓
import cv2
import numpy as np
im = cv2.imread("../data/3.png")
cv2.imshow("im", im)
# 灰度化
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 二值化
ret, im_binary = cv2.threshold(im_gray, 127, 255, cv2.THRESH_BINARY)
# cv2.imshow("im_binary", im_binary)
# 查找轮廓
cnts, hie = cv2.findContours(im_binary, # 原图(经过二值化处理后的)
cv2.RETR_EXTERNAL, # 只检测外轮廓
cv2.CHAIN_APPROX_NONE) # 存储所有轮廓点
# print(type(cnts)) # tuple
# for cnt in cnts:
# # print(type(cnt)) # <class 'numpy.ndarray'>
# print(cnt.shape)
# """
# (257, 1, 2)
# (371, 1, 2)
# (336, 1, 2)
# (228, 1, 2)
# """
# 绘制轮廓
im_cnt = cv2.drawContours(im, # 原始图像
cnts, # 轮廓数据,findContours的返回值
-1, # 绘制所有轮廓
(0, 0, 255), # 轮廓颜色:红色
2) # 轮廓粗细
cv2.imshow("im_cnt", im_cnt)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
2. 绘制矩形包围框
# 绘制轮廓外接矩形框
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png", 0)
cv2.imshow("im", im)
# 二值化处理
ret, im_binary = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
cnts, hie = cv2.findContours(im_binary,
cv2.RETR_LIST, # 不建立等级关系
cv2.CHAIN_APPROX_NONE) # 存储轮廓所有坐标点
# print(cnts[0].shape) # (498, 1, 2)
# 根据轮廓产生外接矩形框参数
x, y, w, h = cv2.boundingRect(cnts[0])
# 绘制矩形框
brcnt = np.array([[[x, y]], [[x+w, y]],[[x+w,y+h]], [[x, y+h]]])
cv2.drawContours(im, [brcnt], -1, (255, 255, 255), 2)
cv2.imshow("result", im)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
3. 绘制圆形包围圈
# 绘制轮廓的最小圆形包围圈
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png", 0)
cv2.imshow("im", im)
# 二值化处理
ret, im_binary = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
cnts, hie = cv2.findContours(im_binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_NONE)
(x, y), radius = cv2.minEnclosingCircle(cnts[0]) # 产生轮廓的最小外接圆形参数
print((x, y), radius) # (204.5, 91.5) 86.53621673583984
center = (int(x), int(y)) # 将圆心的坐标转换为整型
radius = int(radius) # 将半径转换为整型
cv2.circle(im, center, radius, (255, 255, 255), 2) # 绘制圆形
cv2.imshow("result", im)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
4. 绘制最佳拟合椭圆
# 绘制最优拟合椭圆
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png")
cv2.imshow("im", im)
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, im_binary = cv2.threshold(im_gray, 127, 255, cv2.THRESH_BINARY)
# 提取轮廓
cnts, hie = cv2.findContours(im_binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_NONE)
ellipse = cv2.fitEllipse(cnts[0]) # 产生最优拟合椭圆数据
print("ellipse",
ellipse) # ellipse ((204.24952697753906, 91.23741149902344), (69.94644165039062, 162.95944213867188), 84.70285034179688)
cv2.ellipse(im, ellipse, (0, 0, 255), 2) # 绘制椭圆
cv2.imshow("result", im)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口
5. 逼近多边形
# 使用多边形对轮廓进行拟合
import cv2
import numpy as np
im = cv2.imread("../data/cloud.png")
cv2.imshow("im", im)
# 转灰度图像
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 二值化
ret, im_binary = cv2.threshold(im_gray, 127, 255, cv2.THRESH_BINARY)
# 查找轮廓
cnts, hie = cv2.findContours(im_binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_NONE)
# 精度一
adp = im.copy()
epsilon = 0.005 * cv2.arcLength(cnts[0], True) # 精度,根据周长计算
approx = cv2.approxPolyDP(cnts[0], epsilon, True) # 构造多边形,返回多边形数据
adp = cv2.drawContours(adp, [approx], 0, (0, 0, 255), 2) # 绘制
cv2.imshow("result_0.005", adp)
# 精度二
adp2 = im.copy()
epsilon = 0.01 * cv2.arcLength(cnts[0], True) # 精度,根据周长计算
approx = cv2.approxPolyDP(cnts[0], epsilon, True) # 构造多边形,返回多边形数据
adp = cv2.drawContours(adp2, [approx], 0, (0, 0, 255), 2) # 绘制
cv2.imshow("result_0.01", adp2)
cv2.waitKey() # 等待用户按某个按键
cv2.destroyAllWindows() # 销毁所有创建的窗口