【数字图像处理】霍夫变换实现
实现 变换 数字图像处理
2023-09-14 08:56:57 时间
理论部分来源:霍夫变换
作者:https://home.cnblogs.com/u/php-rearch/
一、霍夫变换(Hough)
A-基本原理
一条直线可由两个点A=(X1,Y1)和B=(X2,Y2)确定(笛卡尔坐标)
另一方面,也可以写成关于(k,q)的函数表达式(霍夫空间):
对应的变换可以通过图形直观表示:
变换后的空间成为霍夫空间。即:笛卡尔坐标系中一条直线,对应霍夫空间的一个点。
反过来同样成立(霍夫空间的一条直线,对应笛卡尔坐标系的一个点):
再来看看A、B两个点,对应霍夫空间的情形:
一步步来,再看一下三个点共线的情况:
可以看出如果笛卡尔坐标系的点共线,这些点在霍夫空间对应的直线交于一点:这也是必然,共线只有一种取值可能。
如果不止一条直线呢?再看看多个点的情况(有两条直线):
其实(3,2)与(4,1)也可以组成直线,只不过它有两个点确定,而图中A、B两点是由三条直线汇成,这也是霍夫变换的后处理的基本方式:选择由尽可能多直线汇成的点。
看看,霍夫空间:选择由三条交汇直线确定的点(中间图),对应的笛卡尔坐标系的直线(右图)。
到这里问题似乎解决了,已经完成了霍夫变换的求解,但是如果像下图这种情况呢?
k=∞是不方便表示的,而且q怎么取值呢,这样不是办法。因此考虑将笛卡尔坐标系换为:极坐标表示。
在极坐标系下,其实是一样的:极坐标的点→霍夫空间的直线,只不过霍夫空间不再是[k,q]的参数,而是的参数,给出对比图:
是不是就一目了然了?
给出霍夫变换的算法步骤:
二、霍夫变换的实现
霍夫变换:在霍夫空间中,一个r和theta可以确定一条直线。
本质上在由r与theta组成的二维空间进行投票。
r:r的最大值取图像对角线长度。
theta:0-360度,可分也可不分。
#define PI 3.14159265 #define r 200 //120^2+160^2 = 40000 //斜边长度 #define count 90 //360度分成90份 #define Use_ROWS 120 //图像高度 #define Use_Line 160 //图像宽度 //数据初始化 int jiaodu=0; float Cos[count]={0},Sin[count]={0}; for(int theta = 0,int i=0;theta<=360;i++) { Cos[i]=cos(theta*PI/180); Sin[i]=sin(theta*PI/180); theta+=4; } //二维投票箱 int res[count][r]={0};
/////////////////////////////////////////////////////////////////////// memset(Image, 255, sizeof(Image)); memset(res, 0, sizeof(res)); //二值化 int Threshold,i,j; Threshold = GetOSTU(Image_Use); for(i = 0; i < Use_ROWS; i++) { for(j =0; j < Use_Line; j++) { if(Image_Use[i][j] >= Threshold) Image_Use[i][j]=255;//白为背景 else Image_Use[i][j]=0; //黑为物体 } } //双向梯度 for(int i = 1; i < Use_ROWS- 1; i++) { for(int j = 1; j < Use_Line -1; j++) { Image_Use[i][j] = sqrt((Image_Use[i][j+1] - Image_Use[i][j])*(Image_Use[i][j+1] - Image_Use[i][j])+(Image_Use[i+1][j] - Image_Use[i][j])*(Image_Use[i+1][j] - Image_Use[i][j])); } } // 直线检测 for(int i = 0; i<Use_ROWS;i++) for(int j=0; j<Use_Line;j++) if(Image_Use[i][j]==255)//当该像素点为边缘点时 { for(int theta = 0;theta<=360;) { jiaodu = theta/4;//这里设置360度,分成多少份 int resu = (int)(i*Cos[jiaodu]+j*Sin[jiaodu]); res[jiaodu][resu] +=1; theta+=4; } } ////////////////////////////////// //找出次数最多的结果 int result = res[0][0]; for(int i=0;i<count;i++) for(int j=0;j<r;j++) { if(result<res[i][j]) result = res[i][j]; } //直线提取 int td =(int)(result * 0.8); int s1[30] = {0},s2[30]={0},d=0; for(int i=0;i<count;i++) { for(int j=0;j<r;j++) { if(res[i][j]>td) { s1[d] = i; //角度 s2[d] = j; //距离 d++; } } } d--; for(int i = 0; i < Use_ROWS; i++) { for(int s = 0 ;s<d;d++) { j = (int)((-1.0/tan[s1[s]])*i+(s2[s])/Sin[s1[s]])); Image[i][j] = 0; } }
///////////////////////////////////////////////////////
相关文章
- C#控制台输出退格实现变换闪烁的字符效果
- Java实现 LeetCode 646 最长数对链(暴力)
- Java实现 LeetCode 6 Z字形变换
- java实现国庆星期日
- java实现第五届蓝桥杯信号匹配
- java实现第五届蓝桥杯圆周率
- java实现第七届蓝桥杯压缩变换
- java实现第七届蓝桥杯煤球数量
- Java实现 蓝桥杯VIP 算法训练 薪水计算
- 【转】【UNITY3D 游戏开发之四】有关实现2D帧序列帧播放相关—ANIMATING TILEDTEXTURE
- 通过Git WebHooks+脚本实现自动更新发布代码之Shell脚本(二)
- PCL 欧式变换,实现点云坐标变换
- Atitit java c# php c++ js跨语言调用matlab实现边缘检测等功能attilax总结
- ML之FE之FS:特征工程/数据预处理—特征选择之利用过滤式filter之利用方差阈值的特征筛选(自定义数据集,多种方法实现)案例实现代码
- Dataset之图片数据增强:设计自动生成(高级封装之命令行解析实现)汽车车牌图片算法(cv2+PIL+argparse)根据随机指定七个字符生成逼真车牌图片(自然场景+各噪效果+对应txt说明文档)
- Python语言编程学习:文件路径变量修改,利用os模块固定文件父路径,变换文件子路径实现代码
- 【生成有序序列】借鉴雪花算法实现的一种长度更短的有序序列生成算法
- 图像处理学习——基于霍夫变换(Matlab代码实现)
- 基于图像特征检测——使用相位拉伸变换(Matlab代码实现)
- OpenCV使用分水岭变换来实现图像中对象计数
- 【LeetCode Python实现】6. Z 字形变换(中等)
- Python实现快速傅里叶变换(FFT)
- 在OpenCV里实现极坐标变换3
- 在OpenCV里实现正规化变换2
- 在OpenCV里实现顶帽变换和底帽变换
- 在OpenCV里实现快速傅里叶变换