精华内容
下载资源
问答
  • 霍夫变换检测圆
    千次阅读
    2021-12-04 20:13:06

    圆的参数方程为:
    r 2 = ( x − x 0 ) 2 + ( y − y 0 ) 2 r^2=(x-x_0)^2+(y-y_0)^2 r2=(xx0)2+(yy0)2
    这个方程包含三个参数(圆半径和圆心坐标),这表明需要使用三维的累加器。但一般来说,累加器的维数越多,霍夫变换就越复杂,可靠性也越低。在本例中,每个像素点都会使累加器增加大量的入口。因此,精确地定位局部尖峰值会变得更加困难。为解决这个问题,人们提出了各种策略。OpenCV 采用的策略是在用霍夫变换检测圆的实现中使用两轮筛选。第一轮筛选使用一个二维累加器,找出可能是圆的位置。因为圆周上像素点的梯度方向与半径的方向是一致的,所以对每个像素点来说,累加器只对沿着梯度方向的入口增加计数(根据预先定义的最小和最大半径值)。一旦检测到可能的圆心(即收到了预定数量的投票),就在第二轮筛选中建立半径值范围的一维直方图。这个直方图的尖峰值就是被检测圆的半径。
    实现上述策略的 cv::HoughCircles 函数将 Canny 检测与霍夫变换结合,它的调用方法是:

    cv::GaussianBlur(image,image,cv::Size(5,5),1.5); 
    std::vector<cv::Vec3f> circles; 
     cv::HoughCircles(image, circles, cv::HOUGH_GRADIENT, 
     2, // 累加器分辨率(图像尺寸/2)
     50, // 两个圆之间的最小距离
     200, // Canny 算子的高阈值
     100, // 最少投票数
     25, 
     100); // 最小和最大半径
    

    有一点需要反复提醒:在调用 cv::HoughCircles 函数之前,要对图像进行平滑化,以减少图像中可能导致误判的噪声。检测的结果存放在 cv::Vec3f 实例的向量中。前面两个数值是圆心坐标,第三个数值是半径。

    更多相关内容
  • 资源名:matlab进行霍夫变换检测圆_matlab源码 资源类型:matlab项目全套源码 源码说明: 全部项目源码都是经过测试校正后百分百成功运行的,如果您下载后不能运行可联系我进行指导或者更换。 适合人群:新手及有...
  • 霍夫变换检测圆代码MATLAB 计算机视觉项目地球检测 在混乱的环境中进行政治地球仪检测 计算机视觉中的常见问题是在图片或视频流中搜索并找到特定的对象或形状。 在这个特殊的项目中,我们被要求设计和实施一个完整的...
  • 完整的算法步骤% 1. 读取图像% 2. 转换为灰度% 3. 检测边缘% 4. 定义累加器矩阵% 5. 使用半径值通过方程找到圆心% 6. 在累加器矩阵中赋值% 7. 寻找峰值(圆心) % 8. 在原始彩色图像上绘制圆圈
  • 随机霍夫变换 圆检测

    2020-12-01 00:30:16
    随机霍夫变换 圆检测
  • 概述: -------- 通过检查所有可能的长轴(所有点对)并使用霍夫变换获取短轴来拟合椭圆。 算法复杂度取决于有效非零点的数量,因此如果有任何先验,则在“params”输入参数中提供尽可能多的限制是有益的有关问题的...
  • 霍夫变换检测圆,是图像处理的重要应用,还可用于图形识别
  • Python代码实现霍夫变换检测圆

    千次阅读 2021-08-26 14:38:22
    霍夫变换检测圆 参考资料:计算机视觉 北京邮电大学 鲁鹏 1.简单的介绍一下霍夫变换 我们在使用canny算子检测到图像的边缘之后,我们要如何去描述这些图像的边缘? 我们是否可以通过一些简单的特征来描述这些图像...

    霍夫变换检测圆

    参考资料:计算机视觉 北京邮电大学 鲁鹏

    1.简单的介绍一下霍夫变换

    我们在使用canny算子检测到图像的边缘之后,我们要如何去描述这些图像的边缘?

    我们是否可以通过一些简单的特征来描述这些图像边缘?比如利用直线、圆等简单的集合形状来描述边缘的特征?这就是霍夫变换的目的。

    霍夫变换准确来说是一种特征检测,不仅能识别直线,也能够识别任何形状,常见的有圆形、椭圆形。

    2.霍夫变换检测圆的原理

    一个圆所具有的的基本属性:圆心坐标 ( x , y ) (x,y) (x,y),半径r

    已知一个圆形边缘,如何得出其圆心坐标和半径?

    2.1 简单但不实用的方法

    该方法我们仅用来参考其算法思想,实际中并不应用。

    请添加图片描述

    如图,我们用像素格来表示图片。

    我们想要获得圆心坐标和半径,我们可以选取圆上任意一点A,然后以图片上每一个像素格为圆心B,以AB为半径画圆,记录下圆心坐标和半径。

    重复上述过程,知道将圆上的所有点都计算一遍。(我们将圆心坐标和半径当做一个整体来看,你可以将其视为一个元组)

    然后统计这些圆心坐标和半径,我们采用投票的方法,这些圆心坐标和半径每出现一次,就相当于得到一票。

    这样一定会有一个圆心坐标和半径得票次数最多,那么这个圆心坐标和半径就是我们所要找的。

    因为,圆上的每一点都会给真正的圆心和半径投一票。

    而,以其他点为圆心所画的圆,通常只能够得到一票或者两票。

    显然,这种方法的计算量很大。因此我们在实际应用中并不采用这种方法。

    2.2梯度投票法

    我们在理解了上述算法的思想之后,就可以考虑如何减少算法的计算量。

    我们在学习canny算子的时候,就知道边缘上的每一个像素格都有自己梯度方向。而梯度方向通常和边都是垂直的,因此我们可以知道,沿圆上一点的梯度方向画一条直线,该直线一定会通过圆心。

    于是,我们仅让沿边缘上一点的梯度方向的像素格作为圆心画圆,并记录圆心坐标和半径,这样我们同样可以得到真正的圆心坐标和半径。

    然而,这种方法仍旧计算量很大,我们考虑设置一个步长。即沿梯度方向,每走一个步长的像素格,我们将其取为圆心,并计算半径。这样就进一步降低了计算量。如下图所示,是以一个像素格为步长所画的圆。黑色的矩形框表示我们的图片的大小,黑色的圆为我们通过canny算子检测得到的圆形边缘。红色的圆为我们所取的圆心和半径。

    请添加图片描述

    现在我们需要确定其圆心坐标和半径。

    • 1.首先选取圆上任意一点A,获得其梯度方向(这里为了方便画图,选取了一个梯度方向为水平的点),并设定步长。

      梯度方向在我们canny算子检测边缘时就已经获得了。

    • 2.我们沿该梯度方向以一定步长选取像素格作为圆心B,并计算AB之间的距离,作为半径。记录圆心坐标,半径。

    • 3.对圆上每一点重复上述操作。

    • 4.统计所有圆心坐标和半径,获得得票数最多的圆心坐标和半径,作为输出。

    3.需要解决的几个问题

    3.1非最大化抑制

    由于我们取的步长并不一定使我们取到真正的圆心,所以通常统计出来的圆心坐标和半径会出现聚集的现象。

    请添加图片描述

    如图所示,在真正的圆心附近,出现几个得票数比较多的像素格(通常是前几名)。因此我们需要对其进行最大化抑制。

    但通常情况下,我们并不是单纯的进行非最大化抑制,我们会将得票数最多的像素格,及其周围一定范围内的像素格进行平均操作,得出最准确的真实圆心坐标和半径。

    3.2多个圆的输出

    我们在处理一个图像的时候,通常并不能够确定这个图像中包含有多少个圆。因此我们通常会设置一个阈值,投票数多于某个阈值的点输出,低于阈值的点舍弃。

    4.代码

    4.1 canny算子

    这里使用的canny代码并非上篇文章中所使用的代码,Python代码实现Canny算法——图像边缘轮廓提取

    为什么不是用之前所使用的代码呢?一是因为之前的代码计算效率低,二是因为我太懒了不想优化了(真实原因是我为了把上篇文章的代码融合到霍夫变换的代码中改了好久的bug,运行结果仍旧不太好),于是就取用北邮鲁鹏老师所给的样例代码 ̄□ ̄|

    因此在这里再赘述一下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]])  # x方向偏导卷积核
            self.y_kernal = np.array([[-1], [1]])  # y方向偏导卷积核
            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)  # 定义x偏导存储矩阵
            new_img_y = np.zeros([self.y, self.x], dtype=np.float)  # 定义y偏导存储矩阵
            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)
                        # y方向卷积后的灰度图,dy
                    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)
                        # x方向卷积后的灰度图,dx
    
            gradient_img, self.angle = cv2.cartToPolar(new_img_x, new_img_y)  # 通过dx,dy求取梯度强度和梯度方向即角度
            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:  # dy>dx
                        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
    

    4.2 霍夫变换检测圆的代码:

    import numpy as np
    import math
    
    
    class Hough_transform:
        def __init__(self, img, angle, step=5, threshold=135):
            '''
            img: 输入的边缘图像
            angle: 输入的梯度方向矩阵
            step: Hough 变换步长大小
            threshold: 筛选单元的阈值
            '''
            self.img = img
            self.angle = angle
            self.y, self.x = img.shape[0:2]  
            self.radius = math.ceil(math.sqrt(self.y ** 2 + self.x ** 2))
            self.step = step
            self.vote_matrix = np.zeros(
                [math.ceil(self.y / self.step), math.ceil(self.x / self.step), math.ceil(self.radius / self.step)])
            # 投票矩阵,将原图的宽和高,半径分别除以步长,向上取整,
            self.threshold = threshold
            self.circles = []
    
        def Hough_transform_algorithm(self):
            '''
            按照 x,y,radius 建立三维空间,根据图片中边上的点沿梯度方向对空间中的所有单元进行投票。每个点投出来结果为一折线。
            return:  投票矩阵
            '''
            print('Hough_transform_algorithm')
    
            for i in range(1, self.y - 1):
                for j in range(1, self.x - 1):
                    if self.img[i][j] > 0:
                        # 沿梯度正方向投票
                        y = i
                        x = j
                        r = 0
                        while y < self.y and x < self.x and y >= 0 and x >= 0: # 保证圆心在图像内
                            self.vote_matrix[math.floor(y / self.step)][math.floor(x / self.step)][
                                math.floor(r / self.step)] += 1
                            # 为了避免 y / self.step 向上取整会超出矩阵索引的情况,这里将该值向下取整
                            y = y + self.step * self.angle[i][j]
                            x = x + self.step
                            r = r + math.sqrt((self.step * self.angle[i][j]) ** 2 + self.step ** 2)
                        # 沿梯度反方向投票
                        y = i - self.step * self.angle[i][j]
                        x = j - self.step
                        r = math.sqrt((self.step * self.angle[i][j]) ** 2 + self.step ** 2)
                        while y < self.y and x < self.x and y >= 0 and x >= 0:
                            self.vote_matrix[math.floor(y / self.step)][math.floor(x / self.step)][
                                math.floor(r / self.step)] += 1
                            y = y - self.step * self.angle[i][j]
                            x = x - self.step
                            r = r + math.sqrt((self.step * self.angle[i][j]) ** 2 + self.step ** 2)
            return self.vote_matrix   # 返回投票矩阵
    
        def Select_Circle(self):
            '''
            按照阈值从投票矩阵中筛选出合适的圆,并作极大化抑制,这里的非极大化抑制我采
            用的是邻近点结果取平均值的方法,而非单纯的取极大值。
            return: None
            '''
            print('Select_Circle')
    		# 挑选投票数大于阈值的圆
            houxuanyuan = []
            for i in range(0, math.ceil(self.y / self.step)):
                for j in range(0, math.ceil(self.x / self.step)):
                    for r in range(0, math.ceil(self.radius / self.step)):
                        if self.vote_matrix[i][j][r] >= self.threshold:
                            y = i * self.step + self.step / 2   # 通过投票矩阵中的点,恢复到原图中的点,self.step / 2为补偿值
                            x = j * self.step + self.step / 2
                            r = r * self.step + self.step / 2
                            houxuanyuan.append((math.ceil(x), math.ceil(y), math.ceil(r)))
            if len(houxuanyuan) == 0:
                print("No Circle in this threshold.")
                return
            x, y, r = houxuanyuan[0]
            possible = []
            middle = []
            for circle in houxuanyuan:
                if abs(x - circle[0]) <= 20 and abs(y - circle[1]) <= 20: 
                    # 设定一个误差范围(这里设定方圆20个像素以内,属于误差范围),在这个范围内的到圆心视为同一个圆心
                    possible.append([circle[0], circle[1], circle[2]])
                else:
                    result = np.array(possible).mean(axis=0)  # 对同一范围内的圆心,半径取均值
                    middle.append((result[0], result[1], result[2]))
                    possible.clear()
                    x, y, r = circle
                    possible.append([x, y, r])
            result = np.array(possible).mean(axis=0)  # 将最后一组同一范围内的圆心,半径取均值
            middle.append((result[0], result[1], result[2]))  # 误差范围内的圆取均值后,放入其中
    
            def takeFirst(elem):
                return elem[0]
    
            middle.sort(key=takeFirst)  # 排序 
            # 重复类似上述取均值的操作,并将圆逐个输出
            x, y, r = middle[0]
            possible = []
            for circle in middle:  
                if abs(x - circle[0]) <= 20 and abs(y - circle[1]) <= 20:
                    possible.append([circle[0], circle[1], circle[2]])
                else:
                    result = np.array(possible).mean(axis=0)
                    print("Circle core: (%f, %f)  Radius: %f" % (result[0], result[1], result[2]))
                    self.circles.append((result[0], result[1], result[2]))
                    possible.clear()
                    x, y, r = circle
                    possible.append([x, y, r])
            result = np.array(possible).mean(axis=0)
            print("Circle core: (%f, %f)  Radius: %f" % (result[0], result[1], result[2]))
            self.circles.append((result[0], result[1], result[2]))
    
        def Calculate(self):
            '''
            按照算法顺序调用以上成员函数
            return: 圆形拟合结果图,圆的坐标及半径集合
            '''
            self.Hough_transform_algorithm()
            self.Select_Circle()
            return self.circles
    

    4.3主函数代码:

    import time
    import cv2
    import math
    from my_hough import Hough_transform
    from my_canny import Canny
    
    Path = 'C:/Users/Administrator/Desktop/zhongqiu.jpg'   # 图片路径
    Save_Path = 'C:/Users/Administrator/Desktop/'        # 结果保存路径
    Reduced_ratio = 2    # 为了提高计算效率,将图片进行比例缩放所使用的比例值
    Guassian_kernal_size = 3  
    HT_high_threshold = 45
    HT_low_threshold = 25
    Hough_transform_step = 6
    Hough_transform_threshold = 110
    
    if __name__ == '__main__':
        start_time = time.time()
        
        img_gray = cv2.imread(Path, cv2.IMREAD_GRAYSCALE)
        img_RGB = cv2.imread(Path)
        y, x = img_gray.shape[0:2]
        img_gray = cv2.resize(img_gray, (int(x / Reduced_ratio), int(y / Reduced_ratio)))   # 图片缩放
        img_RGB = cv2.resize(img_RGB, (int(x / Reduced_ratio), int(y / Reduced_ratio)))
        
        # canny
        print('Canny ...')
        canny = Canny(Guassian_kernal_size, img_gray, HT_high_threshold, HT_low_threshold)
        canny.canny_algorithm()
        cv2.imwrite(Save_Path + "canny_result.jpg", canny.img)
    
        # hough
        print('Hough ...')
        Hough = Hough_transform(canny.img, canny.angle, Hough_transform_step, Hough_transform_threshold)
        circles = Hough.Calculate()
        for circle in circles:
            cv2.circle(img_RGB, (math.ceil(circle[0]), math.ceil(circle[1])), math.ceil(circle[2]), (132, 135, 239), 2)
        cv2.imwrite(Save_Path + "hough_result.jpg", img_RGB)
        print('Finished!')
        
        end_time = time.time()
        print("running time" + str(end_time - start_time))
    

    4.4运行结果

    canny提取到的轮廓
    请添加图片描述霍夫变换找到的圆(就是月亮!!在月亮上画了红圈圈)
    请添加图片描述

    展开全文
  • 函数使用标准霍夫变换检测二值图像中的。 根据霍夫变换,图像空间中的每个像素对应于霍夫空间中的一个,反之亦然。 图像的左上角是坐标系的原点。 例子 : [y0detect,x0detect,Accumulator] = ...
  • 对于用霍夫变换检测直线而言,在二维笛卡尔坐标系中,直线上的一点映射到霍夫空间的一条直线: 然而直线上的两个不相同的点映射到霍夫空间的两条相交直线: 对于唯一确定的一条直线而言,它映射到霍夫空间是一个...

    霍夫变换是一种特征检测,它的算法流程大致如下,给定一个物件、要辨别的形状的种类,算法会在参数空间中执行投票来决定物体的形状,而这是由累加空间里的局部最大值来决定。
    对于用霍夫变换检测直线而言,在二维笛卡尔坐标系中,直线上的一点映射到霍夫空间的一条直线:
    在这里插入图片描述
    然而直线上的两个不相同的点映射到霍夫空间的两条相交直线:
    在这里插入图片描述
    对于唯一确定的一条直线而言,它映射到霍夫空间是一个确定的点(k,q):
    在这里插入图片描述
    下面简单推导一下直线的极坐标方程(由于图像空间的像素点均是离散的,所以必须转化为直线的极坐标方程)。
    在这里插入图片描述
    上图中,点(p,q)是过原点的垂线与直线的交点,点(x,y)是直线上的任意一点,r是直线距离原点的距离即极径,通过上图点之间的位置关系,可以推导出下述公式:
    在这里插入图片描述
    在这里插入图片描述
    k是直线的斜率,通过直线的点斜式方程
    在这里插入图片描述
    再将前三个等式带入,我们可以得到直线的极坐标方程
    在这里插入图片描述
    上述极坐标方程其实是一条正弦曲线。我们不妨任意选取x和y的值,假设x=2,y=3,得到如下图象:
    在这里插入图片描述
    在这里插入图片描述
    上图是通过matlab对直线进行检测,通过霍夫变换得到的正弦曲线相交的情况,对交点次数大于设定阈值的点进行了标记。
    matlab霍夫变换检测直线的运行结果如下所示:
    在这里插入图片描述
    所以同理可得,在笛卡尔坐标系中若若干个点均共线,则这些点映射到霍夫空间是多条正弦曲线相交于一点。显然,在霍夫空间中,曲线的交点相交次数越多,代表的参数越确定,即在极坐标系中正弦曲线相交次数最多的点就是我们在y-x笛卡尔坐标系中所要求得的直线方程。下面我们再看一下利用霍夫变换检测圆的原理。
    由圆的一般方程公式
    在这里插入图片描述
    可知,由于圆在笛卡尔坐标系中是二维的所以映射到霍夫空间是三维的(即在霍夫空间中a,b,r是变量)。通过圆在笛卡尔坐标系中的参数方程
    在这里插入图片描述
    可知,在霍夫空间中有如下式子成立:
    在这里插入图片描述
    我们不妨通过固定圆的一般方程中的x和y来看一下当a,b,r作为变量时,在三维立体空间是什么样的曲面。
    在这里插入图片描述
    通过matlab得到上述三维空间的曲面和等值线图,为此我们知道对于笛卡尔坐标系中圆上的某个已知点映射到三维霍夫空间实际上是一个圆锥面。对于霍夫变换检测直线,若干个共线点映射到霍夫空间是若干条相交的直线。那么对于霍夫变换检测圆,若干个共圆的点映射到三维霍夫空间是若干个相交的圆锥面。同理,相交次数最多的点就是我们所要求得的在笛卡尔坐标系中的圆的圆心(a,b)和半径r。
    在matlab程序中,先读取灰度图像,然后利用edge()函数选择’Sobel’算子进行边缘检测,返回二值化图像BW,在函数检测到的边缘地方为1其余地方为0。
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    以下是matlab程序源代码:

    I=imread('图像名.xxx')
    BW=edge(I,'sobel')
    imshow(I)
    hold on
    param=findcircle(BW,15,35,1,0.01,0.5); 
    for i=1:size(param,1)
        x0=param(i,1);y0=param(i,2);r0=param(i,3)
        xi=[-r0:0 0:r0]
        yi=round((r0^2-xi.^2).^0.5)
        plot(yi+y0,xi+x0,'color','g','linewidth',5)
        plot(-yi+y0,xi+x0,'color','g','linewidth',5)
    end
    title('经过霍夫变换得到的特征提取','fontsize',20)
    
    function[circlefind]=findcircle(img,minr,maxr,stepr,stepa,percent)
    r=round((maxr-minr)/stepr)+1;%可增长的步长个数
    angle=round(2*pi/stepa);
    [m,n]=size(img);
    houghspace=zeros(m,n,r);%霍夫空间
    [m1,n1]=find(img);%返回二值化边缘检测图像Img中非零点的坐标,m1存放横坐标,n1存放纵坐标
    num=size(m1,1);%非零点个数
    %a = x-r*cos(angle), b = y-r*sin(angle)
    for i=1:num
        for j=1:r
            for k=1:angle
                a=round(m1(i)-(minr+(j-1)*stepr)*cos(k*stepa));
                b=round(n1(i)-(minr+(j-1)*stepr)*sin(k*stepa));
                if(a>0&&a<=m&&b>0&&b<=n)
                    houghspace(a,b,j)=houghspace(a,b,j)+1;
                end
            end
        end
    end
    par=max(max(max(houghspace)));%找出个数最多的圆的数量作为阈值
    par2=par*percent;%百分比percent阈值调整
    [m2,n2,r2]=size(houghspace);
    circlefind=[];%存储大于阈值的圆的圆心坐标及半径
    for i=1:m2
        for j=1:n2
            for k=1:r2
                if (houghspace(i,j,k)>=par2)
                    a=[i,j,minr+k*stepr];
                    circlefind=[circlefind;a];
                end
            end
        end
    end
    end
    

    结果如下所示:
    在这里插入图片描述
    findcircle()函数中,参数minr,maxr分别是圆的最小和最大半径,在参数值选择上要注意合理选择,如果minr的值设置的过大,则很有可能很多半径较小的圆无法检测出来;如果maxr设置的过小,则半径较大的圆可能无法检测出来。所以在参数设置之前要对圆的半径取值范围有大概了解。而参数stepr可以理解为半径r的增长步长,如果stepr选择过小,则程序迭代次数过多,计算量大,对于图像中圆的半径值变化不太细微的情况应适当让stepr的值高一些。而percent是阈值参数,设置的时候不要太高,否则会造成漏选的情况。stepa参数的取值应尽可能的接近0,程序中参数方程中的角度是k*stepa,其取值范围为(0,2π]。

    展开全文
  • 霍夫变换检测圆形 -opencv

    千次阅读 2021-05-18 15:41:13
    4:霍夫变换检测到的的圆心之间的最小距离,即让我们的算法能明显区分的两个不同之间的最小距离。这个参数如果太小的话,多个相邻的可能被错误地检测成了一个重合的。反之,这个参数设置太大的话,某些就...

    在这里插入图片描述

    在这里插入图片描述

    import cv2
    path='../../img/img.jpg'
    img=cv2.imread(path,1)
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    circles1 = cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,1, 30,param1=100,param2=30,minRadius=3,maxRadius=97)
    print(circles1)
    for i in circles1[0]:
        img=cv2.circle(img,(i[0],i[1]),int(i[2]),(255,0,0),6)
    cv2.imshow('circle',img)
    cv2.waitKey(0)
    

    1:参数一为输入图像要8位灰度图像
    2:使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
    3:检测圆心的累加器图像的分辨率于输入图像之比的倒数,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
    4:霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
    5:param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
    6:param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了。
    7:int类型的minRadius,有默认值0,表示圆半径的最小值。
    8:int类型的maxRadius,也有默认值0,表示圆半径的最大值。

    展开全文
  • 简单的Canny边缘检测程序,另外包含霍夫变换检测道路直线。
  • 霍夫变换,用于圆检测,可进行图像处理。内附MATLAB的代码
  • 霍夫变换检测圆和直线.docx霍夫变换检测圆和直线.docx霍夫变换检测圆和直线.docx霍夫变换检测圆和直线.docx霍夫变换检测圆和直线.docx霍夫变换检测圆和直线.docx霍夫变换检测圆和直线.docx霍夫变换检测圆和直线.docx
  • 霍夫变换检测圆和直线.pdf霍夫变换检测圆和直线.pdf霍夫变换检测圆和直线.pdf霍夫变换检测圆和直线.pdf霍夫变换检测圆和直线.pdf霍夫变换检测圆和直线.pdf霍夫变换检测圆和直线.pdf霍夫变换检测圆和直线.pdf
  • 实用讲义 问题陈述 编写一个简单的霍夫特征检测器,可以检测输入图像中任意大小的。 该程序必须支持以下功能: ...每个半径为 1..n 的霍夫变换,其中 n 是可能的最大半径 找到霍夫空间图像中的亮点,并将其标
  • HOUGHCIRCLES 使用霍夫变换检测图像中的多个磁盘(硬币)。 图像包含分离、接触或重叠的圆盘,其中心可能在图像内或外。 句法houghcircles(im, minR, maxR); houghcircles(im, minR, maxR, thresh); houghcircles...
  • 主要介绍了Python实现霍夫圆和椭圆变换代码详解,具有一定借鉴价值,需要的朋友可以参考下
  • Hough变换检测Hough变换的基本原理在于,利用点与线的对偶性,将图像空间的线条变为参数空间的聚集点,从而检测给定图像是否存在给定性质的曲线。Hough对检测程序如下完整的程序及实例效果见附件% p:阈值...
  • OpenCV霍夫变换检测圆形,Python

    千次阅读 2020-06-02 07:50:55
    假设现在把图中的足球圆形轮廓检测出来,并用红线标记: python代码: import cv2 import numpy as np if __name__ == "__main__": original_img = cv2.imread("c.jpg") gray = cv2.cvtColor(original_img...
  • Xcode 10.0 利用opencv的霍夫变换画出并输出硬币直径。 本代码用5角,已提供例图,需要设置开发者ID及5角钱图片的路径
  • 霍夫变换检测圆和直线 数字图像处理的课程设计 直接使用 非常方便
  • 主要实现的功能是能实时识别视频中的,并返回圆心位置 import cv2 import numpy as np def decodeDisplay(video, flag): gay_img = cv2.cvtColor(video, cv2.COLOR_BGRA2GRAY) img = cv2.medianBlur(gay_img, 7...
  • 使用Matlab编写的椭圆霍夫变换代码,方便初学者学习霍夫变换基本原理。使用时输入一副二值图像,可以预估待检测椭圆的长短轴、倾角等参数,减少运算时间。
  • Opencv 霍夫空间 霍夫变换 霍夫圆检测
  • 霍夫变换检测圆形

    2018-01-31 14:05:00
    利用OpenCV霍夫变换检测 【OpenCV入门教程之十四】OpenCV霍夫变换:霍夫线变换,霍夫变换合辑 Opencv--HoughCircles源码剖析  HoughCircles函数可以利用霍夫变换算法检测出灰度图中的。它和之前的...
  • 这个霍夫变换是高度优化的。 它使用中点算法在投票空间中快速且无间隙地绘制。 如果已知圆形位置的粗略估计,它还包括仅搜索图像的一部分以提高速度的选项。
  • 霍夫变换检测圆形原理分析

    万次阅读 多人点赞 2017-03-01 22:49:04
    上一篇博客中简要描述了一下自己对霍夫变换检测直线的原理理解,现在说一下检测圆形的原理。 其实检测圆形和检测直线的原理差别不大,只不过直线是在二维空间,因为y=kx+b,只有k和b两个自由度。而圆形的一般性...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,740
精华内容 1,496
关键字:

霍夫变换检测圆

友情链接: Texture_Synthesis.zip