Goal
Detect the inner corners of a checkerboard pattern in a grayscale image and return their subpixel coordinates. Input: an image on pixel domain . Output: a set of subpixel pixel locations marking point-symmetric X-junctions of bright and dark quadrants. The response is built from 1-D line integrals rather than gradients, so it is robust to image noise, low contrast, and moderate blur; accuracy approaches pixel on crisp inputs.
Algorithm
Let denote the grayscale image. Let denote pixel coordinates. Let denote a ray angle. Let denote the half-length of the line-integral window, in pixels. Let denote the discrete angle set. Let denote rotation of an image about its centre by angle with bilinear sampling.
Directional line integral through at angle , of half-length :
Squared gap between the brightest and darkest directional integrals over :
At a point-symmetric X-junction the integral along a centreline through two bright sectors is maximal and along a centreline through two dark sectors is minimal; the gap is squared to keep the response non-negative and to sharpen the local maximum.
A 1-D horizontal box blur of half-width :
Each line integral is obtained by rotating the image into alignment with the -axis, blurring horizontally, and rotating back:
Restricting to halves the number of rotations: the image is rotated once for and once for ; a horizontal box blur on each copy yields the integrals at , a vertical box blur yields the integrals at .
Procedure
- Supersample by a factor of two with bilinear interpolation to reduce aliasing in the rotated copies.
- Produce two rotated copies: and .
- Apply a box blur to each copy along and a box blur along , producing four directional blurs corresponding to angles .
- Rotate each blurred copy back to the original frame, obtaining for .
- Compute pixelwise.
- Smooth with a box filter to suppress discretisation noise.
- Detect local maxima of the smoothed ; discard maxima with and apply non-maximum suppression.
- Subpixel refinement: fit a Gaussian peak to in a small neighbourhood of each retained maximum; downscale coordinates by two to undo the supersampling.
flowchart TB
I["I"] --> S["2× super-<br/>sample"]
S --> R0["rot α=0"]
S --> R1["rot α=π/4"]
R0 --> B0["1-D blur<br/>h & v"]
R1 --> B1["1-D blur<br/>h & v"]
B0 --> U["rotate back"]
B1 --> U
U --> C["f_c = (max−min)²"]
C --> K["k×k smooth"]
K --> N["local max + NMS"]
N --> P["Gaussian peak fit"]
Implementation
The four-image combination in Rust, given the rotated-back directional blurs stacked plane-wise:
fn response_map(fr: [&[f32]; 4], n: usize) -> Vec<f32> {
let mut fc = vec![0.0f32; n];
for p in 0..n {
let v = [fr[0][p], fr[1][p], fr[2][p], fr[3][p]];
let mut lo = v[0];
let mut hi = v[0];
for &x in &v[1..] {
if x < lo { lo = x; }
if x > hi { hi = x; }
}
let d = hi - lo;
fc[p] = d * d;
}
fc
}
fn line_integrals(i: &[f32], w: usize, h: usize, m: i32) -> [Vec<f32>; 4] {
let r0 = i.to_vec();
let r1 = rotate(i, w, h, -std::f32::consts::FRAC_PI_4);
let bx0 = box_blur_h(&r0, w, h, m);
let by0 = box_blur_v(&r0, w, h, m);
let bx1 = box_blur_h(&r1, w, h, m);
let by1 = box_blur_v(&r1, w, h, m);
[
bx0,
by0,
rotate(&bx1, w, h, std::f32::consts::FRAC_PI_4),
rotate(&by1, w, h, std::f32::consts::FRAC_PI_4),
]
}
rotate is an affine resampler with bilinear interpolation about the image centre; box_blur_h and box_blur_v are separable -tap box filters evaluated with a running-sum to stay independently of . The response map is the output of response_map applied to the four planes returned by line_integrals.
Remarks
- Complexity: per image. Rotations are with bilinear sampling; box blurs are via running sums; the per-pixel max/min over four values is constant work. Supersampling multiplies by four.
- The four-angle discretisation is justified by point symmetry: at a true X-junction is a smooth, near-sinusoidal function of with period , and the max/min separation is well approximated by sampling two orthogonal pairs and . The approximation degrades when the junction's centreline angle falls midway between sample angles.
- Kernel half-length encodes the expected radius of the corner support. Typical values are (i.e.\ to blurs). A mismatched either truncates the line integral inside a single sector (small ) or crosses into neighbouring junctions (large ).
- The detector is noise-robust because box-filter sums of intensities attenuate additive image noise by a factor proportional to , whereas gradient-based detectors amplify the same noise through differentiation.
- Skipping the supersample roughly doubles the subpixel error but roughly halves the runtime; the trade-off is linear in pixel count.
- The response map also yields per-corner orientation: fitting a subpixel peak to over recovers both centreline angles, which a downstream grid-growing step can use to seed neighbour search.
- Compared with ChESS: see When to choose ChESS over Duda-Radon on the ChESS page, which hosts the comparison per the older-paper-hosts rule.
References
- A. Duda, U. Frese. Accurate Detection and Localization of Checkerboard Corners for Calibration. British Machine Vision Conference (BMVC), 2018. PDF
- E. D. Sinzinger. A model-based approach to junction detection using radial energy. Pattern Recognition, 2008. DOI: 10.1016/j.patcog.2007.06.032
- C. Harris, M. J. Stephens. A Combined Corner and Edge Detector. Alvey Vision Conference, 1988. DOI: 10.5244/c.2.23
- M. Rufli, D. Scaramuzza, R. Siegwart. Automatic detection of checkerboards on blurred and distorted images. IEEE/RSJ IROS, 2008. DOI: 10.1109/IROS.2008.4650703