Android OpenCV(三十三):霍夫圓檢測

這是我參與更文挑戰的第 4 天,活動詳情查看: 更文挑戰html

標準霍夫變換的原理就是把圖像空間轉換成參數空間(即霍夫空間),例如霍夫變換的直線檢測就是在距離 -角度空間內進行檢測。圓能夠表示爲:java

( x a ) 2 + ( y b ) 2 = r 2 (x-a)^2+(y-b)^2 = r^2

其中ab表明圓心座標,r表明圓半徑。所以,霍夫變換的圓檢測就是在這三個參數組成的三維空間內進行。原則上,霍夫變換能夠檢測任何形狀。但複雜的形狀須要的參數不少,霍夫空間的維數對應就多,所以在程序實現上所需的內存空間以及運行效率上都不利於把標準霍夫變換應用於實際複雜圖形的檢測中。 因此一些改進的霍夫變換就相繼提出,它們的基本原理就是儘量減少霍夫空間的維數git

霍夫圓檢測

霍夫圓檢測分爲兩個階段:github

  • 檢測圓心
  • 從圓心推導出圓半徑

檢測圓心

檢測圓心的原理是圓心是它所在圓周全部法線的交點。所以只要找到法線的交點,便可肯定圓心。具體步驟以下:數組

  • 邊緣檢測;
  • 計算圖像梯度,並肯定圓周線。圓周線的梯度即爲法線;
  • 在二維霍夫空間內,繪製全部圖形的梯度直線,某座標點上累加和的值越大,說明在該點上直線相交的次數越多,也就越多是圓心;
  • 在霍夫空間內,4領域內進行非最大值抑制;
  • 設定閾值,霍夫空間內累加和大於該閾值的點就對應於圓心。

從圓心推導出圓半徑

  • 計算某一個圓心到全部圓周線的距離;
  • 設定兩個閾值,定義爲最大半徑和最小半徑,保留距離在這兩個半徑之間的值,這意味着咱們檢測的圓不能太大,也不能過小;
  • 對保留下來的距離進行排序;
  • 找到距離相同的那些值,並計算相同值的數量;
  • 設定一個閾值,只有相同值的數量大於該閾值,才認爲該值是該圓心對應的圓半徑;
  • 對每個圓心,完成以上步驟,獲得全部的圓半徑。

API

public static void HoughCircles(Mat image, Mat circles, int method, double dp, double minDist, double param1, double param2, int minRadius, int maxRadius)
複製代碼
  • 參數一:image,待檢測圓形的圖像,必須是CV_8UC1的灰度圖markdown

  • 參數二:circles,檢測結果。每一個圓形用3個參數表示,即(x , y , radius),圓心座標和圓半徑app

  • 參數三:method,檢測圓形的方法標誌,雖然有4個可選項,可是目前只實現了HOUGH_GRADIENTide

    // C++: enum HoughModes
    public static final int
            HOUGH_STANDARD = 0,
            HOUGH_PROBABILISTIC = 1,
            HOUGH_MULTI_SCALE = 2,
            HOUGH_GRADIENT = 3;
    複製代碼
  • 參數四:dp,累加器分辨率與圖像分辨率的反比。例如,若是 dp = 1,則累加器具備與輸入圖像相同的分辨率。若是dp = 2,則累加器的寬度和高度爲輸入圖像一半oop

  • 參數五:minDist,檢測結果中兩個圓心之間的最小距離。若是參數過小,則除了真實的圓圈外,還可能會錯誤地檢測到多個鄰居圓圈。 若是太大,可能會錯過一些圓圈。post

  • 參數六:param1,使用HOUGH_GRADIENT檢測圓形時,它是傳遞給Canny邊緣檢測器的兩個閾值中的較大值(較小值爲較大值的一半)。

  • 參數七:param2,使用HOUGH_GRADIENT檢測圓形時,此參數爲檢測圓形的累加器閾值,閾值越大,則檢測的圓形越精準。

  • 參數八:minRadius,檢測圓的最小半徑。

  • 參數九:minRadius,檢測圓的最大半徑。

操做

/** * 霍夫圓檢測 * author: yidong * 2020/9/2 */
class HoughCircleDetectActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityHoughCircleBinding
    private lateinit var mGray: Mat
    private lateinit var mRgb: Mat
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_hough_circle)
        mBinding.presenter = this

        mGray = Mat()
        mRgb = Mat()
        val source = Utils.loadResource(this, R.drawable.coins)
        Imgproc.cvtColor(source, mGray, Imgproc.COLOR_BGR2GRAY)
        Imgproc.cvtColor(source, mRgb, Imgproc.COLOR_BGR2RGB)
        mBinding.ivLena.showMat(mRgb)
        source.release()
    }

    fun doHoughCircleDetect() {
        val circle = Mat()
        Imgproc.GaussianBlur(mGray, mGray, Size(9.0, 9.0), 2.0, 2.0)

        Imgproc.HoughCircles(
            mGray,
            circle,
            Imgproc.HOUGH_GRADIENT,
            2.0,
            240.0,
            100.0,
            100.0,
            100,
            200
        )

        for (index in 0 until circle.cols()) {
            val content = FloatArray(3)
            circle.get(0, index, content)

            val center =
                Point(content[0].roundToInt().toDouble(), content[1].roundToInt().toDouble())
            val radius = content[2].roundToInt()

            Imgproc.circle(mRgb, center, 3, Scalar(0.0, 255.0, 0.0), -1, 8, 0)
            Imgproc.circle(mRgb, center, radius, Scalar(0.0, 0.0, 255.0), 3, 8, 0)

            mBinding.ivResult.showMat(mRgb)
        }
    }

    override fun onDestroy() {
        mGray.release()
        mRgb.release()
        super.onDestroy()
    }
}
複製代碼

效果

霍夫圓檢測

源碼

github.com/onlyloveyd/…

相關文章
相關標籤/搜索