# Chequerboard Corner Detection (2011/09/25)

Camera calibration is a fundamental problem in computer vision. In the third episode of the Computer Vision for the Robotic Age podcast I am demonstrating a robust algorithm for identifying the corners of a chequerboard pattern. Identifying the corners of a calibration grid is the initial step for camera calibration.

```require 'rubygems'
require 'hornetseye_ffmpeg'
require 'hornetseye_xorg'
include Hornetseye
class Node
# Non-maxima suppression for corners
def nms(threshold)
# compare image with dilated image and threshold
self >= dilate.major(threshold)
end
# Find a component with 'n' corners
def have(n, corners)
# compute number of corners for each component
hist = mask(corners).histogram max + 1
# compare number of corners with desired number
msk = hist.eq n
if msk.inject :or
# get label of connected component
id = argmax { |i| msk.to_ubyte[i] }.first
eq id
else
# return nil
nil
end
end
def corners(sigma = 5.0, size = 21)
size2 = size / 2
# generate chequer pattern
f1 = finalise(size, size) do |i,j|
x, y = i - size2, j - size2
x * y * Math.exp( -(x ** 2 + y ** 2) / sigma ** 2)
end
# generate chequer pattern rotated by 45°
f2 = finalise(size, size) do |i,j|
x, y = i - size2, j - size2
0.5 * (x ** 2 - y ** 2) * Math.exp( -(x ** 2 + y ** 2) / sigma ** 2)
end
# apply filter pair and compute corner strength
Math.hypot convolve(f1), convolve(f2)
end
end
# relative threshold for corner image
CORNERS = 0.6
# absolute threshold for greylevel image
THRESHOLD = 90
# width and height of calibration grid
W, H = 8, 5
W2, H2 = 0.5 * (W - 1), 0.5 * (H - 1)
N = W * H
# dilation constant
GRID = 7
# open input video
input = AVInput.new 'calibration.avi'
width, height = input.width, input.height
X11Display.show do
# convert to greyscale
grey = img.to_ubyte
# call method for computing corner image
corners = grey.corners
# call method for non-maxima suppression
nms = corners.nms CORNERS * corners.max
# threshold image
binary = grey > THRESHOLD
# find edges using dilation and erosion
edges = binary.dilate(GRID).and binary.erode(GRID).not
# find connected edges
components = edges.components
# check for edge region with 'N' corners
grid = components.have N, nms
if grid
# visualise calibration grid
grid.and(nms).dilate.conditional RGB(255, 255, 0), img
else
# visualise detected corners
nms.dilate.conditional RGB(255, 0, 0), img
end
end
```