跟着鲁sir学CV_Opencv(1)检测硬币边缘之Canny

发布于:2024-05-18 ⋅ 阅读:(101) ⋅ 点赞:(0)

整个过程分为五步:

高斯模糊平滑——计算梯度——非最大抑制——双阈值过滤——滞后跟踪

代码中额外定义:初始化——计算梯度——非最大抑制——双阈值过滤

代码来自GitHub - CV-xueba/A01_cvclass_basic_exercise

canny

引入库文件

引入库

cv2

(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,它提供了大量的图像和视频处理功能。

OpenCV 库的主要功能包括:

  1. 图像处理:包括图像的基本操作,如读取、显示、转换颜色空间、调整大小、旋转、裁剪等。
  2. 图像特征检测:如边缘检测(Sobel、Canny 等)、角点检测(Harris、Shi-Tomasi 等)、特征点检测(SIFT、SURF、ORB 等)。
  3. 图像增强:如直方图均衡化、伽马校正、噪声降低等。
  4. 图像变换:如几何变换(平移、旋转、缩放)、仿射变换、透视变换等。
  5. 视频分析:包括视频的读取、写入、背景减除、运动检测等。
  6. 实时图像处理:支持实时图像捕获、处理和显示。
  7. 机器学习和数据挖掘:提供多种机器学习算法,如SVM、KNN、K-means等。
  8. 深度学习和神经网络:支持深度学习模型的构建、训练和应用,包括预训练的模型和自定义模型。

import numpy as np 用于导入 numpy 库,并为其设置一个简短的别名 np。

  • numpy: 是一个非常流行的 Python 科学计算库,它提供了对多维数组对象的支持以及对这些数组的高效操作。numpy 是 "Numerical Python" 的缩写,它在科学计算、数据分析、机器学习等领域非常常用。
  1. 大规模数组和矩阵运算numpy 提供了强大的多维数组对象 ndarray,可以高效地存储和处理大型数据集。

  2. 数学函数numpy 包含了广泛的数学函数,可以对数组执行向量化的加法、减法、乘法、除法、指数、对数、三角函数等操作。

  3. 线性代数:提供了丰富的线性代数运算功能,如矩阵乘法、特征值和特征向量计算、奇异值分解等。

  4. 傅里叶分析numpy 可以进行快速傅里叶变换(FFT)和逆变换,适用于频域分析。

  5. 随机数生成:可以生成各种概率分布的随机数,适用于统计分析和模拟。

  6. 统计分析:提供均值、方差、标准差、相关性、协方差等统计计算。

  7. 排序和搜索:可以对数组进行高效的排序,以及搜索特定元素或最大/最小值。

  8. 集合逻辑:支持集合操作,如集合的交集、并集、差集等。

  9. 广播功能:允许不同大小的数组进行算术运算,这是通过扩展较小数组的形状来匹配较大数组的形状实现的。

  10. 索引和切片:支持高级索引、切片和布尔索引,可以灵活地操作数组。

  11. 内存映射文件:可以创建数组,直接对应到存储在磁盘上的二进制数据格式,适用于处理大型数据文件。

  12. 数据类型和结构化数据:支持多种数据类型,并且可以创建结构化数组来存储复杂的数据结构。

  13. 文件输入输出:可以读取和写入多种格式的数据文件,包括文本、二进制和 HDF5 格式。

  14. 图像处理:虽然不是 numpy 的主要功能,但它的数组操作可以用于图像处理任务,如图像滤波、形态学操作等。

  15. 与其他库的集成numpy 与其他科学计算库如 scipypandasmatplotlibscikit-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