1.基本原理
在平面直角坐标系中,直线可以用y=k*x + b表示,在下图中,如果假设以O为原点,x轴为极坐标轴,并且OA与极坐标轴的夹角为,那么点A可由极坐标
表示,经过一系列公式转换可得
,任意一组
可以确定一条直线,检测直线主要是以下几步:
1)建立一个二维数组houghbuf[360][p],其中p的长度为图像对角线长度(对应着),其中360°(对应着
)
2)循环遍历图像的坐标(x,y)的时候,也同时由0-360取值遍历,并代入公式
,根据
来累加(1)中的二维数组,同一条线上的点,会被累加到一起
3)取阈值,有多少个点在一条线上,则认为这是一条线
2.代码实现(代码是我以前自学图像处理时写的,代码很粗糙没做任何优化,但很好理解)
//先用边缘检测生成图像,再hough变换
QImage* MainWindow:: HoughLine(QImage* image)
{
double sinValue[360];
double cosValue[360];
int k = 100;
double scale=1;
int p = (int)(sqrt(double(image->width()*image->width() + image->height()*image->height())+1));
QImage* newImage = new QImage(360,p,QImage::Format_ARGB32);
QColor color;
int houghbuf[360][p];
memset(houghbuf,0,sizeof(int)*360*p);//必须清0
for(int i = 0;i<360;i++)
{
sinValue[i] = sin(i*3.1415926/180);
cosValue[i] = cos(i*3.1415926/180);
}
int tp;
for(int y =0;y<image->height();y++)
{
for(int x =0;x<image->width();x++)
{
color = QColor(image->pixel(x,y));
for(int i = 0;i<360;i++)
{
if(color.red() > k)
{
tp = (int)(x*sinValue[i] + y*cosValue[i]);
if(tp<0||houghbuf[i][tp]==255) continue;
houghbuf[i][tp]+=scale;
}
}
}
}
for(int i = 0;i<360;i++)
{
for(int j = 0;j<p;j++)
{
newImage->setPixel(i,j,qRgb(houghbuf[i][j],houghbuf[i][j],houghbuf[i][j]));
}
}
return newImage;
}
//先用边缘检测生成图像,接着hough变换,再滤波,最后画出直线 ,其中k1取值3000
QImage* MainWindow:: DrawLine(QImage* image,QImage* image1,int k1)
{
double sinValue[360];
double cosValue[360];
int k = 100;
double scale=1;
int p = (int)(sqrt(double(image->width()*image->width() + image->height()*image->height())+1));
QImage* newImage = new QImage(360,p,QImage::Format_ARGB32);
QColor color;
int houghbuf[360][p];
memset(houghbuf,0,sizeof(int)*360*p);//必须清0
for(int i = 0;i<360;i++)
{
sinValue[i] = sin(i*3.1415926/180);
cosValue[i] = cos(i*3.1415926/180);
}
int tp;
for(int y =0;y<image->height();y++)
{
for(int x =0;x<image->width();x++)
{
color = QColor(image->pixel(x,y));
for(int i = 0;i<360;i++)
{
if(color.red() > k)
{
tp = (int)(x*sinValue[i] + y*cosValue[i]);
if(tp<0||houghbuf[i][tp]==255) continue;
houghbuf[i][tp]+=scale;
}
}
}
}
for(int i = 0;i<360;i++)
{
for(int j = 0;j<p;j++)
{
newImage->setPixel(i,j,qRgb(houghbuf[i][j],houghbuf[i][j],houghbuf[i][j]));
}
}
int tmplt[5][5]={
{-2,-2,-2,-2,-2},
{-2,0,4,0,-2},
{-2,4,16,4,-2},
{-2,0,4,0,-2},
{-2,-2,-2,-2,-2}
};
int templtsize = 5;
double kk,bb;
int xx,yy;
for(int x = 0;x<360;x++)
{
for(int y= 0;y<p;y++)
{
int r = 0;
int g = 0;
int b = 0;
int px1 = 0;
int py1 = 0;
for(int i = 0;i<templtsize;i++)
{
for(int j = 0;j<templtsize;j++)
{
py1=(y-templtsize/2+i+p)%p;
px1=(x-templtsize/2+j+360)%360;
color = QColor(newImage->pixel(px1,py1));
r+=color.red()*tmplt[i][j];
g+=color.green()*tmplt[i][j];
b+=color.blue()*tmplt[i][j];
}
}
if(r>k1)
{
if(x!=90)
{
bb = y/cos(x*3.1415926535/180);
kk = -sin(x*3.1415926535/180)/cos(x*3.1415926535/180);
yy =0;
xx =0;
if(abs(kk)<=1)
{
for(xx =0;xx<image->width();xx++)
{
yy=(int)(kk*xx+bb);
if(yy>=0 && yy<image->height())
{
r = 255;
g = 0;
b = 0;
image1->setPixel(xx,yy,qRgb( r,g,b));
}
}
}
else
{
for(yy =0;yy<image->height();yy++)
{
xx=(int)(yy/kk - bb/kk);
if(xx>=0 && xx<image->width())
{
r = 255;
g = 0;
b = 0;
image1->setPixel(xx,yy,qRgb( r,g,b));
}
}
}
}
else
{
for(yy=0;yy<image->height();yy++)
{
r = 255;
g = 0;
b = 0;
image1->setPixel(x,yy,qRgb( r,g,b));
}
}
}
}
}
delete newImage;
return image1;
}
3.下载路径:
整个系列链接: https://blog.csdn.net/m0_59023219/category_12425183.html
内容介绍:
[1]根据算法原理,编写纯c++源码,不调用外源库opencv 等;
[2]包括各种图像处理的基本算法,包含腐蚀膨胀,缩放,转置,镜像,平移,均衡变化,灰度拉升,灰度阈值,灰度非线性,转灰度,灰度线性,旋转,简单平滑,高斯平滑,轮廓跟踪,种子算法,hough直线检测,拉普拉斯,带方向边缘检测,常规边缘检测(梯度算子、Roberts算子和Sobel算子),中值滤波,反色操作等;
[3]程序中有完整的注释,便于大家很好理解代码。
代码下载路径:基于QT的C++多种图像处理基本算法源码