This is the fourth day of my participation in Gwen Challenge

The principle of standard Hough transform is to transform image space into parameter space (namely Hough space). For example, the straight line detection of Hough transform is detected in range-angle space. A circle can be expressed as:


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

Where a and b represent the coordinates of the center and r represents the radius of the circle. Therefore, the circle detection of Hough transform is carried out in the three-dimensional space composed of these three parameters. In principle, hough transform can detect any shape. However, complex shapes require many parameters, and the dimensions of Hough space correspond to many, so the memory space required for program implementation and running efficiency are not conducive to the application of standard Hough transform in the detection of actual complex shapes. So some improved Hough transforms have been proposed, their basic principle is to minimize the dimensionality of hough Spaces.

Hough circle detection

Hough circle detection is divided into two stages:

  • Testing center of the circle
  • The radius of the circle is derived from the center

Testing center of the circle

The principle of detecting the center of a circle is that the center of a circle is the intersection of all the normals of its circumference. So if you find the intersection of the normals, you can determine the center of the circle. The specific steps are as follows:

  • Edge detection;
  • Calculate the image gradient and determine the circumference. The gradient of the circumference is the normal;
  • In two-dimensional Hough space, the gradient lines of all graphs are drawn. The larger the sum value at a certain coordinate point is, the more times the lines intersect at that point, and the more likely they are to be the center of a circle.
  • In hough space, non-maximum suppression is performed in 4 domains.
  • Set a threshold, and any point in hough space whose sum is greater than this threshold corresponds to the center of the circle.

The radius of the circle is derived from the center

  • Calculate the distance between the center of a circle and all the circumference lines;
  • Set two thresholds, defined as the maximum radius and the minimum radius, and retain the value of the distance between these two radii, which means that the circle we detect should not be too large or too small;
  • Sort the remaining distance;
  • Find those values that are the same distance and count the number of the same values;
  • Set a threshold value, only when the number of the same value is greater than the threshold value, the value is considered to be the circle radius corresponding to the center of the circle;
  • For each center, complete the above steps to get all the radius of the circle.

API

public static void HoughCircles(Mat image, Mat circles, int method, double dp, double minDist, double param1, double param2, int minRadius, int maxRadius)
Copy the code
  • Parameter 1: image: the circular image to be detected must be the grayscale image of CV_8UC1

  • Parameter 2: Circles, detection result. Each circle is represented by three parameters, namely (x, y, radius), the center coordinates and the radius of the circle

  • Parameter 3: Method, the method mark to detect the circle. Although there are four options, only HOUGH_GRADIENT has been realized so far

    // C++: enum HoughModes
    public static final int
            HOUGH_STANDARD = 0,
            HOUGH_PROBABILISTIC = 1,
            HOUGH_MULTI_SCALE = 2,
            HOUGH_GRADIENT = 3;
    Copy the code
  • Parameter 4: DP, inverse ratio of accumulator resolution to image resolution. For example, if dp = 1, the accumulator has the same resolution as the input image. If dp = 2, the width and height of the accumulator are half of the input image

  • Parameter 5: minDist, the minimum distance between two centers in the detection result. If the parameter is too small, you may incorrectly detect multiple neighbor circles in addition to the real one. If it’s too big, you might miss some circles.

  • Parameter 6: Param1. When detecting the circle using HOUGH_GRADIENT, it is the larger value of the two thresholds passed to the Canny edge detector (the smaller value is half of the larger value).

  • Parameter 7: Param2. When HOUGH_GRADIENT is used to detect the circle, this parameter is the accumulator threshold of detecting the circle. The larger the threshold is, the more accurate the circle is detected.

  • Parameter 8: minRadius: detects the minimum radius of a circle.

  • Parameter 9: minRadius, which checks the maximum radius of the circle.

operation

/** * hofidong * 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(a) {
        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(a) {
        mGray.release()
        mRgb.release()
        super.onDestroy()
    }
}
Copy the code

The effect

The source code

Github.com/onlyloveyd/…