图像处理之霍夫变换(直线检測算法)

霍夫变换是图像变换中的经典手段之中的一个,主要用来从图像中分离出具有某种同样特征的几何

形状(如,直线,圆等)。霍夫变换寻找直线与圆的方法相比与其他方法能够更好的降低噪

声干扰。经典的霍夫变换经常使用来检測直线,圆,椭圆等。

霍夫变换算法思想:

以直线检測为例,每一个像素坐标点经过变换都变成都直线特质有贡献的统一度量,一个简单

的样例例如以下:一条直线在图像中是一系列离散点的集合,通过一个直线的离散极坐标公式,

能够表达出直线的离散点几何等式例如以下:

X *cos(theta) + y * sin(theta)  = r 当中角度theta指r与X轴之间的夹角,r为到直线几何垂

直距离。不论什么在直线上点,x, y都能够表达,当中 r, theta是常量。该公式图形表演示样例如以下:

然而在实现的图像处理领域,图像的像素坐标P(x, y)是已知的,而r, theta则是我们要寻找

的变量。假设我们能绘制每一个(r, theta)值依据像素点坐标P(x, y)值的话,那么就从图像笛卡

尔坐标系统转换到极坐标霍夫空间系统,这样的从点到曲线的变换称为直线的霍夫变换。变换

通过量化霍夫參数空间为有限个值间隔等分或者累加格子。当霍夫变换算法開始,每一个像素

坐标点P(x, y)被转换到(r, theta)的曲线点上面,累加到相应的格子数据点,当一个波峰出现

时候,说明有直线存在。相同的原理,我们能够用来检測圆,仅仅是对于圆的參数方程变为如

下等式:

(x –a ) ^2 + (y-b) ^ 2 = r^2当中(a, b)为圆的中心点坐标,r圆的半径。这样霍夫的參数空间就

变成一个三维參数空间。给定圆半径转为二维霍夫參数空间,变换相对简单,也比較经常使用。

编程思路解析:

1.      读取一幅带处理二值图像,最好背景为黑色。

2.      取得源像素数据

3.      依据直线的霍夫变换公式完毕霍夫变换,预览霍夫空间结果

4.       寻找最大霍夫值,设置阈值,反变换到图像RGB值空间(程序难点之中的一个)

5.      越界处理,显示霍夫变换处理以后的图像

关键代码解析:

直线的变换角度为[0 ~ PI]之间,设置等份为500为PI/500,同一时候依据參数直线參数方程的取值

范围为[-r, r]有例如以下霍夫參数定义:

 // prepare for hough transformint centerX = width / 2;int centerY = height / 2;double hough_interval = PI_VALUE/(double)hough_space;int max = Math.max(width, height);int max_length = (int)(Math.sqrt(2.0D) * max);hough_1d = new int[2 * hough_space * max_length];

实现从像素RGB空间到霍夫空间变换的代码为:

