Saturday, April 5, 2014

Auto-detecting checkerboard corners

This is step 2 of 10 in the tutorial Collecting 3D shape data using StereoMorph

Given a photograph of a checkerboard pattern,


the findCheckerboardCorners() function in the StereoMorph package (v1.2 and higher) can automatically detect the internal corners of the checkerboard


and return these as a series of pixel coordinates to sub-pixel resolution (currently, this function only works with JPEG images).

              [,1]     [,2]
    [1,]  575.1566 387.9233
    [2,]  755.2105 395.1164
    [3,]  935.8325 402.5703
    [4,] 1115.8718 411.0474
    ...

Automated detection of the corners of a checkerboard pattern in a photograph will be used multiple times in this tutorial: to measure the size of checkerboard squares in real-world coordinates, to calibrate a set of cameras in stereo and to test the calibration accuracy. Automated corner detection can also be used to scale photographs for tasks such as 2D morphometrics, eliminating the need to manually digitize a series of points along a ruler.

1. Start by specifying the number of internal corners in the checkerboard. Note that the number of internal corners is not the number of squares but rather the number of corners where black squares adjoin one another. All the checkerboards used in this tutorial have 294 internal corners arranged in a 21 x 14 grid.

> nx <- 21
> ny <- 14

Which number you assign to nx versus ny is arbitrary, so long as you are consistent throughout.

2. Specify the location of the image to be read, the location where the corners should be saved and where to save a “verify image”. The verify image is a copy of the input image with the corners drawn in so that you can check that the correct corners were found and determine in what order they were read (the corner.file and verify.file arguments are optional).

> image.file <- 'Calibration images/v1/DSC_0002.JPG'
> corner.file <- 'Calibration corners/v1/DSC_0002.txt'
> verify.file <- 'Calibration images verify/v1/DSC_0002.JPG'

3. Call findCheckerboardCorners().

> corners <- findCheckerboardCorners(image.file=image.file, nx=nx, ny=ny, corner.file=corner.file, verify.file=verify.file)

Since print.progress argument to findCheckerboardCorners() is TRUE by default, the progress of the function will be returned to the R console. Since corner detection can take several seconds per image, this allows users to track the progress of the function. Whether the expected number of internal corners were found will also be reported to the R console.

You might have images for which findCheckerboardCorners() was unable to find the corners either because of lighting issues or because the checkerboard was at a very oblique orientation. If these are the calibration images, don’t worry – the corners do not have to be found in every image pair for an accurate calibration (at least five images should provide a good calibration). The unsuccessful images will be ignored in subsequent steps. Note that the function assumes, by default, that the checkerboard squares in the image have a perimeter of at least 140 pixels (35 x 35 pixels).

The corners are returned and saved into the variable corners as a matrix with 294 rows and 2 columns. The corners are found to sub-pixel resolution by using information from a 23 x 23 square surrounding each corner to find a more exact corner point.

> corners
          [,1]     [,2]
[1,]  575.1566 387.9233
[2,]  755.2105 395.1164
[3,]  935.8325 402.5703
[4,] 1115.8718 411.0474
...


The order of the returned corners is important for calibrating cameras in stereo and for testing their accuracy. Between the two views and from photo to photo, the corners must be found in the same order. In this way, a corner in a particular row of the matrix will always correspond to the same corner on the checkerboard.

findCheckerboardCorners() will nearly always return the corners in the same order from photo to photo as long as the checkerboard is imaged in a similar orientation. The function looks for the top-left corner relative to the center of the checkerboard. The corners are then ordered first along the nx dimension and secondly along the ny dimension (this is why it is important that nx differs from ny ). This can be verified by checking the verification image (example below) in which the first corner is indicated by a red circle, the last by a blue circle and all intermediate corners are connected by a green line (easy to remember as RGB).
The verification image indicating the found corners and the order in which they were found. The first corner is circled in red, the last in blue with intermediate points connected by green lines.
4. To find the checkerboard corners in multiple images, specify either a folder or a vector of files for image.file, corner.file and verify.file.

> image.file <- 'Calibration images/v1'
> corner.file <- 'Calibration corners/v1'
> verify.file <- 'Calibration images verify/v1'


The function will read all of the images in the folder(s) specified by image.file and the names of the images will be used to name the corner and verification images (with the proper file extensions). In this case, all files in the image.file folder(s) must be images.

5. Then call findCheckerboardCorners() just as before.

> corners <- findCheckerboardCorners(image.file=image.file, nx=nx, ny=ny, corner.file=corner.file, verify.file=verify.file)

Since 8 images are in the image.file folder, the function outputs an array of corners with the dimensions 294 x 2 x 8. The first matrix of corners can be obtained as follows.

> corners[, , 1]
          [,1]     [,2]
[1,]  575.1566 387.9233
[2,]  755.2105 395.1164
[3,]  935.8325 402.5703
[4,] 1115.8718 411.0474
...


In the next step we’ll use findCheckerboardCorners() to measure the printed size of the squares in a checkerboard pattern.

Go to the next step: Measuring checkerboard square size
Go back to the previous step: Creating a checkerboard pattern