整个过程分为五步:
高斯模糊平滑——计算梯度——非最大抑制——双阈值过滤——滞后跟踪
代码中额外定义:初始化——计算梯度——非最大抑制——双阈值过滤
代码来自GitHub - CV-xueba/A01_cvclass_basic_exercise
canny
引入库文件
引入库
cv2
(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,它提供了大量的图像和视频处理功能。
OpenCV 库的主要功能包括:
- 图像处理:包括图像的基本操作,如读取、显示、转换颜色空间、调整大小、旋转、裁剪等。
- 图像特征检测:如边缘检测(Sobel、Canny 等)、角点检测(Harris、Shi-Tomasi 等)、特征点检测(SIFT、SURF、ORB 等)。
- 图像增强:如直方图均衡化、伽马校正、噪声降低等。
- 图像变换:如几何变换(平移、旋转、缩放)、仿射变换、透视变换等。
- 视频分析:包括视频的读取、写入、背景减除、运动检测等。
- 实时图像处理:支持实时图像捕获、处理和显示。
- 机器学习和数据挖掘:提供多种机器学习算法,如SVM、KNN、K-means等。
- 深度学习和神经网络:支持深度学习模型的构建、训练和应用,包括预训练的模型和自定义模型。
import numpy as np
用于导入numpy
库,并为其设置一个简短的别名np。
numpy
: 是一个非常流行的 Python 科学计算库,它提供了对多维数组对象的支持以及对这些数组的高效操作。numpy
是 "Numerical Python" 的缩写,它在科学计算、数据分析、机器学习等领域非常常用。
大规模数组和矩阵运算:
numpy
提供了强大的多维数组对象ndarray
,可以高效地存储和处理大型数据集。数学函数:
numpy
包含了广泛的数学函数,可以对数组执行向量化的加法、减法、乘法、除法、指数、对数、三角函数等操作。线性代数:提供了丰富的线性代数运算功能,如矩阵乘法、特征值和特征向量计算、奇异值分解等。
傅里叶分析:
numpy
可以进行快速傅里叶变换(FFT)和逆变换,适用于频域分析。随机数生成:可以生成各种概率分布的随机数,适用于统计分析和模拟。
统计分析:提供均值、方差、标准差、相关性、协方差等统计计算。
排序和搜索:可以对数组进行高效的排序,以及搜索特定元素或最大/最小值。
集合逻辑:支持集合操作,如集合的交集、并集、差集等。
广播功能:允许不同大小的数组进行算术运算,这是通过扩展较小数组的形状来匹配较大数组的形状实现的。
索引和切片:支持高级索引、切片和布尔索引,可以灵活地操作数组。
内存映射文件:可以创建数组,直接对应到存储在磁盘上的二进制数据格式,适用于处理大型数据文件。
数据类型和结构化数据:支持多种数据类型,并且可以创建结构化数组来存储复杂的数据结构。
文件输入输出:可以读取和写入多种格式的数据文件,包括文本、二进制和 HDF5 格式。
图像处理:虽然不是
numpy
的主要功能,但它的数组操作可以用于图像处理任务,如图像滤波、形态学操作等。与其他库的集成:
numpy
与其他科学计算库如scipy
、pandas
、matplotlib
、scikit-learn
等紧密集成,是 Python 科学计算生态系统的基石。
numpy
是数据密集型计算任务的重要工具,特别是在科学、工程、金融和数据分析等领域。
定义canny类
import cv2
import numpy as np
class Canny:
def __init__(self, Guassian_kernal_size, img, HT_high_threshold, HT_low_threshold):
'''
:param Guassian_kernal_size: 高斯滤波器尺寸
:param img: 输入的图片,在算法过程中改变
:param HT_high_threshold: 滞后阈值法中的高阈值
:param HT_low_threshold: 滞后阈值法中的低阈值
'''
self.Guassian_kernal_size = Guassian_kernal_size
self.img = img
self.y, self.x = img.shape[0:2]
self.angle = np.zeros([self.y, self.x])
self.img_origin = None
self.x_kernal = np.array([[-1, 1]])
self.y_kernal = np.array([[-1], [1]])
self.HT_high_threshold = HT_high_threshold
self.HT_low_threshold = HT_low_threshold
def Get_gradient_img(self):
'''
计算梯度图和梯度方向矩阵。
:return: 生成的梯度图
'''
print ('Get_gradient_img')
new_img_x = np.zeros([self.y, self.x], dtype=np.float)
new_img_y = np.zeros([self.y, self.x], dtype=np.float)
for i in range(0, self.x):
for j in range(0, self.y):
if j == 0:
new_img_y[j][i] = 1
else:
new_img_y[j][i] = np.sum(np.array([[self.img[j - 1][i]], [self.img[j][i]]]) * self.y_kernal)
if i == 0:
new_img_x[j][i] = 1
else:
new_img_x[j][i] = np.sum(np.array([self.img[j][i - 1], self.img[j][i]]) * self.x_kernal)
gradient_img, self.angle = cv2.cartToPolar(new_img_x, new_img_y)
self.angle = np.tan(self.angle)
self.img = gradient_img.astype(np.uint8)
return self.img
def Non_maximum_suppression (self):
'''
对生成的梯度图进行非极大化抑制,将tan值的大小与正负结合,确定离散中梯度的方向。
:return: 生成的非极大化抑制结果图
'''
print ('Non_maximum_suppression')
result = np.zeros([self.y, self.x])
for i in range(1, self.y - 1):
for j in range(1, self.x - 1):
if abs(self.img[i][j]) <= 4:
result[i][j] = 0
continue
elif abs(self.angle[i][j]) > 1:
gradient2 = self.img[i - 1][j]
gradient4 = self.img[i + 1][j]
# g1 g2
# C
# g4 g3
if self.angle[i][j] > 0:
gradient1 = self.img[i - 1][j - 1]
gradient3 = self.img[i + 1][j + 1]
# g2 g1
# C
# g3 g4
else:
gradient1 = self.img[i - 1][j + 1]
gradient3 = self.img[i + 1][j - 1]
else:
gradient2 = self.img[i][j - 1]
gradient4 = self.img[i][j + 1]
# g1
# g2 C g4
# g3
if self.angle[i][j] > 0:
gradient1 = self.img[i - 1][j - 1]
gradient3 = self.img[i + 1][j + 1]
# g3
# g2 C g4
# g1
else:
gradient3 = self.img[i - 1][j + 1]
gradient1 = self.img[i + 1][j - 1]
temp1 = abs(self.angle[i][j]) * gradient1 + (1 - abs(self.angle[i][j])) * gradient2
temp2 = abs(self.angle[i][j]) * gradient3 + (1 - abs(self.angle[i][j])) * gradient4
if self.img[i][j] >= temp1 and self.img[i][j] >= temp2:
result[i][j] = self.img[i][j]
else:
result[i][j] = 0
self.img = result
return self.img
def Hysteresis_thresholding(self):
'''
对生成的非极大化抑制结果图进行滞后阈值法,用强边延伸弱边,这里的延伸方向为梯度的垂直方向,
将比低阈值大比高阈值小的点置为高阈值大小,方向在离散点上的确定与非极大化抑制相似。
:return: 滞后阈值法结果图
'''
print ('Hysteresis_thresholding')
for i in range(1, self.y - 1):
for j in range(1, self.x - 1):
if self.img[i][j] >= self.HT_high_threshold:
if abs(self.angle[i][j]) < 1:
if self.img_origin[i - 1][j] > self.HT_low_threshold:
self.img[i - 1][j] = self.HT_high_threshold
if self.img_origin[i + 1][j] > self.HT_low_threshold:
self.img[i + 1][j] = self.HT_high_threshold
# g1 g2
# C
# g4 g3
if self.angle[i][j] < 0:
if self.img_origin[i - 1][j - 1] > self.HT_low_threshold:
self.img[i - 1][j - 1] = self.HT_high_threshold
if self.img_origin[i + 1][j + 1] > self.HT_low_threshold:
self.img[i + 1][j + 1] = self.HT_high_threshold
# g2 g1
# C
# g3 g4
else:
if self.img_origin[i - 1][j + 1] > self.HT_low_threshold:
self.img[i - 1][j + 1] = self.HT_high_threshold
if self.img_origin[i + 1][j - 1] > self.HT_low_threshold:
self.img[i + 1][j - 1] = self.HT_high_threshold
else:
if self.img_origin[i][j - 1] > self.HT_low_threshold:
self.img[i][j - 1] = self.HT_high_threshold
if self.img_origin[i][j + 1] > self.HT_low_threshold:
self.img[i][j + 1] = self.HT_high_threshold
# g1
# g2 C g4
# g3
if self.angle[i][j] < 0:
if self.img_origin[i - 1][j - 1] > self.HT_low_threshold:
self.img[i - 1][j - 1] = self.HT_high_threshold
if self.img_origin[i + 1][j + 1] > self.HT_low_threshold:
self.img[i + 1][j + 1] = self.HT_high_threshold
# g3
# g2 C g4
# g1
else:
if self.img_origin[i - 1][j + 1] > self.HT_low_threshold:
self.img[i + 1][j - 1] = self.HT_high_threshold
if self.img_origin[i + 1][j - 1] > self.HT_low_threshold:
self.img[i + 1][j - 1] = self.HT_high_threshold
return self.img
def canny_algorithm(self):
'''
按照顺序和步骤调用以上所有成员函数。
:return: Canny 算法的结果
'''
self.img = cv2.GaussianBlur(self.img, (self.Guassian_kernal_size, self.Guassian_kernal_size), 0)
self.Get_gradient_img()
self.img_origin = self.img.copy()
self.Non_maximum_suppression()
self.Hysteresis_thresholding()
return self.img