ROB-330 · Lesson 4 of 12 · 30 min

Image filtering, edges and features

Most of an image is uninformative for geometry. A blank wall or a smooth floor gives no way to tell one pixel from its neighbour, so it cannot be matched between images or used to measure motion. What a robot can measure reliably are distinctive structures: edges where brightness changes sharply, and corners where edges meet. This lesson covers the operations that find them, starting with linear filtering, the workhorse of classical image processing, then gradients and edges, then corner detection and the descriptors that let a robot recognize the same corner in another image. These classical tools remain central in robotics because they are fast, well understood and precise to a fraction of a pixel, and learned features (lesson 9) are judged against them.

Linear filtering and convolution

A linear filter replaces each pixel by a weighted sum of its neighbours. The weights form a small array called a kernel, and sliding the kernel over the image is convolution, the same operation met in ROB-230 for one-dimensional signals:

\[(I * h)(u, v) = \sum_{i}\sum_{j} h(i, j)\, I(u - i,\, v - j)\]

The simplest kernel, a box filter, averages a 3 × 3 or 5 × 5 neighbourhood and reduces noise, but it blurs edges and creates ringing artefacts in the frequency domain. The Gaussian kernel, with weights \( h(x, y) \propto e^{-(x^2 + y^2)/2\sigma^2} \), is preferred: it smooths without ringing, its amount of smoothing is set by a single parameter σ, and it is separable, meaning a 2-D Gaussian blur equals a 1-D blur along rows followed by one along columns. Separability cuts the cost from \( k^2 \) to 2k multiplications per pixel for a k-wide kernel. A kernel about 6σ wide (rounded up to an odd number) captures more than 99 % of the weight.

Noise reduction by averaging follows the statistics of ROB-310: averaging n independent noisy pixels reduces the noise standard deviation by \( \sqrt{n} \). A 3 × 3 box filter averages nine pixels and cuts noise by a factor of three, at the cost of detail. Non-linear filters keep edges better. The median filter replaces a pixel with the median of its neighbourhood, which removes isolated salt-and-pepper noise such as dead pixels while leaving a step edge sharp, and the bilateral filter averages only neighbours of similar brightness.

Worked problem

Choosing a Gaussian kernel

A detector needs a Gaussian blur with σ = 1.5 pixels. How wide should the kernel be, and how many multiplications per pixel does a separable implementation use compared with a direct 2-D one?

Show solution
  1. Width about \( 6\sigma = 9 \) pixels, which is odd, so use 9.
  2. Direct 2-D: \( 9 \times 9 = 81 \) multiplications per pixel.
  3. Separable: \( 9 + 9 = 18 \) multiplications per pixel.

Answer: A 9-tap kernel, and the separable version is 4.5 times cheaper, which matters at 30 frames per second on a robot's embedded processor.

Gradients and edges

An edge is a place where brightness changes quickly, so edges are found from the image gradient, the vector of partial derivatives \( (I_u, I_v) \). On a discrete image, derivatives are approximated by convolving with small difference kernels. The Sobel operator combines a difference in one direction with smoothing in the other:

\[S_u = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix}, \qquad S_v = S_u^{\mathsf{T}}\]

The gradient magnitude \( \sqrt{I_u^2 + I_v^2} \) is large at edges, and the gradient direction \( \theta = \operatorname{atan2}(I_v, I_u) \) points across the edge, from dark to bright. Because differentiation amplifies noise (in frequency terms, it boosts high frequencies), images are almost always smoothed with a Gaussian first; the combined operation is a derivative-of-Gaussian filter.

Worked problem

Gradient at a pixel

A 3 × 3 neighbourhood has rows [10, 10, 80], [10, 20, 90] and [10, 30, 90]. Compute the Sobel gradients, magnitude and direction at the centre.

Show solution
  1. \( I_u \): right column minus left column with weights 1, 2, 1: \( (80 - 10) + 2(90 - 10) + (90 - 10) = 70 + 160 + 80 = 310 \).
  2. \( I_v \): bottom row minus top row with weights 1, 2, 1: \( (10 - 10) + 2(30 - 10) + (90 - 80) = 0 + 40 + 10 = 50 \).
  3. Magnitude: \( \sqrt{310^2 + 50^2} = 314 \).
  4. Direction: \( \operatorname{atan2}(50, 310) = 9.2^{\circ} \).

Answer: A strong edge whose gradient points almost straight to the right (9° below horizontal in image coordinates), so the edge itself runs nearly vertically.

The Canny edge detector, published in 1986 and still standard, turns gradient magnitudes into thin, connected edge curves in four steps: smooth with a Gaussian; compute gradient magnitude and direction; apply non-maximum suppression, keeping a pixel only if its magnitude is larger than its two neighbours along the gradient direction, which thins edges to one pixel; and apply hysteresis thresholding with two thresholds, keeping strong edge pixels and any weak ones connected to them. Hysteresis keeps edges continuous through slightly weaker sections while rejecting isolated noise. Robots use edges to find the boundaries of parts, lane markings, shelf fronts and doorways, and to fit lines and circles with the Hough transform or RANSAC (lesson 5).

