霍夫变换最简单的使用就是检测直线了。
原理:
对于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; }