一、霍夫变换概述

霍夫变换是一种可用于隔离图像中特定形状的特征的技术。因为它要求以某种参数形式指定所需的特征,所以 经典霍夫变换最常用于检测规则曲线,如直线、圆、椭圆

        广义霍夫变换可用于简单的应用中一个或多个特征的分析描述是不可能的。由于广义霍夫算法的计算复杂性,我们将讨论的主要焦点限制在经典霍夫变换上。

尽管存在域限制,但经典 Hough 变换(以下简称为没有 经典前缀)保留了许多应用,因为大多数制造部件(以及医学图像中研究的许多解剖部件)都包含可以用规则曲线描述的特征边界。

霍夫变换技术的主要优点是它可以容忍特征边界描述中的间隙,并且相对不受图像噪声的影响。

使用 Hough 变换算法进行线检测

二、原理概述

1、概述

在给定(可能有噪声的)局部测量的情况下,霍夫技术对于计算一个或多个特征的全局描述(其中解决方案类别的数量不需要先验)特别有用。用于线检测的 Hough 技术背后的动机是每个输入测量值(例如坐标点)表明它对全局一致解决方案的贡献(例如产生该图像点的物理线)。

作为一个简单的例子,考虑将一组线段拟合到一组离散图像点(例如从边缘检测器输出的像素位置)的常见问题。图 1 显示了该问题的一些可能解决方案。这里缺乏关于所需线段数量的先验知识(以及关于什么构成线段的模糊性)使得这个问题受到限制。

a)坐标点。b)和 c)可能的直线。

我们可以用多种形式分析地描述线段。然而,描述一组线的方便方程使用参数或法线概念:

其中是从原点到这条线的法线长度,相对于轴的方向。(下图)对于这条线上的任何点, 都是常数。

直线的描述方式之一

在图像分析上下文中,图像中边缘段的点的坐标是已知的,因此在参数线方程中用作常数,而是我们寻求的未知变量。如果我们绘制每个 定义的可能值,笛卡尔图像空间中的点映射到极坐标霍夫参数空间中的曲线(正弦曲线)。这种点到曲线的变换是直线的霍夫变换。当在 Hough 参数空间中查看时,在笛卡尔图像空间中共线的点变得很明显,因为它们产生在公共点相交的曲线。

变换是通过将霍夫参数空间量化为有限区间或累加器单元来实现的。随着算法的运行,每个都被转换为离散曲线,并且沿着这条曲线的累加器单元递增。累加器阵列中产生的峰值代表了图像中存在相应直线的有力证据。

我们可以使用相同的过程来检测具有分析描述的其他特征。例如,在的情况下,参数方程是其中是圆心的坐标,是半径。在这种情况下,算法的计算复杂度开始增加,因为我们现在在参数空间中有三个坐标和一个 3-D 累加器。(一般来说,累加器数组的计算量和大小随着参数的数量呈多项式增加。因此,这里描述的基本 Hough 技术仅适用于简单曲线。)

2、算法

1、​​​​​​​确定 ρ 和 θ 的范围。通常,θ 的范围是 [ 0, 180 ] 度,ρ是 [ - d , d ],其中d是边缘图像对角线的长度。量化 ρ 和 θ 的范围很重要,这意味着应该有有限数量的可能值。

2、创建一个称为累加器的二维数组,表示具有维度(num_rhos,num_thetas)的霍夫空间,并将其所有值初始化为零。

3、对原始图像进行边缘检测。这可以通过您选择的任何边缘检测算法来完成。

4、对于边缘图像上的每个像素,检查该像素是否为边缘像素。如果是边缘像素,遍历所有可能的 θ 值,计算对应的 ρ,在累加器中找到 θ 和 ρ 索引,并根据这些索引对递增累加器。

5、循环遍历累加器中的所有值。如果该值大于某个阈值,则获取 ρ 和 θ 索引,从索引对中获取 ρ 和 θ 的值,然后可以将其转换回y = ax + b的形式。

3、线条检测过程

检测图像中线条的过程。霍夫空间中的黄点表示存在线,并由 θ 和 ρ 对表示。

如前所述,边缘点在霍夫空间中产生余弦曲线。由此,如果我们将边缘图像中的所有边缘点映射到霍夫空间上,就会产生很多余弦曲线。如果两个边缘点位于同一条线上,则它们对应的余弦曲线将在特定的 (ρ, θ) 对上相交。因此,霍夫变换算法通过查找具有大于某个阈值的多个交点的 (ρ, θ) 对来检测线。值得注意的是,如果不对霍夫空间进行邻域抑制等预处理以去除边缘图像中的相似线条,这种阈值方法可能并不总是产生最佳结果。

三、简单示例

霍夫变换可用于识别最适合一组给定边缘点的曲线参数。该边缘描述通常从特征检测算子(例如Roberts Cross、Sobel或 Canny边缘检测器)获得,并且可能是有噪声的,即它可能包含对应于单个整体特征的多个边缘片段。此外,由于边缘检测器的输出仅定义 特征在图像中的位置,因此霍夫变换的工作是确定特征是什么(即检测具有参数(或其他)的特征) 描述) 以及 有多少其中存在于图像中。

为了详细说明霍夫变换,我们从两个遮挡矩形的简单图像开始,Canny 边缘检测器可以为这部分生成一组边界描述,如图

在这里,我们看到了图像中的整体边界,但是这个结果没有告诉我们关于这个边界描述中特征的身份(和数量)的任何信息。在这种情况下,我们可以使用霍夫(线检测)变换来检测该图像的八个单独的直线段,从而识别出对象的真实几何结构。

如果我们使用这些边缘/边界点作为 Hough 变换的输入,则会在极坐标空间中为笛卡尔空间中的每个边缘点生成一条曲线。 累加器阵列,当被视为强度图像时,看起来像

均衡图像的直方图使我们能够看到包含在低强度像素值中的信息模式,如图所示

请注意,虽然是概念上的极坐标,但累加器空间以矩形绘制 ,横坐标和纵坐标。请注意,累加器空间在图像的垂直边缘处环绕,因此实际上只有 8 个真正的峰值。

梯度图像中共线点生成的曲线方程:在霍夫变换空间中的峰值处相交。这些交点表征了原始图像的直线段。有许多方法可以用来从累加器阵列中提取这些亮点或局部最大值。例如,一种简单的方法涉及 阈值化,然后 对累加器阵列图像中孤立的亮点簇应用一些细化。这里我们使用一个相对阈值来提取唯一 方程:对应于原始图像中每条直线边缘的点。(换句话说,我们只取累加器数组中的那些局部最大值,其值等于或大于全局最大值的某个固定百分比。)

从霍夫变换空间(即 去霍夫)映射回笛卡尔空间会产生一组图像主题的线描述。通过将此图像叠加在原始图像的倒置版本上,我们可以确认 Hough 变换找到了两个矩形的 8 个真实边的结果,从而揭示了被遮挡场景的基本几何形状

请注意,在这个简单的例子中,检测到的和原始图像线的对齐精度显然不是完美的,它是由累加器阵列的量化决定的。(另请注意,许多图像边缘有几条检测到的线。这是由于附近有几个具有相似线参数值的霍夫空间峰值。存在控制这种效果的技术,但这里没有用于说明标准霍夫的输出转换。)

还要注意,霍夫变换生成的线是无限长的。如果我们希望识别生成变换参数的实际线段,则需要进一步的图像分析,以查看这些无限长线的哪些部分实际上有点。

四、参考代码

1、原图如下

2、霍夫变换/反变换图像

3、参考代码

这个代码并不严谨,仅供参考。

(1)霍夫变换代码

private int[,] houghMap = new int[180, 180];
private int maxHough  = 0;
private Bitmap bmpHough = new Bitmap("a.jpg");// 霍夫变换
private void hough_Load()
{Rectangle rect = new Rectangle(0, 0, bmpHough.Width, bmpHough.Height);System.Drawing.Imaging.BitmapData bmpData = bmpHough.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmpHough.PixelFormat);IntPtr ptr = bmpData.Scan0;int bytes = bmpHough.Width * bmpHough.Height;byte[] grayValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);bmpHough.UnlockBits(bmpData);Array.Clear(houghMap, 0, 32400);for (int i = 0; i < bmpHough.Height - 1; i++){for (int j = 0; j < bmpHough.Width - 1; j++){if (grayValues[i * bmpHough.Width + j] == 255){for (int thet = 0; thet < 180; thet++){double arc = thet * Math.PI / 180;int rho = Convert.ToInt32((j * Math.Cos(arc) + i * Math.Sin(arc)) / 8) + 90;rho = rho>179 ? 179 : rho;houghMap[thet, rho]++;if (maxHough < houghMap[thet, rho])maxHough = houghMap[thet, rho];}}}}
}

(2)反霍夫变换代码

private void hough_Paint(object sender, PaintEventArgs e)
{Bitmap houghImage = new Bitmap(180, 180, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);System.Drawing.Imaging.ColorPalette cp = houghImage.Palette;for (int i = 0; i < 256; i++){cp.Entries[i] = Color.FromArgb(i, i, i);}houghImage.Palette = cp;Rectangle rectHough = new Rectangle(0, 0, 180, 180);System.Drawing.Imaging.BitmapData houghData = houghImage.LockBits(rectHough, System.Drawing.Imaging.ImageLockMode.ReadWrite, houghImage.PixelFormat);IntPtr ptr = houghData.Scan0;int bytes = 180 * 180;byte[] grayHough = new byte[bytes];for (int i = 0; i < 180; i++){for (int j = 0; j < 180; j++){grayHough[i * 180 + j] = Convert.ToByte(houghMap[i, j] * 255 / maxHough);}}System.Runtime.InteropServices.Marshal.Copy(grayHough, 0, ptr, bytes);houghImage.UnlockBits(houghData);Graphics g = e.Graphics;g.DrawImage(houghImage, 40, 20, 180, 180);g.FillRectangle(Brushes.Black, 250, 20, 180, 180);double thresholding = maxHough * 0.6;double k, b;int x1, x2, y1, y2;for (int i = 0; i < 180; i++){for (int j = 0; j < 180; j++){if (houghMap[i, j] > thresholding){if (i == 90){g.DrawLine(Pens.White, 250, 200, 250, 20);}else if (i == 0)g.DrawLine(Pens.White, 250, 430, 250, 20);else{k = (-1 / Math.Tan(i * Math.PI / 180));b = ((j - 90) * 8 / Math.Sin(i * Math.PI / 180)) *180 / 512;if (b >= 0 && b <= 180){x1 = 0;y1 = Convert.ToInt32(b);double temp = -b / k;if (temp <= 180 && temp >= 0){x2 = Convert.ToInt32(temp);y2 = 0;}else if (temp >= -180 && temp < 0){x2 = Convert.ToInt32((180 - b) / k);y2 = 180;}else{x2 = 180;y2 = Convert.ToInt32(180 * k + b);}}else if (b < 0){x1 = Convert.ToInt32(-b / k);y1 = 0;double temp = k * 180 + b;if (temp >= 0 && temp <= 180){x2 = 180;y2 = Convert.ToInt32(temp);}else{x2 = Convert.ToInt32((180 - b) / k);y2 = 180;}}else{x1 = Convert.ToInt32((180 - b) / k);y1 = 180;double temp = k * 180 + b;if (temp >= 0 && temp <= 180){x2 = 180;y2 = Convert.ToInt32(temp);}else{x2 = Convert.ToInt32(-b / k);y2 = 0;}}g.DrawLine(Pens.White, x1 + 250, y1 + 20, x2 + 250, y2 + 20);}}}                }g.DrawString("Hough变换映射图像", new Font("Arial", 8), Brushes.Black, 80, 210);g.DrawString("Hough反变换图像", new Font("Arial", 8), Brushes.Black, 290, 210);
}

数字图像处理 什么是霍夫变换?相关推荐

  1. 数字图像处理知识总结

    一:基本概念 数字图像:指由被称作像素的小块区域组成的二维矩阵.将物理图像行列划分后,每个小块区域称为像素(pixel).每个像素包括两个属性:位置和灰度. 图像数字化一般分为采样.量化与编码三个步骤 ...

  2. 大学生学图像处理计算机要求,重点大学计算机教材:数字图像处理

    重点大学计算机教材:数字图像处理 语音 编辑 锁定 讨论 上传视频 <重点大学计算机教材:数字图像处理>是2012年机械工业出版社出版的图书,作者是姚敏.[1] 书    名 重点大学计算 ...

  3. 数字图像处理——隐形眼镜缺陷检测算法

    数字图像处理--隐形眼镜缺陷检测算法 摘 要:本文致力于寻找出一种具有较强鲁棒性的检测隐形眼镜边缘缺陷的方法.本文针对图像中物体几何形状的特殊性,提出了一种基于霍夫变换的缺陷检测算法,并在低噪声图像的 ...

  4. 《数字图像处理 MATLAB版》学习笔记

    学习教材:<数字图像处理 MATLAB版>(第二版) 冈萨雷斯 学习过程中的图片代码和及我收集的一些关于数字图像处理的其他学习资料,需要的可以评论留下邮箱(需要购买专栏),加油 文章目录 ...

  5. 数字图像处理第十章 图像分割

    图像分割 1 基础知识 2 点.线和边缘检测 2.1 点检测 2.2 线检测 2.3 边缘检测 3 使用霍夫变换的线检测 3.1 函数hough 3.2 函数houghpeaks和函数houghlin ...

  6. 数字图像处理复习笔记

    数字图像处理基础 1.绪论 1.1 数字图像的概念 图像:用各种观测系统以不同的形式或者手段观测客观世界从而获得的可以直接或者间接作用于人的视觉系统而产生的视知觉实体.其中图像可分成"图&q ...

  7. 数字图像处理第十章——图像分割

    数字图像处理第十章 数字图像处理---图像分割 (一)点.线和边缘检测 1.1 点检测 1.2 线检测 1.3 使用函数edge的边缘检测 (二)使用霍夫变换的线检测 2.1 函数hough 2.2 ...

  8. 数字图像处理复习(part3)

    数字图像处理复习(part3) 前面提到了空间域变换,接下来开始频率域变换,然后各种滤波,最后还了解了彩色图像和压缩.进入最后的部分. Chapter9 形态学图像处理 引入:为什么叫形态学呢?形态学 ...

  9. 数字图像处理——图像分割

    数字图像处理-图像分割 (一)点.线和边缘检测 1.1 点检测 1.2 线检测 1.3 使用函数edge的边缘检测 (二)使用霍夫变换的线检测 2.1 函数hough 2.2 函数houghpeaks ...

最新文章

  1. sqlserver 把两个sql查询语句查询出来的两张表合并成一张表
  2. Applese 走方格
  3. vim 树形目录插件NERDTree安装及简单用法
  4. 日美“利刃”联合军演
  5. 基于matlab的数字下变频器的设计与仿真应用,基于MATLAB的数字下变频器的没汁与仿真应用...
  6. Linux内存分配机制之伙伴系统和SLAB
  7. lunix下的redis数据库操作——list列表
  8. hdu 3123(GCC)数论
  9. Java构造方法的继承调用
  10. s905各种型号的区别_2020榨汁机推荐,榨汁机、原汁机和破壁机有什么区别?高性价比榨汁机、原汁机怎么选?...
  11. web前端是不是没有前景了?
  12. 如何关闭热点资讯,如何关闭360浏览器热点资讯
  13. Micrium uC-Probe 使用
  14. c4d怎么导入fbx_c4d怎么导入模型?品索教你Maya模型文件如何导入到C4d
  15. 【课程作业】情感分析方向SKEP: Sentiment Knowledge Enhanced Pretraining for Sentiment Analysis阅读报告
  16. K-th Closest Distance (主席树)
  17. 2020年度商业书单:高瓴创始人张磊《价值》等10本书入选
  18. win7怎么进网络连接服务器未响应,win7 怎么远程连接服务器未响应
  19. Java实现 蓝桥杯VIP 算法提高 阮小二买彩票
  20. Word2016如何去掉首页页码并从任意也开始页码

热门文章

  1. python end函数用法_python end用法是什么?_后端开发
  2. H5 webapp 实现分享功能
  3. 在一页纸上打印8页PPT讲义的方法
  4. tmux无法使用鼠标滚轮滚动页面
  5. JVM(运行时数据区结构)详解一
  6. UDP Flood攻击
  7. 【研究方法】好的研究想法从哪里来--刘知远
  8. python也很浪漫一朵玫瑰送给小姐姐
  9. 关于“未能加载文件或程序集”的解决方法
  10. 给应届求职offer画上句号:从非科班自学Java到阿里、字节、京东等厂OC之路(后缀150+页烫手面经)