自己动手写一个霍夫变换检测直线(线段)
霍夫变换最简单的使用就是检测直线了。
原理:
对于x-y坐标中的一条直线y=kx+b,任取其上两点(x1,y1)与(x2,y2),在参数坐标k-b中分别对应两条直线L1与L2,两者相交与一点(b,k)。原直线上所有点在参数平面中对应的直线都相交于这一点。
对于x=c这类直线无法用y=kx+b处理,一般使用参数方程rho=xcos(theta)+ysin(theta)表示,则参数平面中为众多三角函数曲线相交与一点(theta,rho)
对于参数平面细分(因为程序处理时候数据不会连续,是离散的),分别统计每个点挂载的曲线数量,即“有多少条直线在这一点相交”,取数量最多的那个点,对应原有的待检测直线
先用霍夫变换检测直线,确定“伪直线”,然后取原图中点,用最小二乘法求出“真直线”。
说明:
OpenCV中自带HoughLines和HoughLinesP等函数用于检测直线。
代码
/*读入一张图像
*检测其中的一条线段
*并将其标记出来
*策略:取图像上每一点做霍夫变换,然后统计交点
*用交点的信息推出直线的斜率与截距
*并用点线距离判别合法点
*再用最小二乘法模拟直线方程
***ChriZ!
*/
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <string>
#include <math.h>
#include <vector>
#include <string.h>
#include <map>
using namespace std;
using namespace cv;
//0 represent black
//1 represent white
#define LINE 0
#define ELSE 255
typedef Mat_<uchar> MatU;
double f(int xi, int yi, double theta){
double ret=xi*cos(theta)+yi*sin(theta);
return ret;
}
double dis(double k, double b, double xi, double yi){
double up=fabs(k*xi-yi+b);
double down=sqrt(k*k+1);
return up/down;
}
int main(){
string filename="C:/testdir/13.png";
Mat imgg=imread(filename);
MatU img;
cvtColor(imgg, img, CV_RGB2GRAY);
// Mat imhough=Mat(img.rows, img.cols, img.type());
// bitwise_not(img, img);
//threshold(img, img, 128, 255, THRESH_BINARY);
int x, y;
double theta;
//MatU test=MatU(img.rows, img.cols, img.type());
//Matrix test=new Matrix(img.rows, img.cols);
//int test[img.rows*4][img.cols];
int test[314][800];
for(x=0; x<314; x++){
for(y=0; y<800; y++){
test[x][y]=0;
}
}
for(y=0; y<img.rows; y++){
for(x=0; x<img.cols; x++){
Point cur(x,y);
if(img(cur)==LINE){
// cout << "(" << i << "," << j << ")" << endl;
for(theta=0; theta<3.14; theta=theta+0.01){
double rho=f(x, y, theta);
// if(rho>150) cout << rho << endl;
test[int(theta*100)][int(rho)+400]+=1;
// 数组下标非负,遭遇负数rho时要处理,所以统统加400,后面处理时再减400
// test[theta][int(rho)]+=1;
}
}
}
}
int max=-1;
double mx=0, my=0;
for(y=0; y<800; y++){
for(x=0; x<314; x++){
if(test[x][y]>max){
max=test[x][y];
mx=x/100.0;
my=y-400;
}
}
}
//cout << "max=" << max << endl;
//cout << "mx=" << mx << endl;
double mk=-1.0/tan(mx);
double mb=my*1.0/sin(mx);
cout << "k=" << mk << endl << "b=" << mb << endl;
double dk=1;//pivot valut
vector<Point> store;
double xmin=200, xmax=0;//[xmin,xmax]表示直线横坐标范围
for(y=0; y<img.rows; y++){
for(x=0; x<img.cols; x++){
Point cur(x, y);
if(img(cur)==LINE){
if(dis(mk, mb, x, y)<dk){
store.push_back(Point(x, y));
if(xmin>x) xmin=x;
if(xmax<x) xmax=x;
}
}
}
}
double A=0,//sigma of (xi*xi)
B=0,//sigma of (xi)
C=0,//sigma of (xi*yi)
D=0;//sigma of (yi)
double k2x,// k of ercheng
b2x;//b of ercheng
int m=store.size();
size_t i;
for(i=0; i<store.size(); i++){
double tx=store[i].x;
double ty=store[i].y;
A+=tx*tx;
B+=tx;
C+=tx*ty;
D+=ty;
}
k2x=(D*B-m*C)/(B*B-m*A);
b2x=(D-B*k2x)/m;
// line( im2x, Point(xmin, k2x*xmin+b2x), Point(xmax, k2x*xmax+b2x), Scalar(255), 3, CV_AA);
// line( img, Point(xmin, k2x*xmin+b2x), Point(xmax, k2x*xmax+b2x), Scalar(255), 3, CV_AA);
// imshow("im2x", im2x);
imshow("imgg", imgg);
imshow("img", img);
Mat im2x=imgg.clone();
cout << "xmin=" << xmin << " xmax=" << xmax << endl;
line( im2x, Point(xmin, k2x*xmin+b2x), Point(xmax, k2x*xmax+b2x), Scalar(255), 3, CV_AA);
//line( im2x, Point(0, 0), Point(100, 100), Scalar(0,0,255), 3, CV_AA);
imshow("im2x", im2x);
waitKey();
return 0;
}

Greatness is never a given, it must be earned.

浙公网安备 33010602011771号