首页 > 其他分享 >Hough变换

Hough变换

时间:2024-07-28 15:55:20浏览次数:5  
标签:plt idx Hough 变换 range rho np theta

python实现广义Hough变换算法、Hough变换算法

      • 1.广义Hough变换算法详解
        • 算法步骤
        • Python 实现
        • 详细解释
        • 优缺点
      • 2.Hough变换算法详解
        • 算法步骤
        • Python 实现
        • 详细解释
        • 优缺点

 

实现广义Hough变换算法(Generalized Hough Transform)可以用于检测任意形状的对象,不限于标准的直线或圆形。这里将详细介绍广义Hough变换的原理及其Python实现。

1.广义Hough变换算法详解

广义Hough变换的基本原理是将目标形状(通常用边缘检测后的二值图像表示)的每个像素点转化为其可能的参数空间(例如,中心点、旋转角度等)中的投票。通过累积这些投票,可以找到在图像中存在的目标形状的位置和方向。

算法步骤
  1. 预处理:获取目标形状的边缘图像。

  2. 定义参数空间:根据目标形状的特征,定义参数空间(通常是多维的),例如中心点坐标、角度、比例等。

  3. 填充累加器:对于每个目标形状的像素点,计算其在参数空间中的可能位置,并在累加器中进行累加。

  4. 确定目标位置:在累加器中找到最高投票的位置,该位置即为目标形状在原始图像中的位置和属性。

Python 实现

以下是广义Hough变换的Python实现示例,用于检测图像中的任意形状。这里以检测矩形为例子。

import cv2
import numpy as np
import matplotlib.pyplot as plt

def generalized_hough_transform(image, template):
    """
    广义Hough变换算法实现,用于检测任意形状的对象

    参数:
    image (numpy.ndarray): 输入的灰度图像
    template (numpy.ndarray): 目标形状的二值化模板图像

    返回:
    tuple: 目标形状在原始图像中的位置和属性信息
    """
    # 提取目标形状的边缘
    edges = cv2.Canny(template, 50, 150)

    # 计算目标形状的参数空间
    accumulator = np.zeros_like(image, dtype=np.uint64)

    rows, cols = np.nonzero(edges)
    for i in range(len(rows)):
        y = rows[i]
        x = cols[i]
        for theta in range(0, 180):  # 假设角度范围
            rho = x * np.cos(np.deg2rad(theta)) + y * np.sin(np.deg2rad(theta))
            rho = int(rho)
            accumulator[rho, theta] += 1

    # 找到最高投票的位置
    rho_idx, theta_idx = np.unravel_index(np.argmax(accumulator), accumulator.shape)
    rho = rho_idx - accumulator.shape[0] // 2  # 转换为原始坐标系中的rho
    theta = np.deg2rad(theta_idx)  # 转换为角度

    return rho, theta

# 示例用法
if __name__ == "__main__":
    # 读取图像
    image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
    template = cv2.imread('template.png', cv2.IMREAD_GRAYSCALE)

    # 调用广义Hough变换算法
    rho, theta = generalized_hough_transform(image, template)

    # 显示原始图像和检测结果
    plt.figure(figsize=(12, 6))
    plt.subplot(1, 2, 1)
    plt.title('Original Image')
    plt.imshow(image, cmap='gray')
    plt.axis('off')

    plt.subplot(1, 2, 2)
    plt.title('Detected Shape')
    plt.imshow(cv2.cvtColor(template, cv2.COLOR_GRAY2RGB))
    plt.axis('off')

    # 绘制检测到的形状
    h, w = template.shape
    cos_theta = np.cos(theta)
    sin_theta = np.sin(theta)
    x0 = cos_theta * rho
    y0 = sin_theta * rho
    x1 = int(x0 + 1000 * (-sin_theta))
    y1 = int(y0 + 1000 * (cos_theta))
    x2 = int(x0 - 1000 * (-sin_theta))
    y2 = int(y0 - 1000 * (cos_theta))
    plt.plot([x1, x2], [y1, y2], 'r-', lw=2)

    plt.show()
详细解释

 

1. 提取目标形状的边缘:

 

edges = cv2.Canny(template, 50, 150)

 

使用Canny边缘检测算法获取目标形状的二值化边缘图像。

 

 

2. 计算目标形状的参数空间:

 

accumulator = np.zeros_like(image, dtype=np.uint64)

 

创建一个累加器数组,用于累计目标形状的投票。

 

 

3. 填充累加器:

 

for i in range(len(rows)):
    y = rows[i]
    x = cols[i]
    for theta in range(0, 180):  # 假设角度范围
        rho = x * np.cos(np.deg2rad(theta)) + y * np.sin(np.deg2rad(theta))
        rho = int(rho)
        accumulator[rho, theta] += 1

 

遍历目标形状的边缘像素,计算其在参数空间(rho, theta)中的投票,并在累加器中进行累加。

 

 

4. 找到最高投票的位置:

 

rho_idx, theta_idx = np.unravel_index(np.argmax(accumulator), accumulator.shape)
rho = rho_idx - accumulator.shape[0] // 2  # 转换为原始坐标系中的rho
theta = np.deg2rad(theta_idx)  # 转换为角度

在累加器中找到最高投票的位置,并将其转换为原始图像坐标系中的rho和角度theta。

5. 显示和保存检测结果:

plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(image, cmap='gray')
plt.axis('off')

plt.subplot(1, 2, 2)
plt.title('Detected Shape')
plt.imshow(cv2.cvtColor(template, cv2.COLOR_GRAY2RGB))
plt.axis('off')

# 绘制检测到的形状
h, w = template.shape
cos_theta = np.cos(theta)
sin_theta = np.sin(theta)
x0 = cos_theta * rho
y0 = sin_theta * rho
x1 = int(x0 + 1000 * (-sin_theta))
y1 = int(y0 + 1000 * (cos_theta))
x2 = int(x0 - 1000 * (-sin_theta))
y2 = int(y0 - 1000 * (cos_theta))
plt.plot([x1, x2], [y1, y2], 'r-', lw=2)

plt.show()
  1. 使用Matplotlib库显示原始图像和检测到的形状,以及在检测结果图像上绘制检测到的形状。

优缺点

优点:

  • 适用性广泛:能够检测任意形状的对象,不限于直线或圆形。
  • 灵活性:通过定义不同的参数空间,可以适应不同形状的检测需求。

缺点:

  • 计算复杂度高:需要对每个像素点在多维参数空间中进行累加,对计算资源要求高。
  • 对参数敏感:参数的选择对检测结果影响较大,需要根据具体应用进行调整。

广义Hough变换算法在实际应用中需要根据具体场景和目标形状进行参数调整和优化,以达到最佳的检测效果。
Hough变换是一种经典的图像处理技术,用于检测图像中的直线。它通过将图像空间中的像素点映射到参数空间(Hough空间),并在参数空间中进行累加来检测直线。以下是Hough变换的详细介绍和Python实现。

2.Hough变换算法详解

算法步骤
  1. 边缘检测:首先对图像进行边缘检测,通常使用Canny边缘检测器获取二值化的边缘图像。

  2. 参数空间初始化:根据图像的尺寸和角度范围初始化Hough变换的参数空间。对于检测直线,通常使用极坐标参数表示:极径(r)和极角(θ)。

  3. 累加器填充:遍历边缘图像中的每个像素点,对每个边缘像素点计算其可能的直线参数,并在Hough累加器中进行累加。

  4. 找出累加器中的峰值:在累加器中找到高投票的点,这些点表示了可能的直线参数(r, θ)。

  5. 反映射直线到图像空间:将在参数空间中找到的直线参数(r, θ)反映射到原始图像空间中,并绘制检测到的直线。

Python 实现

以下是使用Python和OpenCV库实现Hough变换算法检测直线的示例代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt

