Computer vision

Morphological Operations

Shrink, grow, clean and outline shapes by sliding a small shape over the image.

What are morphological operations?

Morphological operations process images based on shapes. They work on binary (black/white) or grayscale images.

Structuring element

A small kernel that defines the neighbourhood shape: rectangle, ellipse, cross or custom.

Applications

  • Noise removal
  • Shape analysis
  • Object extraction
  • Skeletonization

Erosion and dilation

Input

Erosion: min

Erosion: min(neighbourhood)

Shrinks bright regions, removes small white noise, disconnects objects.

Dilation: max(neighbourhood)

Expands bright regions, fills small holes, connects nearby objects.

Erosion

Each pixel takes the minimum of its neighbourhood: white regions shrink and small white noise disappears.

binary
cv2.erode, 5×5

Erosion in OpenCV


          import cv2
          import numpy as np
          # binary image
          _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
          # create structuring element
          kernel = np.ones((5, 5), np.uint8)  # ans:
          # ans: can also use cv2.getStructuringElement()
          # erosion
          eroded = cv2.erode(binary, kernel, iterations=1)  # ans:
          # ans: iterations: number of times to apply
          # effect: shrinks white regions, removes small noise
          # ans: larger kernel or more iterations = more erosion
        

Dilation

Each pixel takes the maximum of its neighbourhood: white regions grow and small black holes fill in.

binary
cv2.dilate, 5×5

Dilation in OpenCV


          # dilation
          dilated = cv2.dilate(binary, kernel, iterations=1)  # ans:
          # effect: expands white regions, fills small holes
          # ans: larger kernel or more iterations = more dilation
          # multiple iterations
          dilated = cv2.dilate(binary, kernel, iterations=3)
          # ans: equivalent to applying it 3 times
        

Opening

Opening = erosion followed by dilation.

binary, with white specks
① erode: specks vanish, shapes shrink
② dilate: shapes grow back, specks stay gone

Opening in OpenCV


        kernel = np.ones((5, 5), np.uint8)
        # opening = erosion + dilation
        opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)  # ans:
        # equivalent to:
        eroded = cv2.erode(binary, kernel)  # ans:
        opening = cv2.dilate(eroded, kernel)  # ans:
        # removes small white noise, preserves large shapes
      

Closing

Closing = dilation followed by erosion.

binary, with black holes
① dilate: holes fill, shapes grow
② erode: shapes shrink back, holes stay filled

Closing in OpenCV


        # closing = dilation + erosion
        closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)  # ans:
        # equivalent to:
        dilated = cv2.dilate(binary, kernel)  # ans:
        closing = cv2.erode(dilated, kernel)  # ans:
        # fills small black holes in white regions
      

Morphological gradient

Gradient = dilation − erosion. It outlines the edges of objects.

binary
gradient

Gradient in OpenCV


          # morphological gradient
          gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel)  # ans:
          # equivalent to:
          dilated = cv2.dilate(binary, kernel)  # ans:
          eroded = cv2.erode(binary, kernel)  # ans:
          gradient = dilated - eroded  # ans:
          # highlights object boundaries
        

Top hat

Top hat = image − opening(image). It extracts small bright features.


          # top hat
          tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, kernel)  # ans:
          # extracts bright regions smaller than the kernel
          # ans: useful for bright objects on a dark background
        
gray
top hat, 9×9

Black hat

Black hat = closing(image) − image. It extracts small dark features.


          # black hat
          blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, kernel)  # ans:
          # extracts dark regions smaller than the kernel
          # ans: useful for dark objects on a bright background
        
gray
black hat, 9×9

Structuring elements


          # rectangular kernel
          rect = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))  # ans:
          # elliptical kernel
          ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))  # ans:
          # cross-shaped kernel
          cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))  # ans:
          # custom kernel
          custom = np.array([[0, 1, 0],
                             [1, 1, 1],
                             [0, 1, 0]], np.uint8)
          # ans: cross-shaped, like a 3x3 MORPH_CROSS
        

Morphology playground

binary

Exercises

Answer first, then press → to check.

Exercises 1 · concepts

What is erosion?

It shrinks bright regions: each pixel becomes its neighbourhood minimum.

What is dilation?

It expands bright regions: each pixel becomes its neighbourhood maximum.

What is opening?

Erosion then dilation; it removes noise.

What is closing?

Dilation then erosion; it fills holes.

What is the morphological gradient?

Dilation minus erosion; it outlines edges.

Exercises 2 · concepts

When to use opening?

To remove small white noise while preserving object shape.

When to use closing?

To fill small holes and connect broken parts.

What is top hat?

img − opening: it extracts small bright features.

What is black hat?

closing − img: it extracts small dark features.

The effect of a larger kernel?

A more aggressive operation that affects larger structures.

Exercises 3 · coding


        # erosion with 3x3 kernel
        kernel = np.ones((3, 3), np.uint8)
        eroded = cv2.erode(binary, kernel, iterations=1)  # ans:
        # dilation with 5x5 kernel
        kernel = np.ones((5, 5), np.uint8)
        dilated = cv2.dilate(binary, kernel, iterations=1)  # ans:
        # opening
        kernel = np.ones((5, 5), np.uint8)
        opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)  # ans:
      

Exercises 4 · coding


        # closing
        kernel = np.ones((5, 5), np.uint8)
        closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)  # ans:
        # morphological gradient
        gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel)  # ans:
        # elliptical kernel
        ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))  # ans:
        result = cv2.morphologyEx(binary, cv2.MORPH_OPEN, ellipse)  # ans:
      

Exercises 5 · mixed


        # top hat with 9x9 kernel
        kernel = np.ones((9, 9), np.uint8)
        tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, kernel)  # ans:
        # black hat
        blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, kernel)  # ans:
        # multiple erosions
        kernel = np.ones((3, 3), np.uint8)
        eroded = cv2.erode(binary, kernel, iterations=3)  # ans:
        # cross-shaped structuring element
        cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))  # ans:
        result = cv2.morphologyEx(binary, cv2.MORPH_OPEN, cross)  # ans: