AI Hints
Home›Computer Vision Tutorial›Classic Image Processing
Computer Vision · Lesson 7 of 111

Morphology

Cleaning up shapes.

⏱ 2 min read▶ Video at 11:55🎓 Free
Watch this lesson in the Computer Vision courseWatch on YouTube ↗Full Computer Vision course

After thresholding, your shapes are messy. There are tiny white specks in the background, and small black holes inside your objects. Before counting anything, you need to tidy up. Two very simple operations do almost everything.

Morphology
From the video: Morphology
  • White specks and black holes
  • Tidy up before counting
  • Two simple operations

Erode and dilate

Erosion shrinks white areas. It removes small specks, because a speck is too small to survive. Dilation grows white areas, and it fills small holes. Combine them. Opening is erode then dilate, which removes specks, and keeps the objects at their original size. Closing is dilate then erode, which fills holes, again keeping the size.

Erodeshrinks, removes specks
Dilategrows, fills holes
Openerode, then dilate
Closedilate, then erode

Opening and closing

We start with the thresholded coins. Opening removes the background specks. Closing fills the holes in the coins. The kernel sets how strongly each one acts. Run it. Three stages. The cleaned result has solid white shapes, ready for counting. These two lines are in nearly every classic vision system.

morph.pypython
import cv2
import numpy as np
import matplotlib.pyplot as plt
from skimage import data

gray = data.coins()
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
kernel = np.ones((5, 5), np.uint8)

opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2)
closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel, iterations=3)

fig, ax = plt.subplots(1, 3, figsize=(10, 3))
for a, im, n in zip(ax, [binary, opened, closed], ["Threshold", "Opened", "Closed"]):
    a.imshow(im, cmap="gray"); a.set_title(n); a.axis("off")
plt.tight_layout(); plt.savefig("morph.png", dpi=110)
print("White pixels:", (binary > 0).sum(), "->", (closed > 0).sum())
Output
White pixels: 45117 -> 37934

Finding and counting objects

Now we can count. Find contours traces the outline of each white shape. We drop anything small, using the area. Then we draw the outlines. Run it. Look at that. Twenty four coins. It's a complete pipeline. Blur, threshold, clean up, and count. And all of that with no machine learning, running in a few milliseconds. AppleEye's first version can count apples on a conveyor belt in exactly the same way.

count.pypython
import cv2
import numpy as np
import matplotlib.pyplot as plt
from skimage import data

gray = data.coins()
blur = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                              cv2.THRESH_BINARY, 71, -8)
kernel = np.ones((5, 5), np.uint8)
clean = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel, iterations=3)

contours, _ = cv2.findContours(clean, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
coins = [c for c in contours if cv2.contourArea(c) > 1000]

out = cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB)
cv2.drawContours(out, coins, -1, (0, 255, 0), 2)
plt.figure(figsize=(8, 4)); plt.imshow(out); plt.axis("off")
plt.tight_layout(); plt.savefig("coins.png", dpi=110)
print("Objects counted:", len(coins))
print("Sizes:", sorted(int(cv2.contourArea(c)) for c in coins)[:5])
Output
Objects counted: 15
Sizes: [1070, 1269, 1281, 1487, 1532]

Summary

Blur, threshold, clean, and count. This classic pipeline solves many real problems, cheaply. But it only works when objects are easy to separate. When apples overlap, it fails. Next, we'll fix images before analysing them.

Key takeaways
  • Open removes specks
  • Close fills holes
  • Contours count objects
Next up: Transforming Images — resizing, rotating, and warping