Computer vision

Feature Detection

Find the points an algorithm can recognise again: corners, blobs and edges.

What are features?

Feature: a distinctive pattern in an image that can be reliably detected.

Corners

Where edges intersect: a high gradient in several directions.

Blobs

Regions that differ from their surroundings.

Edges

Boundaries between regions.

Why detect features? Object recognition · image matching · tracking · 3-D reconstruction · image stitching

Corner detection

Corner: a point where two edges meet: intensity changes in several directions.

Flat: no change in any direction
Edge: change only across the edge
Corner: change in every direction

Harris corner detector

Measures "corner-ness" from the gradients in a small window.

Gradient matrix (summed over the window):

$$M = \sum \begin{bmatrix} I_x^2 & I_x I_y \\ I_x I_y & I_y^2 \end{bmatrix}$$

Corner response:

$$R = \det(M) - k \cdot \operatorname{trace}(M)^2$$

R > threshold → corner detected.

\(\det(M) = \lambda_1 \lambda_2\) and \(\operatorname{trace}(M) = \lambda_1 + \lambda_2\), where \(\lambda_1, \lambda_2\) are the eigenvalues of \(M\): how strongly intensity changes along the two main directions.

Harris corners in OpenCV


        import cv2
        import numpy as np
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        gray = np.float32(gray)
        # detect harris corners
        corners = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)  # ans:
        # blockSize: neighbourhood size
        # ans: size of the window the gradients are summed over
        # ksize: Sobel kernel size
        # ans: for computing the gradients (3, 5, 7)
        # k: Harris parameter
        # ans: typically 0.04-0.06, a sensitivity parameter
        # threshold to mark corners
        corners = cv2.dilate(corners, None)
        img[corners > 0.01 * corners.max()] = [0, 0, 255]
        # ans: marks corners in red where the response > threshold
      

Shi-Tomasi corner detector

Shi-Tomasi: an improved Harris, better for tracking.

\(R = \min(\lambda_1, \lambda_2)\)

  • Advantage: more reliable corner selection.
  • Use case: optical flow, tracking.

Shi-Tomasi in OpenCV


        # detect good features to track
        corners = cv2.goodFeaturesToTrack(gray, maxCorners=100,
                                          qualityLevel=0.01, minDistance=10)  # ans:
        # maxCorners: maximum number to return
        # ans: the 100 strongest corners
        # qualityLevel: minimum quality (0-1)
        # ans: 0.01 keeps corners > 1% of the best one
        # minDistance: minimum pixel distance between corners
        # ans: at least 10 pixels apart
        # draw corners
        for corner in corners:  # ans:
            x, y = corner.ravel()  # ans:
            cv2.circle(img, (int(x), int(y)), 3, (0, 255, 0), -1)  # ans:
      

FAST corner detector

FAST: Features from Accelerated Segment Test.

  1. Pick a pixel p with intensity \(I_p\).
  2. Consider the circle of 16 pixels around p.
  3. If N contiguous pixels are all brighter than \(I_p + t\), or all darker than \(I_p - t\) → corner.
  4. N is typically 12 (FAST-12).

Advantage: very fast, real-time capable.

FAST in OpenCV


        # create a FAST detector
        fast = cv2.FastFeatureDetector_create()  # ans:
        # detect keypoints
        keypoints = fast.detect(gray, None)  # ans:
        # draw keypoints
        img_kp = cv2.drawKeypoints(img, keypoints, None, color=(0, 255, 0))  # ans:
        # adjust the threshold
        fast.setThreshold(30)
        # ans: higher threshold = fewer, stronger corners
        # control non-max suppression
        fast.setNonmaxSuppression(True)
        # ans: removes adjacent weak corners
      

Three corner detectors, live

Blob detection

Blob: a region significantly different from its surroundings.

SimpleBlobDetector finds bright or dark roughly circular regions, filtered by colour, size (area), circularity, convexity and inertia.

Circularity = 4π · area / perimeter²: 1 for a circle, about 0.785 for a square.

Blob detection in OpenCV


        # create a blob detector with default params
        detector = cv2.SimpleBlobDetector_create()  # ans:
        # detect blobs
        keypoints = detector.detect(gray)  # ans:
        # draw blobs
        img_blobs = cv2.drawKeypoints(img, keypoints, None, (0, 0, 255),
            cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)  # ans:
        # custom parameters
        params = cv2.SimpleBlobDetector_Params()
        params.filterByArea = True
        params.minArea = 100
        params.maxArea = 5000
        params.filterByCircularity = True
        params.minCircularity = 0.8
        detector = cv2.SimpleBlobDetector_create(params)  # ans:
        # ans: detects circular blobs of 100-5000 pixels, circularity > 0.8
      

Exercises

Answer first, then press → to check.

Exercises 1 · concepts

What is a corner?

A point with a high gradient in several directions.

Why detect features?

Object recognition, matching, tracking, stitching.

What does Harris detect?

Corners, using the gradient matrix.

What is the difference between Harris and Shi-Tomasi?

Shi-Tomasi uses min(λ1, λ2), which is better for tracking.

What is FAST?

A fast corner detector that tests a circle of pixels.

Exercises 2 · concepts

What is a blob?

A region significantly different from its surroundings.

What is the k parameter in Harris?

The sensitivity, typically 0.04-0.06.

What is qualityLevel in goodFeaturesToTrack?

The minimum quality, as a fraction (0-1) of the best corner.

Why is FAST fast?

A simple comparison test; no gradient computation.

What does the minDistance parameter do?

It keeps corners at least N pixels apart.

Exercises 3 · coding


        # detect Harris corners
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        gray = np.float32(gray)
        corners = cv2.cornerHarris(gray, 2, 3, 0.04)  # ans:
        # detect Shi-Tomasi corners
        corners = cv2.goodFeaturesToTrack(gray, 100, 0.01, 10)  # ans:
        # create a FAST detector
        fast = cv2.FastFeatureDetector_create()  # ans:
        keypoints = fast.detect(gray, None)  # ans:
      

Exercises 4 · coding


        # detect blobs
        detector = cv2.SimpleBlobDetector_create()  # ans:
        keypoints = detector.detect(gray)  # ans:
        # draw Harris corners
        corners = cv2.cornerHarris(gray, 2, 3, 0.04)
        corners = cv2.dilate(corners, None)
        img[corners > 0.01 * corners.max()] = [0, 0, 255]  # ans:
        # draw Shi-Tomasi corners
        corners = cv2.goodFeaturesToTrack(gray, 100, 0.01, 10)
        for corner in corners:  # ans:
            x, y = corner.ravel()  # ans:
            cv2.circle(img, (int(x), int(y)), 3, (255, 0, 0), -1)  # ans:
      

Exercises 5 · mixed


        # adjust the FAST threshold
        fast = cv2.FastFeatureDetector_create()
        fast.setThreshold(50)  # ans:
        keypoints = fast.detect(gray, None)  # ans:
        # detect the top 50 Shi-Tomasi corners
        corners = cv2.goodFeaturesToTrack(gray, 50, 0.01, 10)  # ans:
        # custom blob parameters
        params = cv2.SimpleBlobDetector_Params()
        params.filterByArea = True  # ans:
        params.minArea = 50  # ans:
        params.maxArea = 1000  # ans:
        detector = cv2.SimpleBlobDetector_create(params)  # ans: