自己动手写一个霍夫变换检测直线(线段)

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

  

自己动手写一个霍夫变换检测直线(线段)_第1张图片

你可能感兴趣的:(写)