Corners and the structure tensor

An edge locates position in only one direction: slide along an edge and the image looks the same. A corner, where the image changes in every direction, can be located in both coordinates, which makes corners ideal for matching and tracking. The Harris detector (Harris and Stephens, 1988) measures this by summing products of gradients over a small window W, giving the structure tensor

\[M = \sum_{(u,v) \in W} w(u, v) \begin{bmatrix} I_u^2 & I_u I_v \\ I_u I_v & I_v^2 \end{bmatrix}\]

Its eigenvalues \( \lambda_1, \lambda_2 \) describe how the image changes as the window shifts. Both small: a flat region. One large and one small: an edge. Both large: a corner. Rather than computing eigenvalues, Harris used the response

\[R = \det M - k\,(\operatorname{tr} M)^2 = \lambda_1 \lambda_2 - k(\lambda_1 + \lambda_2)^2\]

with k around 0.04 to 0.06. R is large and positive at corners, negative at edges and small in flat regions. Shi and Tomasi (1994) showed that using \( \min(\lambda_1, \lambda_2) \) directly gives corners that track better; their 'good features to track' are the default in many visual odometry systems. Corner positions can be refined to around 0.1 pixel by fitting to the local gradient pattern.

Worked problem

Classifying with the Harris response

Three windows have structure tensor eigenvalues of (2, 3), (900, 15) and (800, 700). With k = 0.05, compute R for each and classify them.

Show solution
  1. (2, 3): \( 6 - 0.05 \times 25 = 4.75 \): small, flat.
  2. (900, 15): \( 13{,}500 - 0.05 \times 915^2 = 13{,}500 - 41{,}861 = -28{,}361 \): negative, an edge.
  3. (800, 700): \( 560{,}000 - 0.05 \times 1500^2 = 560{,}000 - 112{,}500 = 447{,}500 \): large positive, a corner.

Answer: Flat, edge and corner respectively. In practice R is computed at every pixel and corners are taken as local maxima above a threshold.

Sobel gradients and the Harris response on a synthetic square: the four corners stand out
import numpy as np