// start hough transform now....
int[][] image_2d = convert1Dto2D(inPixels);
for (int row = 0; row < height; row++) {for (int col = 0; col < width; col++) {int p = image_2d[row][col] & 0xff;if(p == 0) continue; // which means background color// since we does not know the theta angle and r value, // we have to calculate all hough space for each pixel point// then we got the max possible theta and r pair.// r = x * cos(theta) + y * sin(theta)for(int cell=0; cell < hough_space; cell++ ) {max = (int)((col - centerX) * Math.cos(cell * hough_interval) + (row - centerY) * Math.sin(cell * hough_interval));max += max_length; // start from zero, not (-max_length)if (max < 0 || (max >= 2 * max_length)) {// make sure r did not out of scope[0, 2*max_lenght]continue;}hough_2d[cell][max] +=1;}}
}

寻找最大霍夫值计算霍夫阈值的代码例如以下:

// find the max hough value
int max_hough = 0;
for(int i=0; i<hough_space; i++) {for(int j=0; j<2*max_length; j++) {hough_1d[(i + j * hough_space)] = hough_2d[i][j];if(hough_2d[i][j] > max_hough) {max_hough = hough_2d[i][j];}}
}
System.out.println("MAX HOUGH VALUE = " + max_hough);// transfer back to image pixels space from hough parameter space
int hough_threshold = (int)(threshold * max_hough);

从霍夫空间反变换回像素数据空间代码例如以下:

     // transfer back to image pixels space from hough parameter spaceint hough_threshold = (int)(threshold * max_hough);for(int row = 0; row < hough_space; row++) {for(int col = 0; col < 2*max_length; col++) {if(hough_2d[row][col] < hough_threshold) // discard itcontinue;int hough_value = hough_2d[row][col];boolean isLine = true;for(int i=-1; i<2; i++) {for(int j=-1; j<2; j++) {if(i != 0 || j != 0) {int yf = row + i;int xf = col + j;if(xf < 0) continue;if(xf < 2*max_length) {if (yf < 0) {yf += hough_space;}if (yf >= hough_space) {yf -= hough_space;}if(hough_2d[yf][xf] <= hough_value) {continue;}isLine = false;break;}}}}if(!isLine) continue;// transform back to pixel data now...double dy = Math.sin(row * hough_interval);double dx = Math.cos(row * hough_interval);if ((row <= hough_space / 4) || (row >= 3 * hough_space / 4)) {for (int subrow = 0; subrow < height; ++subrow) {int subcol = (int)((col - max_length - ((subrow - centerY) * dy)) / dx) + centerX;if ((subcol < width) && (subcol >= 0)) {image_2d[subrow][subcol] = -16776961;}}} else {for (int subcol = 0; subcol < width; ++subcol) {int subrow = (int)((col - max_length - ((subcol - centerX) * dx)) / dy) + centerY;if ((subrow < height) && (subrow >= 0)) {image_2d[subrow][subcol] = -16776961;}}}}}

霍夫变换源图例如以下:

霍夫变换以后,在霍夫空间显演示样例如以下:(白色表示已经找到直线信号)

终于反变换回到像素空间效果例如以下:

一个更好的执行监測直线的结果(输入为二值图像):

完整的霍夫变换源码例如以下:

package com.gloomyfish.image.transform;import java.awt.image.BufferedImage;import com.process.blur.study.AbstractBufferedImageOp;public class HoughLineFilter extends AbstractBufferedImageOp {public final static double PI_VALUE = Math.PI;private int hough_space = 500;private int[] hough_1d;private int[][] hough_2d;private int width;private int height;private float threshold;private float scale;private float offset;public HoughLineFilter() {// default hough transform parameters//  scale = 1.0f;//    offset = 0.0f;threshold = 0.5f;scale = 1.0f;offset = 0.0f;}public void setHoughSpace(int space) {this.hough_space = space;}public float getThreshold() {return threshold;}public void setThreshold(float threshold) {this.threshold = threshold;}public float getScale() {return scale;}public void setScale(float scale) {this.scale = scale;}public float getOffset() {return offset;}public void setOffset(float offset) {this.offset = offset;}@Overridepublic BufferedImage filter(BufferedImage src, BufferedImage dest) {width = src.getWidth();height = src.getHeight();if ( dest == null )dest = createCompatibleDestImage( src, null );int[] inPixels = new int[width*height];int[] outPixels = new int[width*height];getRGB( src, 0, 0, width, height, inPixels );houghTransform(inPixels, outPixels);setRGB( dest, 0, 0, width, height, outPixels );return dest;}private void houghTransform(int[] inPixels, int[] outPixels) {// prepare for hough transformint centerX = width / 2;int centerY = height / 2;double hough_interval = PI_VALUE/(double)hough_space;int max = Math.max(width, height);int max_length = (int)(Math.sqrt(2.0D) * max);hough_1d = new int[2 * hough_space * max_length];// define temp hough 2D array and initialize the hough 2Dhough_2d = new int[hough_space][2*max_length];for(int i=0; i<hough_space; i++) {for(int j=0; j<2*max_length; j++) {hough_2d[i][j] = 0;}}// start hough transform now....int[][] image_2d = convert1Dto2D(inPixels);for (int row = 0; row < height; row++) {for (int col = 0; col < width; col++) {int p = image_2d[row][col] & 0xff;if(p == 0) continue; // which means background color// since we does not know the theta angle and r value, // we have to calculate all hough space for each pixel point// then we got the max possible theta and r pair.// r = x * cos(theta) + y * sin(theta)for(int cell=0; cell < hough_space; cell++ ) {max = (int)((col - centerX) * Math.cos(cell * hough_interval) + (row - centerY) * Math.sin(cell * hough_interval));max += max_length; // start from zero, not (-max_length)if (max < 0 || (max >= 2 * max_length)) {// make sure r did not out of scope[0, 2*max_lenght]continue;}hough_2d[cell][max] +=1;}}}// find the max hough valueint max_hough = 0;for(int i=0; i<hough_space; i++) {for(int j=0; j<2*max_length; j++) {hough_1d[(i + j * hough_space)] = hough_2d[i][j];if(hough_2d[i][j] > max_hough) {max_hough = hough_2d[i][j];}}}System.out.println("MAX HOUGH VALUE = " + max_hough);// transfer back to image pixels space from hough parameter spaceint hough_threshold = (int)(threshold * max_hough);for(int row = 0; row < hough_space; row++) {for(int col = 0; col < 2*max_length; col++) {if(hough_2d[row][col] < hough_threshold) // discard itcontinue;int hough_value = hough_2d[row][col];boolean isLine = true;for(int i=-1; i<2; i++) {for(int j=-1; j<2; j++) {if(i != 0 || j != 0) {int yf = row + i;int xf = col + j;if(xf < 0) continue;if(xf < 2*max_length) {if (yf < 0) {yf += hough_space;}if (yf >= hough_space) {yf -= hough_space;}if(hough_2d[yf][xf] <= hough_value) {continue;}isLine = false;break;}}}}if(!isLine) continue;// transform back to pixel data now...double dy = Math.sin(row * hough_interval);double dx = Math.cos(row * hough_interval);if ((row <= hough_space / 4) || (row >= 3 * hough_space / 4)) {for (int subrow = 0; subrow < height; ++subrow) {int subcol = (int)((col - max_length - ((subrow - centerY) * dy)) / dx) + centerX;if ((subcol < width) && (subcol >= 0)) {image_2d[subrow][subcol] = -16776961;}}} else {for (int subcol = 0; subcol < width; ++subcol) {int subrow = (int)((col - max_length - ((subcol - centerX) * dx)) / dy) + centerY;if ((subrow < height) && (subrow >= 0)) {image_2d[subrow][subcol] = -16776961;}}}}}// convert to hough 1D and return resultfor (int i = 0; i < this.hough_1d.length; i++){int value = clamp((int)(scale * this.hough_1d[i] + offset)); // scale always equals 1this.hough_1d[i] = (0xFF000000 | value + (value << 16) + (value << 8));}// convert to image 1D and returnfor (int row = 0; row < height; row++) {for (int col = 0; col < width; col++) {outPixels[(col + row * width)] = image_2d[row][col];}}}public BufferedImage getHoughImage() {BufferedImage houghImage = new BufferedImage(hough_2d[0].length, hough_space, BufferedImage.TYPE_4BYTE_ABGR);setRGB(houghImage, 0, 0, hough_2d[0].length, hough_space, hough_1d);return houghImage;}public static int clamp(int value) {if (value < 0)value = 0;else if (value > 255) {value = 255;}return value;}private int[][] convert1Dto2D(int[] pixels) {int[][] image_2d = new int[height][width];int index = 0;for(int row = 0; row < height; row++) {for(int col = 0; col < width; col++) {index = row * width + col;image_2d[row][col] = pixels[index];}}return image_2d;}}

转载文章请务必注明出自本博客!!

图像处理之霍夫变换(直线检測算法)相关推荐

  1. OpenCV2马拉松第22圈——Hough变换直线检測原理与实现

    计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/27220445 收入囊中 Hough变换 概率Ho ...

  2. Canny边缘检測算法原理及其VC实现具体解释(一)

    图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般能够看作是一个阶跃,既从一个灰度值在非常小的缓冲区域内急剧变化到还有一个灰度相差较大的灰度值.图象的边缘部分集中了图象的大部分信息,图 ...

  3. 3D空间中射线与三角形的交叉检測算法

    引言 射线Ray,在3D图形学中有非常多重要的应用.比方,pick操作就是使用射线Ray来实现的,还有诸如子弹射线的碰撞检測等等都能够使用射线Ray来完毕. 所以,在本次博客中,将会简单的像大家介绍下 ...

  4. OpenCV图像处理篇之边缘检測算子

    3种边缘检測算子 灰度或结构等信息的突变位置是图像的边缘,图像的边缘有幅度和方向属性.沿边缘方向像素变化缓慢,垂直边缘方向像素变化剧烈.因此,边缘上的变化能通过梯度计算出来. 一阶导数的梯度算子 对于 ...

  5. 【图像处理基础】基于matlab霍夫变换直线识别(拟合角平分线)【含Matlab源码 2575期】

    ⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[图像处理基础]基于matlab霍夫变换直线识别(拟合角平分线)[含Matlab源码 2575期] 点击上面蓝色字体,直接付费下载,即可. ...

  6. 【转】 LSD(Line Segment Detector) 直线段检测算法学习~

    论文回顾之一 一种新的直线段检测算法---LSD:a Line Segment Detector 原文地址:http://blog.csdn.net/polly_yang/article/detail ...

  7. 【youcans 的 OpenCV 例程200篇】157. 霍夫变换直线检测

    欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中 [youcans 的 OpenCV 例程20 ...

  8. OpenCV 霍夫变换直线检测(SHT、MSHT和PPHT)

    一.霍夫变换简述   霍夫变换(Hough Transform)是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法.主要用来从图像中分离出具有某种相同特征的几何形状(如,直线 ...

  9. 【从零学习openCV】IOS7下的人脸检測

    前言: 人脸检測与识别一直是计算机视觉领域一大热门研究方向,并且也从安全监控等工业级的应用扩展到了手机移动端的app,总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,眼下在学习ope ...

最新文章

  1. 中国首次!2021年图计算挑战赛揭榜,华中科技大团队夺冠
  2. 二维“玄”如何“抖动”出三维世界?
  3. endl在c语言中的作用,C++中的endl
  4. Google Code Jam 2014 总结
  5. html页面右侧滚动,HTML5页面点击和左右滑动页面滚动
  6. sublime开发php插件下载,SublimeText3 配置PHP开发插件
  7. 练习题 - 基于快速文本标题匹配的知识问答实现(二,实现篇)
  8. Java-BufferReader中的readLine()方法
  9. (没用,只是学习贴,可能永不会更新)Js 写《智慧树》自动评论脚本
  10. (liunx)全套青龙面板+傻妞流水版2022年8月22日更新
  11. 所有文件夹都变成1KB文件夹快捷方式病毒的手动清除方法
  12. 超越扁平化设计的「化繁为简」有哪些亮点?
  13. 《星际穿越》关于时间与空间的思考
  14. LVGL+NES|基于lvgl实现nes模拟器(lv_100ask_nes)
  15. CSS中position的relative和absolute.
  16. Bing 无法访问临时解决方案
  17. 树莓派4B 8G安装日志(1)——基础环境安装
  18. Windows远程桌面协议(RDP)
  19. Dusk network 生态图
  20. 计算机类设备资产管理,智的设备设施资产管理系统

热门文章

  1. swift_030(Swift 的访问控制)
  2. day3----str常用操作方法
  3. [LeetCode]Array主题系列{35,39,40,48题}
  4. Fsharp 类中的空字段
  5. pip快速下载安装python 模块module
  6. xhtml和css概述
  7. verilog中=和=的区别
  8. [转]Oracle DB 复制数据库
  9. [原]编程融入生活---设计模式总结
  10. MongoError: topology was destroyed解决方法