OpenCvSharp 学习笔记20-- 霍夫变换 - 直线检测 (Hough Line transform)

一,霍夫变换介绍:

  • 霍夫(Hough) 变换是一种用于检测线,圆或者图像中其他简单形状的方法。
  • 使用霍夫直线检测,首先要对图像进项边缘检测预处理。
  • 平面空间到极坐标空间的转换

图像空间中的直线可以用两个变量表示。例如:

  1. 在笛卡尔坐标系中:参数:(m,b)
  2. 在极坐标系统:参数:(r,θ)

x = ρ cos ⁡ θ , y = ρ cos ⁡ θ x=\rho\cos\theta , y=\rho\cos\theta x=ρcosθy=ρcosθ
ρ 2 = x 2 + y 2 , tan ⁡ θ = y / x ( x 不 等 于 0 ) \rho^2=x^2+y^2 , \tan\theta=y/x (x不等于0) ρ2=x2+y2tanθ=y/xx0
OpenCvSharp 学习笔记20-- 霍夫变换 - 直线检测 (Hough Line transform)_第1张图片

霍夫变换基本原理是:二进制图像中的任何点都可能属于某些可能的线。如果为我们将每一条线参数化,比如斜率为 a a a ,截距为 b b b ,原始图像中的点就可以转换为对应于通过该点的所有线在该平面 ( a , b ) (a,b) (a,b) 中的点的轨迹,也可能只是一部分根轨迹。如果我们将原图中的每个非0 像素 都转换成输出图像中这样的一系列点,并将所有这些贡献相加,那么原图 ( ( x , y ) 平 面 ) ((x,y)平面) ((x,y)) 中的线将显示为输出图像 ( ( a , b ) 平 面 ) ((a,b)平面) ((a,b)) 中的局部最大值。由于我们对每个点的贡献进行求和 ,所以 ( ( a , b ) 平 面 ) ((a,b)平面) ((a,b)) 通常称为" 累加器平面"。
但是可能会发现,斜截式方程并不是代表所有穿过某个点的线的最佳方式( 因为图像中线的密度和斜率有很大的不同,还有一个相关的事实是,斜率的区间可能从 − ∞ -\infty + ∞ +\infty + ,正是因为如此,图像变换时数值计算实际用到的参数有所不同,最好的参数形式是用极坐标中的点( ρ \rho ρ, θ \theta θ)表示线,每条直线经过这个点并且垂直于它与原点相连的线) 如图:
OpenCvSharp 学习笔记20-- 霍夫变换 - 直线检测 (Hough Line transform)_第2张图片
图像平面 (A) 中有一个点可以表示很多直线,每条直线都可以有 (B) 中的 ρ \rho ρ θ \theta θ 参数化,在 ( ρ \rho ρ, θ \theta θ) 平面中,这些线组合在一起形成特殊的形状 (C) 的曲线

对于霍夫变换,我们将在极坐标系统中表示直线。因此,直线方程可以写成:
y = ( − cos ⁡ θ sin ⁡ θ ) x + ( r sin ⁡ θ ) y=(-\frac{\cos\theta}{\sin\theta})x +(\frac{r}{\sin\theta}) y=(sinθcosθ)x+(sinθr)

1:Arranging the terms(极经): r = x c o s θ + y s i n θ r=xcosθ+ysinθ r=xcosθ+ysinθ
一般对于每个点(x0,y0),我们可以定义通过该点的直线族为:
r θ = x 0 ∗ cos ⁡ θ + y 0 ∗ sin ⁡ θ r\theta=x_0 * \cos\theta +y_0 * \sin\theta rθ=x0cosθ+y0sinθ
θ \theta θ 的取值范围在 0° ~ 180° 或 0° ~ 360° 之间, 每次取 1°,(x,y)坐标不变 获取一次 r (极坐标的极经)值,获取一定范围内的点绘制成曲线。即:
每一对( r θ rθ rθ, θ θ θ)代表,经过每一行( x 0 x_0 x0, y 0 y_0 y0)。
2:便利所有像素点,绘制曲线,绘制无数条曲线,这些曲线相交与一点,这表明,这些像素点都属于同一条直线。

OpenCvSharp 学习笔记20-- 霍夫变换 - 直线检测 (Hough Line transform)_第3张图片

对于任意一条直线上的点来说,变换到极坐标中, 从 [0 ~ 360] 空间 可以得到 r 的大小,属于同一条直线上的点在极坐标空间 (r,θ) 必然在一个点上有最强的信号出现,据此反算到平面坐标中就可以得到直线上各个点的坐标。从而得到直线。

二,API:

标准的霍夫变换
Cv2.HoughLines():使用标准霍夫变换查找二进制图像中的行。从平面坐标转换到极坐标空间,最终返回输出 (r,θ)表示极坐标空间。
返回值: LineSegmentPolar[]
结果需要自己反变换到平面空间,使用难度较大!

参数 描述
InputArray image 输入图像,8位、单通道、二进制源图像。
double rho 累加器的距离分辨率(以像素为单位),(生成极坐标时的像素扫描的步长)
double theta 累加器的角度分辨率(以弧度为单位) (生成极坐标的角度步长,一般为 1°)
int threshold 累加器阈值参数,只有获取足够交点的极坐标才能看作直线
double srn = 0 对于多尺度霍夫变换,它是距离分辨率的因子。[默认值为0] 如果不是设置0 表示经典霍夫变换
double stn = 0 对于多尺度霍夫变换,它是距离分辨率的因子。[默认值为0] 如果不是设置0 表示经典霍夫变换

霍夫变换直线概率
**Cv2.HoughLinesP:**使用概率霍夫变换查找二进制图像中的线段。最终输出的是直线的两个点坐标
返回值类型:LineSegmentPoint[]

参数 描述
InputArray image 输入图像,8位、单通道、二进制源图像。
double rho 累加器的距离分辨率(以像素为单位),(生成极坐标时的像素扫描的步长)
double theta 累加器的角度分辨率(以弧度为单位) (生成极坐标的角度步长,一般为 1°)
int threshold 阈值参数,只有获取足够交点的极坐标才能看作直线
double minLineLength = 0 最小线长度。比这短的线段将被拒绝。[默认值为0]
double maxLineGap = 0 同一条线上的点之间连接它们的最大允许间隙。[默认值为0]

三,代码:

/// 
        /// 霍夫变换-直线
        /// 
        /// 
        private static void HoughtLine(string imagePath)
        {
            using (Mat srcLine = new Mat(imagePath, ImreadModes.AnyColor | ImreadModes.AnyDepth))
            using (Mat dst = new Mat(srcLine.Size(), MatType.CV_8UC3, Scalar.Blue))
            {
                // 1:边缘检测
                Mat canyy = new Mat(srcLine.Size(), srcLine.Type());
                Cv2.Canny(srcLine, canyy, 60, 200, 3, false);
             
                /*
                 *  HoughLinesP:使用概率霍夫变换查找二进制图像中的线段。
                 *  参数:
                 *      1; image: 输入图像 (只能输入单通道图像)
                 *      2; rho:   累加器的距离分辨率(以像素为单位) 生成极坐标时候的像素扫描步长
                 *      3; theta: 累加器的角度分辨率(以弧度为单位)生成极坐标时候的角度步长,一般取值CV_PI/180 ==1度
                 *      4; threshold: 累加器阈值参数。只有那些足够的行才会返回 投票(>阈值);设置认为几个像素连载一起                     才能被看做是直线。
                 *      5; minLineLength: 最小线长度,设置最小线段是有几个像素组成。
                 *      6;maxLineGap: 同一条线上的点之间连接它们的最大允许间隙。(默认情况下是0):设置你认为像素之间                     间隔多少个间隙也能认为是直线
                 *      返回结果:
                 *      输出线。每条线由一个4元向量(x1, y1, x2,y2)
                 */
                LineSegmentPoint[] linePiont = Cv2.HoughLinesP(canyy, 1, 1, 1, 1, 10);//只能输入单通道图像
                Scalar color = new Scalar(0, 255, 255);
                for (int i = 0; i < linePiont.Count(); i++)
                {
                    Point p1 = linePiont[i].P1;
                    Point p2 = linePiont[i].P2;
                    Cv2.Line(dst, p1, p2, color, 4, LineTypes.Link8);
                }
                
                using (new Window("DST", WindowMode.AutoSize, dst))
                using (new Window("CANYY", WindowMode.AutoSize, canyy))
                using (new Window("SRC", WindowMode.AutoSize, srcLine))
                {
                    Cv2.WaitKey(0);
                }
            }
        }

OpenCvSharp 学习笔记20-- 霍夫变换 - 直线检测 (Hough Line transform)_第4张图片
右边黄色线段为霍夫直线检测值输出。

你可能感兴趣的:(学习笔记)