def conv2(img, k):
    """Same-size 2-D correlation with zero padding (enough for small kernels)."""
    kh, kw = k.shape
    p = np.pad(img, ((kh // 2,), (kw // 2,)))
    out = np.zeros_like(img, dtype=float)
    for i in range(kh):
        for j in range(kw):
            out += k[i, j] * p[i:i + img.shape[0], j:j + img.shape[1]]
    return out

# synthetic image: a bright square on a dark background
img = np.zeros((60, 60))
img[20:40, 20:40] = 100.0

sobel_u = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], float)
Iu, Iv = conv2(img, sobel_u), conv2(img, sobel_u.T)

g = np.exp(-np.arange(-2, 3) ** 2 / 2.0)
G = np.outer(g, g); G /= G.sum()              # 5 x 5 Gaussian window, sigma 1
Suu, Svv, Suv = conv2(Iu * Iu, G), conv2(Iv * Iv, G), conv2(Iu * Iv, G)
R = Suu * Svv - Suv ** 2 - 0.05 * (Suu + Svv) ** 2

# local maxima above 10 % of the strongest response
thr = 0.1 * R.max()
peaks = []
for y in range(1, 59):
    for x in range(1, 59):
        if R[y, x] > thr and R[y, x] == R[y - 1:y + 2, x - 1:x + 2].max():
            peaks.append((x, y))
print("corners found:", peaks)
print("R at an edge midpoint (30, 20): %.0f" % R[20, 30])
print("R in a flat area (5, 5): %.0f" % R[5, 5])
Output
corners found: [(20, 20), (39, 20), (20, 39), (39, 39)]
R at an edge midpoint (30, 20): -535523558
R in a flat area (5, 5): 0

Scale and the image pyramid

A corner detected with a 5 × 5 window in one image may look rounded and edge-like when the camera moves closer and the structure fills fifty pixels. To match features across changes of distance, detectors must work at several scales. The usual tool is an image pyramid: repeatedly blur and halve the image, and run the detector at each level. Scale-space theory formalizes this: blurring with Gaussians of increasing σ creates a family of images, and features are found where a response, such as the Laplacian of Gaussian or its approximation the difference of Gaussians, peaks in both position and scale. The scale at which a feature peaks tells how big it is, so the same physical structure is found at matching scales in near and far views.

Descriptors: SIFT, ORB and friends

Detecting a corner says where it is; matching it in another image needs a description of what it looks like. A descriptor is a vector computed from the image patch around a feature, designed so that the same physical point gives similar vectors in different images despite changes in viewpoint, lighting and scale.

  • SIFT (scale-invariant feature transform, Lowe, 2004) finds difference-of-Gaussian peaks, assigns each a dominant orientation from local gradients, and describes a rotated, scaled patch by histograms of gradient directions in a 4 × 4 grid of cells with 8 orientation bins each, giving a 128-number vector. It is robust and accurate, and its patent expired in 2020, so it is now freely usable in OpenCV.
  • ORB (oriented FAST and rotated BRIEF, Rublee and others, 2011) is built for speed. FAST finds corners by checking whether a ring of 16 pixels around a candidate has a long run of pixels all brighter or all darker than the centre. BRIEF describes the patch by 256 binary comparisons between pairs of pixels, rotated to the feature's orientation. Binary descriptors are compared with the Hamming distance, the number of differing bits, which modern processors compute in a single instruction. ORB-SLAM, one of the best-known visual SLAM systems, is built on ORB features.
  • Others include SURF, AKAZE and BRISK, and learned descriptors such as SuperPoint (lesson 9), which often match better under large viewpoint and lighting changes.
Three panels. The left panel shows a small image patch with a square outline and three regions labelled flat, edge and corner, each with a small arrow diagram showing how the window can slide: freely in flat, along the edge only, and nowhere without change at the corner. The middle panel shows an ellipse diagram of structure tensor eigenvalues with axes lambda one and lambda two, regions labelled flat, edge and corner. The right panel shows a binary descriptor as a row of 16 black and white cells compared with a second row, with three differing bits highlighted and labelled Hamming distance 3.
Corners can be located in every direction, the structure tensor's eigenvalues separate flat, edge and corner, and binary descriptors are compared by counting differing bits

Worked problem

Comparing binary descriptors

Two 8-bit descriptor fragments are 10110100 and 10011101. What is their Hamming distance? If full 256-bit ORB descriptors of the same point typically differ in about 30 bits and random pairs in about 128, would a distance of 45 suggest a match?

Show solution
  1. XOR: 10110100 ⊕ 10011101 = 00101001, which has three 1 bits.
  2. Hamming distance of the fragments: 3.
  3. A full-descriptor distance of 45 is far closer to the typical match distance of 30 than to the random level of 128.

Answer: Distance 3 for the fragments. A full distance of 45 is a plausible match, though lesson 5 shows how to confirm it with a ratio test and geometric checks.

Common mistakes

  • MistakeDifferentiating a raw image without smoothing

    InsteadSmooth with a Gaussian first, or use derivative-of-Gaussian filters, because differentiation amplifies noise.

  • MistakeUsing a box filter when edges must be preserved

    InsteadUse a Gaussian for clean smoothing, or a median or bilateral filter to keep edges sharp.

  • MistakeTracking points on edges or plain surfaces

    InsteadTrack corners, where the image changes in every direction.

  • MistakeDetecting features at a single scale when distance changes

    InsteadUse an image pyramid or scale-space detector.

  • MistakeComparing binary descriptors with Euclidean distance

    InsteadUse the Hamming distance for ORB, BRIEF and similar descriptors.

Summary and key terms

  • Linear filtering is convolution with a kernel; Gaussian kernels smooth without ringing and are separable.
  • Averaging n pixels cuts noise by \( \sqrt{n} \); median and bilateral filters smooth while keeping edges.
  • Gradients from Sobel or derivative-of-Gaussian filters give edge strength and direction.
  • Canny edges use smoothing, gradients, non-maximum suppression and hysteresis thresholds.
  • The structure tensor's eigenvalues distinguish flat regions, edges and corners; Harris and Shi–Tomasi detectors use them.
  • Image pyramids and scale-space let detectors find the same structure at different distances.
  • Descriptors such as SIFT (128 floats) and ORB (256 bits, Hamming distance) let features be matched between images.
Kernel
The small array of weights used in a linear filter.
Convolution
Sliding a kernel over an image and summing weighted neighbours.
Separable filter
A 2-D filter that can be applied as two 1-D passes.
Image gradient
The vector of partial derivatives of brightness.
Non-maximum suppression
Keeping only pixels whose response exceeds their neighbours along a direction.
Hysteresis thresholding
Using a high and a low threshold so that weak edges connected to strong ones are kept.
Structure tensor
The matrix of summed gradient products that describes local image change.
Image pyramid
A stack of progressively blurred and downsampled versions of an image.
Descriptor
A vector summarizing the appearance of a feature's neighbourhood.
Hamming distance
The number of differing bits between two binary strings.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. How much does a 5 × 5 box filter reduce independent pixel noise?

    Show answer

    By a factor of 5.

  2. What kernel width suits σ = 2?

    Show answer

    About 13 pixels.

  3. Which filter removes isolated dead pixels while keeping edges sharp?

    Show answer

    The median filter.

  4. If \( I_u = 0 \) and \( I_v = 40 \), which way does the gradient point?

    Show answer

    Straight down the image (90°).

  5. What does hysteresis do in Canny?

    Show answer

    Keeps weak edge pixels connected to strong ones.

  6. Eigenvalues (500, 480): flat, edge or corner?

    Show answer

    Corner.

  7. Why do corners make better tracking points than edges?

    Show answer

    They can be located in both directions.

  8. How many numbers are in a SIFT descriptor?

    Show answer

    128.

  9. What is the Hamming distance between 1100 and 1010?

    Show answer

    2.

  10. What structure lets detectors handle changes of scale?

    Show answer

    An image pyramid or scale space.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz