标准霍夫变换识别粗直线

Posted lc__________

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了标准霍夫变换识别粗直线相关的知识,希望对你有一定的参考价值。

在项目中需要识别粗直线。

正常来讲对于直线的识别需要对图像进行边缘检测,再对边缘检测后的图像进行概率霍夫变换。但是对于存在粗直线的图像,边缘检测后,粗直线非边缘的部分就被过滤掉了,有效信息会有部分丢失,且opencv中霍夫变换的效果不太理想,以至于对于两条边缘直线的合并就更加困难了。因此想对霍夫线变换进行改进。

概率霍夫变换效率高于标准霍夫变换,而且可以找到线段的两个端点,是一般大家用的比较多的方法。

概率霍夫变换会沿着直线的方向继续寻找直线上的点,以确定线段的两个端点。但是在粗直线中,这不方便被表示,因此选用了更耗时的标准霍夫变换。

opencv中实现霍夫变换的步骤如下:

1.对边缘图像进行霍夫变换

2.对霍夫空间进行4领域内的非最大值抑制

3.对极大值进行排序,极值越大,则越有可能是直线

4.输出直线

我的改进:

1.不对图像进行边缘检测。直接对二值图像中的黑色像素点进行霍夫变换

2.非最大值抑制对于粗直线来说没有太大意义,因此不进行非最大值抑制,直接对霍夫变换后的结果进行排序

我用的是VB.net + EmguCv

Sub ThickLineHoughLinesStandard(ByVal img As Image(Of Gray, Byte),
                                         ByVal rho As Double,
                                         ByVal theta As Double,
                                         ByVal threshold As Integer,
                                         ByRef output As ArrayList)
        Dim width As Integer = img.Width
        Dim height As Integer = img.Height
        Dim numangle, numrho As Integer
        Dim total As Integer = 0
        Dim irho As Double = 1 / rho
        Dim scale As Double

        numangle = Int(Math.PI / theta)
        numrho = Int(((img.Width + img.Height) * 2 + 1) / rho)

        Dim accum((numangle + 2) * (numrho + 2)) As Integer
        Dim sort_buf(numangle * numrho) As Integer

        Dim ang As Double = 0.0
        Dim tabSin As Hashtable = New Hashtable
        Dim tabCos As Hashtable = New Hashtable
        '为避免重复运算,事先计算好sinθi/ρ和cosθi/
        For n = 0 To numangle - 1
            tabSin(n) = Math.Sin(ang) * irho
            tabCos(n) = Math.Cos(ang) * irho
            ang += theta
        Next
        '执行步骤1,逐点进行霍夫变换,并把结果放入累加器中
        For i = 0 To height - 1
            For j = 0 To width - 1
                '只对图像的非零值进行处理,即只对图像的边缘像素进行霍夫变换
                If img.Data(i, j, 0) = 0 Then
                    For n = 0 To numangle - 1
                        Dim r As Integer = Math.Floor(j * tabCos(n) + i * tabSin(n))
                        r += (numrho - 1) / 2
                        accum((n + 1) * (numrho + 2) + r + 1) = accum((n + 1) * (numrho + 2) + r + 1) + 1
                    Next
                End If
            Next
        Next
        '执行步骤2,找到局部极大值
        For r = 0 To numrho - 1
            For n = 0 To numangle - 1
                Dim base As Integer = (n + 1) * (numrho + 2) + r + 1
                If accum(base) > threshold Then
                    sort_buf(total) = base
                    total += 1
                End If
            Next
        Next
        '执行步骤3,对存储再sort_buf数组内的累加器的数据由大到小进行排序
        Dim sortBaseHashtable As New Hashtable
        Dim sortAccumHashtable As New Hashtable
        Dim sortArray As New ArrayList
        For s = 0 To total - 1
            sortBaseHashtable(s) = sort_buf(s)
            sortAccumHashtable(s) = accum(sort_buf(s))
            sortArray.Add(accum(sort_buf(s)))
        Next
        sortArray.Sort()
        Dim outputSortBuf(sortArray.Count - 1) As Integer
        Dim outputSortCount As Integer = 0
        For s = sortArray.Count - 1 To 0 Step -1
            For Each a In sortAccumHashtable
                If Val(sortArray(s)) = Val(a.value) Then
                    outputSortBuf(outputSortCount) = sortBaseHashtable(s)
                    outputSortCount += 1
                    sortAccumHashtable.Remove(Int(a.key))
                    Exit For
                End If
            Next
        Next
        '执行步骤4,输出直线
        scale = 1.0 / (numrho + 2)
        For i = 0 To total - 1
            Dim line As New Line
            'idx为极大值在累加器数组的位置
            Dim idx As Integer = outputSortBuf(i)
            '分离出该极大值在霍夫空间中的位置
            Dim n As Integer = Math.Floor(idx * scale - 1)
            Dim r As Integer = idx - (n + 1) * (numrho + 2) - 1
            '最终得到极大值所对应的角度和距离
            line.rho = (r - (numrho - 1) * 0.5F) * rho
            line.angle = n * theta
            output.Add(line)
        Next
    End Sub
ThickLineHoughLinesStandard(img, 1, Math.PI / 15.0, 200, output)
For Each Line In output
    Dim a As Double = Math.Cos(Line.angle)
    Dim b As Double = Math.Sin(Line.angle)
    Dim x0 As Double = a * Line.rho
    Dim y0 As Double = b * Line.rho
    Dim k As New LineSegment2D
    k.P1 = New Point(x0 + 2000 * (-b) + 20, y0 + 2000 * a + 50)
    k.P2 = New Point(x0 - 2000 * (-b) + 20, y0 - 2000 * a + 50)
    outputImg.Draw(k, New Bgr(Color.Red), 1)
Next
outputImg.Save(Application.StartupPath + "\\img\\output.bmp")

最终输出的直线中,角度相同,rho连续的直线组合成了我想要找到的粗直线~

以上是关于标准霍夫变换识别粗直线的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV探索之路:霍夫变换

Python+OpenCV图像处理(十四)—— 直线检测

霍夫变换检测直线(HoughLines)

HoughLinesP(霍夫变换直线检测)

Python OpenCV 霍夫(Hough Transform)直线变换检测原理,图像处理第 33 篇博客

opencv —— HoughLinesHoughLinesP 霍夫线变换(标准霍夫线变换多尺度霍夫线变换累积概率霍夫线变换)