zoukankan      html  css  js  c++  java
  • 自己动手写一个霍夫变换检测直线(线段)

    霍夫变换最简单的使用就是检测直线了。
    原理:
    对于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.
  • 相关阅读:
    Winform跨线程操作界面的策略
    Winform DataGridView扩展
    GDI+的常用类
    函数中参数的验证顺序
    C# Winform常见的Editor及其它经验
    能够引起异常的运算符和关键字
    终结程序
    C#异常处理策略
    python3.6入门到高阶(全栈) day01 python 基础
    虚拟机中系统盘扩容
  • 原文地址:https://www.cnblogs.com/zjutzz/p/3112030.html
Copyright © 2011-2022 走看看