def hough_transform(image, edge_image, threshold):
    """
    实现Hough变换检测图像中的直线

    参数:
    image (numpy.ndarray): 输入的灰度图像
    edge_image (numpy.ndarray): 边缘检测后的二值化图像
    threshold (int): 累加器阈值,用于确定直线检测的灵敏度

    返回:
    list: 检测到的直线的参数列表 [(rho1, theta1), (rho2, theta2), ...]
    """
    # 图像尺寸
    height, width = edge_image.shape

    # 极坐标参数空间的r和theta的步长
    theta_step = 1
    r_step = 1

    # 极坐标参数空间的范围
    max_rho = int(np.sqrt(height**2 + width**2))  # 极径的最大值
    theta_range = np.arange(0, 180, theta_step)
    rho_range = np.arange(-max_rho, max_rho, r_step)

    # 构建累加器
    accumulator = np.zeros((len(rho_range), len(theta_range)), dtype=np.uint64)

    # 边缘图像中的非零像素点
    edge_points = np.argwhere(edge_image > 0)

    # 遍历每个边缘像素点
    for y, x in edge_points:
        for theta_idx, theta in enumerate(np.deg2rad(theta_range)):
            rho = int(x * np.cos(theta) + y * np.sin(theta))
            rho_idx = np.argmin(np.abs(rho_range - rho))
            accumulator[rho_idx, theta_idx] += 1

    # 获取高投票的直线参数
    lines = []
    for rho_idx in range(len(rho_range)):
        for theta_idx in range(len(theta_range)):
            if accumulator[rho_idx, theta_idx] > threshold:
                rho = rho_range[rho_idx]
                theta = np.deg2rad(theta_range[theta_idx])
                lines.append((rho, theta))

    return lines

# 示例用法
if __name__ == "__main__":
    # 读取图像
    image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)

    # 边缘检测
    edge_image = cv2.Canny(image, 50, 150)

    # 进行Hough变换
    threshold = 100  # 累加器阈值
    detected_lines = hough_transform(image, edge_image, threshold)

    # 绘制检测到的直线
    plt.figure(figsize=(8, 6))
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_GRAY2RGB))
    plt.title('Detected Lines')
    plt.axis('off')

    for rho, theta in detected_lines:
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0 + 1000 * (-b))
        y1 = int(y0 + 1000 * (a))
        x2 = int(x0 - 1000 * (-b))
        y2 = int(y0 - 1000 * (a))
        plt.plot([x1, x2], [y1, y2], 'r-', lw=2)

    plt.show()
详细解释
  1. 边缘检测:

    edge_image = cv2.Canny(image, 50, 150)

    使用Canny边缘检测算法获取图像的二值化边缘图像。

  2. 初始化参数空间:

    max_rho = int(np.sqrt(height**2 + width**2))  # 极径的最大值
    theta_range = np.arange(0, 180, theta_step)
    rho_range = np.arange(-max_rho, max_rho, r_step)
    accumulator = np.zeros((len(rho_range), len(theta_range)), dtype=np.uint64)

    初始化极坐标参数空间(rho, theta)及其对应的累加器。

  3. 填充累加器:

    for y, x in edge_points:
        for theta_idx, theta in enumerate(np.deg2rad(theta_range)):
            rho = int(x * np.cos(theta) + y * np.sin(theta))
            rho_idx = np.argmin(np.abs(rho_range - rho))
            accumulator[rho_idx, theta_idx] += 1

    遍历边缘图像中的每个像素点,计算其可能的直线参数(rho, theta),并在累加器中进行累加。

  4. 找出高投票的直线参数:

    lines = []
    for rho_idx in range(len(rho_range)):
        for theta_idx in range(len(theta_range)):
            if accumulator[rho_idx, theta_idx] > threshold:
                rho = rho_range[rho_idx]
                theta = np.deg2rad(theta_range[theta_idx])
                lines.append((rho, theta))

    在累加器中找到累计值超过阈值的点,即为检测到的直线参数(rho, theta)。

  5. 绘制检测到的直线:

    plt.figure(figsize=(8, 6))
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_GRAY2RGB))
    plt.title('Detected Lines')
    plt.axis('off')
    
    for rho, theta in detected_lines:
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0 + 1000 * (-b))
        y1 = int(y0 + 1000 * (a))
        x2 = int(x0 - 1000 * (-b))
        y2 = int(y0 - 1000 * (a))
        plt.plot([x1, x2], [y1, y2], 'r-', lw=2)
    
    plt.show()

    使用Matplotlib库在原始图像上绘制检测到的直线。

优缺点

优点:

  • 适用性广泛:能够检测直线,简单且有效。
  • 不依赖于直线的长度和位置:适用于检测任意方向的直线。

