这是我参与更文挑战的第 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()
}
}
复制代码