這是我參與更文挑戰的第 4 天,活動詳情查看: 更文挑戰html
標準霍夫變換的原理就是把圖像空間轉換成參數空間(即霍夫空間),例如霍夫變換的直線檢測就是在距離 -角度空間內進行檢測。圓能夠表示爲:java
其中
a
和b
表明圓心座標,r
表明圓半徑。所以,霍夫變換的圓檢測就是在這三個參數組成的三維空間內進行。原則上,霍夫變換能夠檢測任何形狀。但複雜的形狀須要的參數不少,霍夫空間的維數對應就多,所以在程序實現上所需的內存空間以及運行效率上都不利於把標準霍夫變換應用於實際複雜圖形的檢測中。 因此一些改進的霍夫變換就相繼提出,它們的基本原理就是儘量減少霍夫空間的維數
。git
霍夫圓檢測分爲兩個階段:github
檢測圓心的原理是圓心是它所在圓周全部法線的交點。所以只要找到法線的交點,便可肯定圓心。具體步驟以下:數組
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_GRADIENT
ide
// 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()
}
}
複製代碼