精华内容
下载资源
问答
  • HOUGH变换直线检测

    2016-06-01 21:28:09
    简单的额hough变换直线检测,适合新手,配合opencv使用
  • hough变换直线检测

    2015-11-04 10:34:22
    hough变换直线检测代码,此代码可以检测出灰度图像中的直线
  • Hough变换直线检测

    2015-07-28 21:25:45
    本代码是Hough变换直线检测的算法,已在Matlab上运行,效果还不错!
  • 数字图像处理 Hough 变换直线检测 ,matlab 实现 实验八 Hough 变换直线检测 一实验目的 理解Hough变换的原理了解其应用掌握利用Hough变换进行直线检测的处 理过程 及编程方法 二实验内容 利用Hough变换检测直线通常...
  • Hough 变换直线检测

    2010-05-17 19:47:46
    对霍夫变换直线检测流程进行了描述。同时对传统的霍夫变换进行了流程的介绍和编程的实现。
  • Win8 Metro(C#)数字图像处理--2.38Hough变换直线检测 原文:Win8 Metro(C#)数字图像处理--2.38Hough变换直线检测  [函数名称] Hough变换直线检测HoughL...
    原文:Win8 Metro(C#)数字图像处理--2.38Hough变换直线检测

    

    [函数名称]

    Hough 变换直线检测         HoughLineDetect(WriteableBitmap src, int threshould)

    [算法说明]

      Hough变换是数字图像处理中一种常用的几何形状识别方法,它可以识别直线,圆,椭圆,弧线等

    等几何形状,其基本原理是利用图像二维空间和Hough参数空间的点-线对偶性,把图像空间中的形

    状检测问题转换到Hough的参数空间中去,最终以寻找参数空间中的峰值问题,得到形状检测的最优

    结果。

           /// <summary>
            /// Hough transform of line detectting process.
            /// </summary>
            /// <param name="src">The source image.</param>
            /// <param name="threshould">The threshould to adjust the number of lines.</param>
            /// <returns></returns>
            public static WriteableBitmap HoughLineDetect(WriteableBitmap src, int threshould)2 Hough 变换直线检测
            {
                if (src != null)
                {
                    int w = src.PixelWidth;
                    int h = src.PixelHeight;
                    WriteableBitmap srcImage = new WriteableBitmap(w, h);
                    byte[] temp = src.PixelBuffer.ToArray();
                    int roMax = (int)Math.Sqrt(w * w + h * h) + 1;
                    int[,] mark = new int[roMax, 180];
                    double[] theta = new double[180];
                    for (int i = 0; i < 180; i++)
                    {
                        theta[i] = (double)i * Math.PI / 180.0;
                    }
                    double roValue = 0.0;
                    int transValue=0;
                    for (int y = 0; y < h; y++)
                    {
                        for (int x = 0; x < w; x++)
                        {
                            if (temp[x * 4 + y * w*4] == 0)
                            {
                                for (int k = 0; k < 180; k++)
                                {
                                    roValue = (double)x * Math.Cos(theta[k]) + (double)y * Math.Sin(theta[k]);
                                    transValue = (int)Math.Round(roValue / 2 + roMax / 2);
                                    mark[transValue, k]++;
                                }
                            }
                        }
                    }
                    for (int y = 0; y < h; y++)
                    {
                        for (int x = 0; x < w; x++)
                        {
                            int T = x * 4 + y * w * 4;
                            if (temp[T] == 0)
                            {
                                for (int k = 0; k < 180; k++)
                                {
                                    roValue = (double)x * Math.Cos(theta[k]) + (double)y * Math.Sin(theta[k]);
                                    transValue = (int)Math.Round(roValue / 2 + roMax / 2);
                                    if (mark[transValue, k] > threshould)
                                    {
                                        temp[T + 2] = (byte)255;
                                    }
                                }
                            }
                        }
                    }
                    Stream sTemp = srcImage.PixelBuffer.AsStream();
                    sTemp.Seek(0, SeekOrigin.Begin);
                    sTemp.Write(temp, 0, w * 4 * h);
                    return srcImage;
                }
                else
                {
                    return null;
                }
            }
    <strong><span style="font-size:14px;">[图像效果]</span></strong>

    注意:图中没有标红的线,是因为threshold=80,如果这个值改变,会影响检测结果,这个值足够小,另外两条直线也将被标红。

    posted on 2018-03-13 10:27 NET未来之路 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/lonelyxmas/p/8554396.html

    展开全文
  • 简单的课程题目。这是一篇包含了代码的文档,是结合opencv对直线进行检测检测直线属于那种简单的直线
  • 基于相位编组图像分块的快速HOUGH变换直线检测
  • Hough变换:Hough变换是1962年由Hough提出来的,用于检测图像中直线、圆、抛物线、椭圆等形状能够用一定函数关系描述的曲线,它在影像分析,模式识别等很多领域中得到了成功的应用。 Hough变换的基本原理是将影像...

    霍夫变换Hough

    霍夫变换(Hough)是一个非常重要的检测间断点边界形状的方法。它通过将图像坐标空间变换到参数空间,来实现直线与曲线的拟合。

    Hough变换:Hough变换是1962年由Hough提出来的,用于检测图像中直线、圆、抛物线、椭圆等形状能够用一定函数关系描述的曲线,它在影像分析,模式识别等很多领域中得到了成功的应用。

    Hough变换的基本原理是将影像空间中的曲线(包括直线)变换到参数空间中,通过检测参数空间中的极值点,确定出该曲线的描述参数,从而提取影像中的规则曲线。

    一条直线的表示方法有好多种,最常见的是  y=mx+b 的形式。 假设有一幅图像,经过滤波,边缘检测等操作,变成了下面这张图的形状,怎么把这张图片中的直线提取出来。基本的思考流程是:如果直线 y=mx+b 在图片中,那么图片中,必需有N多点在直线上(像素点代入表达式成立),只要有这条直线上的两个点,就能确定这条直线。该问题可以转换为:求解所有的(m,b)组合。

            设置两个坐标系,左边的坐标系表示的是(x,y)值,右边的坐标系表达的是(m,b)的值,即直线的参数值。那么一个(x,y)点在右边对应的就是是一条线,左边坐标系的一条直线就是右边坐标系中的一个点。这样,右边左边系中的交点表示有多个点经过(m,b)确定的直线。但是,该方法存在一个问题(m,b)的取值范围太大。

     

      为了解决(m,n)取值范围过大的问题,在直线的表示方面用 xcosθ+ysinθ=p 的规范式代替一般表达式,参数空间变成(θ,p),0=<θ<=2PI。这样图像空间中的一个像素点在参数空间中就是一条曲线(三角函数曲线)。

          Hough Line算法表述如下:

               1、初始化(θ,p)空间,N(θ,p)=0   (N(θ,p)表示在该参数表示的直线上的像素点的个数)

               2、对于每一个像素点(x,y),在参数空间中找出令 xcosθ+ysinθ=p 的(θ,p)坐标,N(θ,p)+=1

               3、统计所有N(θ,p)的大小,取出N(θ,p)>threasold的参数  (threadsold是预设的阈值)

    OpenCV中的HoughLines  

    void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 

           image:输入图像

           lines:检测到的直线(表示其实为直线参数(θ,p)集合)

           rho:像素每次迭代的大小(即每一次选取像素的过程跳跃多少,一般设置为1)

           theta:角度累加器的大小(即选取的直线参数θ的变化),一般为CV_PI/180

           thresold:阈值大小(即每个参数对至少经过的像素点数)

    下面这段代码具体实现了读取图片,提取直线,并且把直线显示出来的功能,一般情况下,我们在提取直线之前会对原始图像做一次Canny边缘检测。

    #include <iostream>
    
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    
    using namespace std;
    using namespace cv;
    
    int main(){
    
      //读取图片,转换成灰度图像,并且对其执行一次高斯滤波,去除噪声点
      Mat img=imread("img//yifulou.jpg");
      Mat result;
      cvtColor(img,result,CV_RGB2GRAY);
      GaussianBlur(result,result,Size(3,3),1);
      imshow("逸夫楼",result);
    
      //Cany边缘提取
      Canny(result,result,50,200,3);
      
    
      //利用Hough计算直线
      vector<Vec2f> lines;
      HoughLines(result,lines,1,CV_PI/180,170);
      cvtColor(result,result,CV_GRAY2RGB); //为了展示需要,把灰度图像转换成RGB格式
      for(size_t i=0;i<lines.size();i++){
            float rho = lines[i][0], theta = lines[i][1];
            Point pt1, pt2;
            double a = cos(theta), b = sin(theta);
            double x0 = a*rho, y0 = b*rho;
            pt1.x = cvRound(x0 + 1000*(-b));
            pt1.y = cvRound(y0 + 1000*(a));
            pt2.x = cvRound(x0 - 1000*(-b));
            pt2.y = cvRound(y0 - 1000*(a));
            line( result, pt1, pt2, Scalar(55,100,195), 1, CV_AA);
      }
      cout<<"检测到直线"<<lines.size()<<endl;
      imshow("Hough Line",result);
    
      cv::waitKey();
    }

    效果

     

    霍夫变换检测圆的原理  

    霍夫变换检测圆形的原理跟检测直线的原理是一样的。圆的表达式为  (x-a)2+(y-b)2=r2 , 把问题转换成在求解经过像素点最多的 (a,b,r) 参数对。这里分析一下图像中的一个像素点,对应参数空间的图形。如果r确定,那么一个像素点对应参数空间的一个圆,那么r不确定,则对于每一个r都是一个圆,这个图形是一个三维的圆台。如下图。

    这里会发现(a,b,r)的参数空间特别大,计算量特别大。如果像素点,知道其所属的圆形的半径和指向圆心的角度,a,b其实是可以计算出来的。那么如下面这个课件上写的那样,参数空间变成了二维的,计算量大大降低。

      看课件上的左上角的图形,如果一个圆上的点,都沿着其梯度方向画线,那么所有线的角点就是圆心。OpenCV中的霍夫梯度算法就利用这个原理,先计算可能的圆心,然后再去计算可能的半径。OK,现在的问题是这个梯度值怎么得到,第一我们检测的圆肯定是边界,那么用Soebl算子去计算局部一位导数,肯定值是比较大的,这样可以用Sobel计算出来的梯度值去近似角度。因此。霍夫梯度检测圆形的算法如下(下面的算法描述来源于  http://blog.csdn.net/hhyh612/article/details/54947205):

          

          I、估计圆心

             1、把原图做一次Canny边缘检测,得到边缘检测的二值图

             2、对原始图像执行一次Sobel算子,计算出所有像素的邻域梯度值

             3、初始化圆心空间N(a,b),令所有的N(a,b)=0

             4、遍历Canny边缘二值图中的所有非零像素点,沿着梯度方向画线,将线段经过的所有累加器中的点(a,b)的N(a,b)+=1

             5、统计排序N(a,b),得到可能的圆心

         II、估计半径(针对某一个圆心a,b)

             1、计算Canny图中所有非0点距离圆心的距离

             2、距离从小到大排序,根据阈值,选取合适的可能半径(比如3和3.5都被划为半径值3中)

             3、初始化半径空间r,N(r)=0

             4、遍历Canny图中的非0点,对于点所满足的半径r,N(r)+=1

             5、统计得到可能的半径值

     

    利用霍夫变换检测其他图形的原理也是这样。找出表达式以及参数空间,遍历图像,找出参数空间中符合要求的参数。最近,看到一个利用最小二乘去寻找圆的算法,那个算法的大致思路是列出圆形的表达式,然后通过最小二乘去求迭代求解参数值。这个方案认为更适合解决,利用图像中的点尽可能去拟合一个圆或者几个圆,不适合检测图像中有多少个圆,而且最小二乘的计算量感人。 

    OpenCV中的HoughCircles    

    OpenCV中的HoughCircles方法实现了检测圆形的功能。方法包含在 imgproc/imgproc.hpp 头文件中,具体方法如下

    void cv::HoughCircles	(	InputArray 	image,
                                OutputArray 	circles,
                                int 	method,
                                double 	dp,
                                double 	minDist,
                                double 	param1 = 100,
                                double 	param2 = 100,
                                int 	minRadius = 0,
                                int 	maxRadius = 0 
                            )		
    
    Python:
    circles	=	cv.HoughCircles(	image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]	)
    

    image:输入图像

           circles:检测的圆形,(a,b,r)的参数集合

           method:检测使用的方法,目前OpenCV只提供了CV_HOUGH_GRADIENT方法,即霍夫梯度法

           dp:图像像素分辨率与参数空间分辨率的比值(官方文档上写的是图像分辨率与累加器分辨率的比值,它把参数空间认为是一个累加器,毕竟里面存储的都是经过的像素点的数量),dp=1,则参数空间与图像像素空间(分辨率)一样大,dp=2,参数空间的分辨率只有像素空间的一半大

           minDist:两个圆心之间的最小距离。这个距离设置过小,会导致本来属于一个圆上的点被分散成几个小圆,过大则导致部分小圆检测不出来

           param1:CV_HOUGH_GRADIENT过程中执行Canny边缘检测的阈值

           param2:参数空间阈值(即至少多少点经过该参数表示的圆)

           minRadius:半径最小值

           maxRadius:半径最大值

    import cv2 as cv
    import numpy as np
    
    
    src = cv.imread('./res/board.jpg', cv.IMREAD_COLOR)
    img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
    img = cv.medianBlur(img, 5)
    cimg = src.copy()
    
    circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 10, np.array([]), 100, 30, 1, 20)
    if circles is not None:
        a, b, c = circles.shape
        print(str(circles))
        for i in range(b):
            cv.circle(cimg, (circles[0][i][0], circles[0][i][1]), circles[0][i][2], (0, 0, 255), 3, cv.LINE_AA)
            cv.circle(cimg, (circles[0][i][0], circles[0][i][1]), 2, (0, 255, 0), 3, cv.LINE_AA)  # draw center of circle
    
        cv.imshow("detected circles", cimg)
    
    cv.waitKey(0)
    

     

    展开全文
  • HOUGH变换的思想,在变换域里面对直线的斜率和截距进行检测,从而检测直线的信息。
  • 经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆。它的抗噪声、抗形变能力较强。另一种直线提取的方法是对图像边缘点进行链码追踪,在得到的链码串中提取直线。 霍夫

    前言

    霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,可以识别图像中的几何形状。它将图像空间中的特征点映射到参数空间进行投票,通过检测累计结果的局部极值点得到一个符合某特定形状的点的集合。经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆。它的抗噪声、抗形变能力较强。另一种直线提取的方法是对图像边缘点进行链码追踪,在得到的链码串中提取直线。

    霍夫变换将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题。

    正文

    原理

    1. 关于原理,请看这篇文章Hough直线检测的理解,或者是这篇文章:霍夫变换。这篇关于hough的原理写的很透彻,值得好好看一下。

    函数

    Canny

    在这里插入图片描述

    HoughLines

    void HoughLines(
    InputArray image, 				// 输入图像,即源图像(需为8位的单通道二进制图像)
    OutputArray lines, 				// 经过调用HoughLines函数后储存了霍夫线变换检测到线条的输出矢量(每一条线由具有两个元素的矢量(rho,theta)表示)
    double rho, 					// 以像素为单位的距离精度 rho,另一种形容方式是直线搜索时的进步尺寸的单位半径。
    double theta, 					// 以弧度为单位的角度精度 theta,另一种形容方式是直线搜索时的进步尺寸的单位角度。
    int threshold, 					// 累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值
    double srn=0, 					// 对于多尺度的霍夫变换,这是第三个参数进步尺寸rho的除数距离
    double stn=0 					// 对于多尺度的霍夫变换,srn表示第四个参数进步尺寸的单位角度theta的除数距离
    )
    

    cv.line

    void cvLine( CvArr* img,CvPoint pt1, CvPoint pt2, CvScalar color,int thickness=1, int line_type=8, int shift=0 );
    第一个参数img:要划的线所在的图像;
    第二个参数pt1:直线起点
    第二个参数pt2:直线终点
    第三个参数color:直线的颜色 e.g:Scalor(0,0,255)
    第四个参数thickness=1:线条粗细
    第五个参数line_type=8, 
       8 (or 0) - 8-connected line(8邻接)连接 线。
       4 - 4-connected line(4邻接)连接线。
       CV_AA - antialiased 线条。
    第六个参数:坐标点的小数点位数。
    

    cv.houghLineP

    void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )
    

    cv::HoughLinesP(
    InputArray src, // 输入图像,必须8-bit的灰度图像
    OutputArray lines, // 输出的极坐标来表示直线,经过调用HoughLinesP函数后后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(x_1,y_1, x_2, y_2) 表示,其中,(x_1, y_1)和(x_2, y_2) 是是每个检测到的线段的结束点。
    double rho, // 生成极坐标时候的像素扫描步长,一般取值为 1
    double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180,即表示一度
    int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
    double minLineLength=0;// 最小直线长度,有默认值0,表示最低线段的长度,比这个设定参数短的线段就不能被显现出来。
    double maxLineGap=0;// 最大间隔,有默认值0,允许将同一行点与点之间连接起来的最大的距离。
    )

    这里输出的是图像的两个点。

    结果

    第一种方法cv.HoughLines效果图
    在这里插入图片描述
    第二种方法效果图
    在这里插入图片描述
    第二种这里的效果不是很好,应该是我的图片或是参数没调好的问题。

    代码

    import cv2 as cv
    import numpy as np
    
    def line_detection(image):
        gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
        edges = cv.Canny(gray,50,150,apertureSize=3)
        # cv2.HoughLines()返回值就是(ρ,θ)。ρ 的单位是像素,θ 的单位是弧度。
        # 这个函数的第一个参数是一个二值化图像,所以在进行霍夫变换之前要首先进行二值化,或者进行 Canny 边缘检测。
        # 第二和第三个值分别代表 ρ 和 θ 的精确度。第四个参数是阈值,只有累加其中的值高于阈值时才被认为是一条直线,
        # 也可以把它看成能 检测到的直线的最短长度(以像素点为单位)。
    
        lines = cv.HoughLines(edges,1,np.pi/180,200)
    # 若输入的图采用上面的函数去检测直线没有检测到,则lines的数量为0,则会报错
        for line in lines:
            rho, theta = line[0]
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a * rho
            y0 = b * rho
            x1 = int(x0 + 1000 * (-b))
            y1 = int(y0 + 1000 * (a))
            x2 = int(x0 - 1000 * (-b))
            y2 = int(y0 - 1000 * (a))
            cv.line(image, (x1, y1), (x2, y2), (43, 43, 43), 2)
        cv.imshow("line_detection", image)
    
    def line_detection_possible_demo(image):
        gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
        edges = cv.Canny(gray, 50, 150, apertureSize=3)
        # lines = cv.HoughLines(edges,1,np.pi/180,200)
        minLineLength = 50
        maxLineGap =  10
        lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
        for x1,y1,x2,y2 in lines[0]:
            cv.line(image,(x1,y1),(x2,y2),(0,255,0),2)
        cv.imshow('hough_lines',image)
    
    
    src = cv.imread("../images/shufa3.jpg")
    cv.namedWindow("input image",cv.WINDOW_AUTOSIZE)
    cv.imshow('input image', src)
    #line_detection(src)
    line_detection_possible_demo(src)
    cv.waitKey(0)  # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
    
    cv.destroyAllWindows()
    

    参考文献

    1. 霍夫直线变换介绍
    2. opencv学习笔记——cv::line函数详解
    展开全文
  • 计算机视觉讨论群162501053 转载请注明:... 收入囊中 Hough变换概率Hough变换自己实现Hough变换直线检测 葵花宝典 先看一下我实现的效果图 下面,我们进入Hough变换的原理讲解。 看上图,我们知
    计算机视觉讨论群162501053

    收入囊中
    • Hough变换
    • 概率Hough变换
    • 自己实现Hough变换直线检测

    葵花宝典
    先看一下我实现的效果图


    下面,我们进入Hough变换的原理讲解。

    看上图,我们知道,经过一点(x0,y0)的直线可以表示成y0 = mox + b0
    反过来看方程,b = –x0m + y0 ,于是我们从原来的坐标系转移到了Hough空间,m是横坐标,b是纵坐标


    刚才提到,经过(x0,y0)的直线具有的特征是b = –x0m + y0,在Hough空间下也是一条直线,
    那么经过(x1,y1)的直线具有的特征是b = -x1m + y1,在Hough空间下是另一条直线。
    两条直线的相交点的(m,b)就是经过(x0,y0)(x1,y1)的直线,这个应该可以理解吧。
    于是就有了一个简单的想法,对于每一个点,在Hough空间中都画出一条直线,对于每条直线经过的点,都填充在如下的 Hough空间中,看哪交点多,就能确定。我们用一个二维数组表示Hough空间,如下。最后就变成数哪些格子的值比较高。

    但是,用m和b有局限性。因为m是可以取到无穷大的,所以这个特征只在理论上可行...实际上我们不可能申请一个无限大的二维数组。

    自然而然,我们想到了极坐标,在极坐标下,就没有这个限制了。
    Line variables在极坐标下,我们的直线可以写成:y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right )
    也就是:r = x \cos \theta + y \sin \theta
    经过点(x0,y0)的直线:r_{\theta} = x_{0} \cdot \cos \theta  + y_{0} \cdot \sin \theta
    当x0 = 8, y0 = 6,我们有这样的图
    Polar plot of a the family of lines of a point我们在下面只考虑r > 0 并且 0< \theta < 2 \pi.

    我们还有2个点,x_{1} = 9y_{1} = 4       x_{2} = 12y_{2} = 3,就可以绘制出下面的图形
    Polar plot of the family of lines for three points这3条直线相交于(0.925, 9.6), 也就是说 (\theta, r) = (0.925, 9.6) 是这3个点 (x_{0}, y_{0})(x_{1}, y_{1})  (x_{2}, y_{2})共同经过的直线!

    因此,我们有了算法雏形                                       

    • 初始化H( Hough空间的二维数组)全为0
    • 遍历图片的 (x,y) 
    For θ = 0 to 360
          ρ = xcos θ + y sin θ
          H(θ,
    ρ) = H(θ,ρ) + 1
        end
    end
    • Find the value(s) of (θ, ρ)where H(θ, ρ)is a local maximum
    • Thedetected line in the image is given by  ρ = xcos θ + y sin θ

    看下面的图片,当都一条直线时,Hough空间的某个区域就会很亮,取局部极大值就可以



    一张更复杂的图片



    初识API
    C++: void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
     
    • image – 8-bit,单通道二值图(有可能被函数改变)
    • lines – 输出vector,是 (\rho, \theta) 的vector. \rho 是距离原点距离(0,0) (图片左上角[0,0]处). \theta  ( 0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line} ).
    • rho – 累加器的半径resolution
    • theta – 累加器的theta resulution
    • threshold – 返回Hough空间中 ( >\texttt{threshold} ).的点
    • srn – For the multi-scale Hough transform, it is a divisor for the distance resolution rho . The coarse accumulator distance resolution is rho and the accurate accumulator resolution is rho/srn . If both srn=0 and stn=0 , the classical Hough transform is used. Otherwise, both these parameters should be positive.
    • stn – For the multi-scale Hough transform, it is a divisor for the distance resolution theta.


    C++: void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, doublemaxLineGap=0 )
     
    • image –8-bit,单通道二值图(有可能被函数改变)
    • lines – 输出向量是4-element vector (x_1, y_1, x_2, y_2) ,  (x_1,y_1) 是起点 (x_2, y_2) 是终点
    • rho – Distance resolution of the accumulator in pixels.
    • theta – Angle resolution of the accumulator in radians.
    • threshold – Accumulator threshold parameter. Only those lines are returned that get enough votes ( >\texttt{threshold} ).
    • minLineLength – 最小长度,小于这个值不被认为是线段
    • maxLineGap – 两个点之间最大的gap,当小于这个值两个点就被认为是同一线段的点


    荷枪实弹
    还是先贴出官方sample
    #include <cv.h>
    #include <highgui.h>
    #include <math.h>
    
    using namespace cv;
    
    int main(int argc, char** argv)
    {
        Mat src, dst, color_dst;
        if( argc != 2 || !(src=imread(argv[1], 0)).data)
            return -1;
    
        Canny( src, dst, 50, 200, 3 );
        cvtColor( dst, color_dst, CV_GRAY2BGR );
    
    #if 0
        vector<Vec2f> lines;
        HoughLines( dst, lines, 1, CV_PI/180, 100 );
    
        for( size_t i = 0; i < lines.size(); i++ )
        {
            float rho = lines[i][0];
            float theta = lines[i][1];
            double a = cos(theta), b = sin(theta);
            double x0 = a*rho, y0 = b*rho;
            Point pt1(cvRound(x0 + 1000*(-b)),
                      cvRound(y0 + 1000*(a)));
            Point pt2(cvRound(x0 - 1000*(-b)),
                      cvRound(y0 - 1000*(a)));
            line( color_dst, pt1, pt2, Scalar(0,0,255), 3, 8 );
        }
    #else
        vector<Vec4i> lines;
        HoughLinesP( dst, lines, 1, CV_PI/180, 80, 30, 10 );
        for( size_t i = 0; i < lines.size(); i++ )
        {
            line( color_dst, Point(lines[i][0], lines[i][1]),
                Point(lines[i][2], lines[i][3]), Scalar(0,0,255), 3, 8 );
        }
    #endif
        namedWindow( "Source", 1 );
        imshow( "Source", src );
    
        namedWindow( "Detected Lines", 1 );
        imshow( "Detected Lines", color_dst );
    
        waitKey(0);
        return 0;
    }

    假如我们想检测直线,就可以用第一个API,因为这个API返回的是直线的两个参数
    如果想检测图片中的线段,就用第二个API,因为这个 API返回的是起点和终点

    下面看下我自己的实现,首先是弧度及结构体的定义
    const double pi = 3.1415926f;
    const double RADIAN = 180.0/pi; 
    
    struct line
    {
    	int theta;
    	int r;
    };

    接下来是变换到Hough空间,填充二维数组
    vector<struct line> houghLine(Mat &img, int threshold)
    {
    	vector<struct line> lines;
    	int diagonal = floor(sqrt(img.rows*img.rows + img.cols*img.cols));
    	vector< vector<int> >p(360 ,vector<int>(diagonal));
    	
    	for( int j = 0; j < img.rows ; j++ ) { 
    		for( int i = 0; i < img.cols; i++ ) {
                if( img.at<unsigned char>(j,i) > 0)
    			{
    				for(int theta = 0;theta < 360;theta++)
    				{
    					int r = floor(i*cos(theta/RADIAN) + j*sin(theta/RADIAN));
    					if(r < 0)
    						continue;
    					p[theta][r]++;
    				}
    			}
    		}
    	}
    
    	//get local maximum
    	for( int theta = 0;theta < 360;theta++)
    	{
    		for( int r = 0;r < diagonal;r++)
    		{
    			int thetaLeft = max(0,theta-1);
    			int thetaRight = min(359,theta+1);
    			int rLeft = max(0,r-1);
    			int rRight = min(diagonal-1,r+1);
    			int tmp = p[theta][r];
    			if( tmp > threshold 
    				&& tmp > p[thetaLeft][rLeft] && tmp > p[thetaLeft][r] && tmp > p[thetaLeft][rRight]
    				&& tmp > p[theta][rLeft] && tmp > p[theta][rRight]
    				&& tmp > p[thetaRight][rLeft] && tmp > p[thetaRight][r] && tmp > p[thetaRight][rRight])
    			{
    				struct line newline;
    				newline.theta = theta;
    				newline.r = r;
    				lines.push_back(newline);
    			}
    		}
    	}
    
    	return lines;
    }
    

    最后是画直线的函数
    void drawLines(Mat &img, const vector<struct line> &lines)
    {
    	for(int i = 0;i < lines.size();i++)
    	{
    		vector<Point> points;
    		int theta = lines[i].theta;
    		int r = lines[i].r;
    
    		double ct = cos(theta/RADIAN);
    		double st = sin(theta/RADIAN);
    		
    		//r = x*ct + y*st
    		//left
    		int y = int(r/st);
    		if(y >= 0 && y < img.rows){
    			Point p(0, y);
    			points.push_back(p);
    		}
    		//right
    		y = int((r-ct*(img.cols-1))/st);
    		if(y >= 0 && y < img.rows){
    			Point p(img.cols-1, y);
    			points.push_back(p);
    		}
    		//top
    		int x = int(r/ct);
    		if(x >= 0 && x < img.cols){
    			Point p(x, 0);
    			points.push_back(p);
    		}
    		//down
    		x = int((r-st*(img.rows-1))/ct);
    		if(x >= 0 && x < img.cols){
    			Point p(x, img.rows-1);
    			points.push_back(p);
    		}
    		
    		cv::line( img, points[0], points[1], Scalar(0,0,255), 1, CV_AA);
    	}
    }

    完整代码
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <iostream>
    #include <vector>
    #include <cmath>
    using namespace cv;
    using namespace std;
    
    const double pi = 3.1415926f;
    const double RADIAN = 180.0/pi; 
    
    struct line
    {
    	int theta;
    	int r;
    };
    
    /*
     * r = xcos(theta) + ysin(theta)
     */
    vector<struct line> houghLine(Mat &img, int threshold)
    {
    	vector<struct line> lines;
    	int diagonal = floor(sqrt(img.rows*img.rows + img.cols*img.cols));
    	vector< vector<int> >p(360 ,vector<int>(diagonal));
    	
    	for( int j = 0; j < img.rows ; j++ ) { 
    		for( int i = 0; i < img.cols; i++ ) {
                if( img.at<unsigned char>(j,i) > 0)
    			{
    				for(int theta = 0;theta < 360;theta++)
    				{
    					int r = floor(i*cos(theta/RADIAN) + j*sin(theta/RADIAN));
    					if(r < 0)
    						continue;
    					p[theta][r]++;
    				}
    			}
    		}
    	}
    
    	//get local maximum
    	for( int theta = 0;theta < 360;theta++)
    	{
    		for( int r = 0;r < diagonal;r++)
    		{
    			int thetaLeft = max(0,theta-1);
    			int thetaRight = min(359,theta+1);
    			int rLeft = max(0,r-1);
    			int rRight = min(diagonal-1,r+1);
    			int tmp = p[theta][r];
    			if( tmp > threshold 
    				&& tmp > p[thetaLeft][rLeft] && tmp > p[thetaLeft][r] && tmp > p[thetaLeft][rRight]
    				&& tmp > p[theta][rLeft] && tmp > p[theta][rRight]
    				&& tmp > p[thetaRight][rLeft] && tmp > p[thetaRight][r] && tmp > p[thetaRight][rRight])
    			{
    				struct line newline;
    				newline.theta = theta;
    				newline.r = r;
    				lines.push_back(newline);
    			}
    		}
    	}
    
    	return lines;
    }
    
    void drawLines(Mat &img, const vector<struct line> &lines)
    {
    	for(int i = 0;i < lines.size();i++)
    	{
    		vector<Point> points;
    		int theta = lines[i].theta;
    		int r = lines[i].r;
    
    		double ct = cos(theta/RADIAN);
    		double st = sin(theta/RADIAN);
    		
    		//r = x*ct + y*st
    		//left
    		int y = int(r/st);
    		if(y >= 0 && y < img.rows){
    			Point p(0, y);
    			points.push_back(p);
    		}
    		//right
    		y = int((r-ct*(img.cols-1))/st);
    		if(y >= 0 && y < img.rows){
    			Point p(img.cols-1, y);
    			points.push_back(p);
    		}
    		//top
    		int x = int(r/ct);
    		if(x >= 0 && x < img.cols){
    			Point p(x, 0);
    			points.push_back(p);
    		}
    		//down
    		x = int((r-st*(img.rows-1))/ct);
    		if(x >= 0 && x < img.cols){
    			Point p(x, img.rows-1);
    			points.push_back(p);
    		}
    		
    		cv::line( img, points[0], points[1], Scalar(0,0,255), 1, CV_AA);
    	}
    }
    
    int main( int, char** argv )
    {
    	Mat src,src_gray,edge;
      	src = imread( argv[1] );
      	cvtColor( src, src_gray, CV_BGR2GRAY );
    
      	blur( src_gray, src_gray, Size(3,3) );
      	Canny( src_gray, edge, 50, 200);
    	vector<struct line> lines = houghLine(edge, 90);
    	drawLines(src, lines);
    	
      	namedWindow("result", 1); 
        imshow("result", src);
        waitKey();
        
      	return 0;
    }



    举一反三

    概率Hough变换在基本算法上增加了比较少的修改。之前是逐行扫描,现在则是随机选点。每当累加器的一个条目达到指定的最小值,就沿这条直线的方向扫描,并且将通过它的所有点删除(即使它们还没有参与投票)。而且该扫描还确定被接受的线段的长度。为此,该算法定义了两个附加参数。一个是被接受线段的最小长度,而另一个是被允许以形成连续的段的最大距离。这个附加步骤增加了算法的复杂性,但是复杂性带来的效率损失被较少的点会参与投票过程补偿。

    我们再来看一看其他形状在二维 Hough空间的样子



    我们再考虑一下噪声的影响


    噪声使得峰值定位很难

    噪声程度越厉害,结果越不准确

    解决噪声问题的算法:

    这个算法也不复杂,对于一个点,我们以前要遍历[0,360]的角度,但是现在,这个角度就直接被我们取出来了,速度也有很大的提升,非常不错的算法。
    展开全文
  • Hough变换直线检测的MATLAB实现

    千次阅读 2017-09-25 20:27:51
    1.Hough变换是一个非常重要的检测间断点边界形状的方法,它通过将图像坐标空间变换到参数空间,来实现直线和曲线的拟合。 2.通过Hough变换,在二值图像中检测直线需要三个步骤  a)利用hough()函数执行hough变换,...
  • 利用hough变换,对直线进行检测,源代码.cpp
  • matlab下的直线检测算法
  • lines = cvHoughLines2(dst,storage,CV_HOUGH_STANDARD,1,CV_PI/180,150,0,0); for (i=0;i<lines->total;i++) { float *line = (float *)cvGetSeqElem(lines,i); float rho = line[0]; float ...
  • 为了能有效解决Hough 变换的计算量大的问题,文中提出了一种基于...像素点的极角范围,减少每个点的计算次数,在保持精度的同时,提高直线检测的速度,在有噪声的情况下,该算法相对标 准Hough 变换算法可以提高到6 到7 倍。
  • 在上文中发现经过霍夫变换检测出的直线有可能因为车辆挡住路沿等原因断开,形成线段,这样就不好了,因为检测道路是要找直线焦点。 Thus it is necessary to combine 相同斜率的直线 and connect them. 本代码提供了...
  • 霍夫变换直线检测的原理    笛卡尔坐标(x,y坐标)系上的直线y=kx+b 可以在极坐标系上可以用下式表示  r=x cosθ + ysinθ , 其中r为该原点到该直线的距离,θ为该直线和x轴的夹角。  那么可以通过计算每个点...
  • Java调用OpenCV进行Hough变换直线检测

    千次阅读 2015-02-13 13:55:59
    private BitmapHoughTransFormLine(Bitmap bmp)  {  Mat rgbMat = new Mat();  //存储原图像的矩阵  Mat grayMat = new Mat(); //存储灰度图像的矩阵 ...//存储检测出的直线坐标的矩阵,每个element

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,029
精华内容 411
关键字:

hough变换直线检测