缺点:

  • 对参数的选择敏感:参数的选择(如阈值)会影响检测结果,需要根据具体情况调整。
  • 计算复杂度高:需要遍历边缘图像中的每个像素点,并在参数空间中进行累加,计算量较大。

Hough变换是一种经典且重要的图像处理技术,在许多计算机视觉和图像分析应用中都有广泛应用。

标签:plt,idx,Hough,变换,range,rho,np,theta
From: https://www.cnblogs.com/Gaowaly/p/18328324

相关文章

  • Matlab编程资源库(10)离散傅立叶变换
    一、离散傅立叶变换算法简要给定一个N点的离散信号序列x(n),其中n表示时刻,n=0,1,2,...,N-1。定义离散傅立叶变换的频域序列X(k),其中k表示频率,k=0,1,2,...,N-1。通过以下公式计算每个频率对应的复数值: X(k)=Σx(n)*exp(-j*2π*kn/N),其中j表示虚......
  • 霍夫(Hough)直线变换(直线检测)
    0原理 霍夫变换在检测各种形状的的技术中非常流行,如果你要检测的形状可以用数学表达式写出,你就可以是使用霍夫变换检测它。及时要检测的形状存在一点破坏或者扭曲也可以使用。我们下面就看看如何使用霍夫变换检测直线。首先将一条直线用一个点表示,这样用一个点表示直线上......
  • 《昇思25天学习打卡营第5天|数据变换 Transforms》
    数据变换Transforms通常情况下,直接加载的原始数据并不能直接送入神经网络进行训练,此时我们需要对其进行数据预处理。MindSpore提供不同种类的数据变换(Transforms),配合数据处理Pipeline来实现数据预处理。所有的Transforms均可通过map方法传入,实现对指定数据列的处理......
  • 基于 SIFT 和小波变换的图像拼接融合研究用matlab进行实现
     研究背景与意义本文涉及到的图像融合方法,它是基于SIFT和小波变换完成图像处理,相对于传统方法表现出更优秀的性能,能够显著减少合并后的不完美之处,从而提升图像的品质和内容的完整性。这表明这种方法可能会在实践中被更多地接受和应用,为图像处理领域的进一步发展做出积极助益......
  • 图像透视变换技术
    文章目录概要技术原理实现步骤总结透视变换矩阵的通用性小结概要图像透视变换(PerspectiveTransformation)是计算机视觉中一种重要的图像变换方法,它可以将图像从一个视角投影到另一个视角,从而改变图像的几何形状。透视变换常用于矫正图像的透视失真、图像配准、生成......
  • Groupby 以及变换和回归
    我试图从简单的回归中获得残差。此回归按每个年份和组进行。这就是我所做的。但是,有没有办法将残差作为新列与原始数据帧一起获取?df=pd.DataFrame({'Name':['a','b','c','d','e','a','b','c','d','e','a',&......
  • 力扣6. Z 字形变换
    将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z字形排列。比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:PAHNAPLSIIGYIR之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。......
  • 拉氏变换转化为傅里叶变换
    说明:关于将象函数转为傅里叶变换,部分院校考研或期末考题会出现,但大部分辅导机构和网络资料枚举的例题对于这部分内容的阐述不全面,而杨晓非老师的《信号与系统(第二版》对这部分解析比较好,但有部分地方需要说明解释一下,故著以此章便于同学们理解。1傅里叶变换的存在性首先需要......
  • G2O(2) 基本例子 3D-3D位姿求解 -( 一元点多边 3D点对位姿求解)求解3D点1到3D点2的变换
     残差1通常2D像素对3D点位姿和点    2但是这个里面没有2D像素,是单纯的3D点对3D点位姿求解   CMakeLists.txtcmake_minimum_required(VERSION2.8)project(vo1)set(CMAKE_BUILD_TYPE"Release")add_definitions("-DENABLE_SSE")set(CMAKE_CXX_FLAGS......
  • 苦学Opencv的第六天:图像的几何变换
    PythonOpenCV入门到精通学习日记:图像的几何变换前言几何变换,顾名思义就是修改图像的几何结构,例如大小,角度和形状等等,让图像呈现不同的效果。这些几何变换的操作一般都涉及复杂且精密的计算,Opencv将这些计算过程全部都包装成了各种灵活的方法,我们只需要修改一些参数,就能实......