iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0
Software Development

從像素到 Computer Vision:30 天理解數位影像處理系列 第 21

Day 21 | Connected Component:電腦怎麼知道這是幾個物體?

  • 分享至 

  • xImage
  •  

上一篇介紹了 Morphology。

經過 Erosion 和 Dilation 後,我們已經可以把二值化圖片中的雜訊去除,或是修補一些破損的區域。

不過,當圖片整理乾淨之後,又有另一個問題。

如果圖片裡有好幾個白色區域,電腦要怎麼知道它們分別代表幾個不同的物體?

例如一張細胞影像,電腦要知道有幾顆細胞;或是一張文件圖片,電腦要知道有幾個文字區塊。

對我們來說,這些物體一眼就能分辨。

但對電腦而言,它看到的仍然只是一張由許多 Pixel 組成的二值化圖片。

那它要怎麼判斷哪些 Pixel 屬於同一個物體?

這就是 Connected Component(連通元件分析) 要解決的問題。

Connected Component 在做什麼?

Connected Component 的概念,就是把彼此相連的 Pixel 視為同一個物體,並替每個物體分配一個不同的 Label(標籤)。

舉例來說,如果圖片中有三個互不相連的白色區域,分析完成後,第一個區域可能被標記為 Label 1,第二個區域標記為 Label 2,第三個區域則標記為 Label 3。

之後,只要看到相同的 Label,電腦就知道這些 Pixel 屬於同一個物體。

什麼叫做「相連」?

看到這裡,問題來了:

如果兩個 Pixel 只有對角線接觸,也算是相連嗎?

其實,在影像處理中有兩種常見的定義:

  • 4-Connected,只考慮上下左右四個方向。

  • 8-Connected,除了上下左右之外,也把四個對角線算進來。

OpenCV 預設採用 8-Connected,因為它通常比較符合人眼對「連在一起」的直覺。

實作:使用 Connected Component

OpenCV 已經提供了 connectedComponents() 函式。

import cv2
import matplotlib.pyplot as plt

# 讀取圖片
img = cv2.imread("dog.jpeg", cv2.IMREAD_GRAYSCALE)

# 二值化
_, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# Connected Component
num_labels, labels = cv2.connectedComponents(binary)

print(f"Number of labels: {num_labels}")

這個函式會回傳兩個值。

  • num_labels:圖片中總共有多少個 Label。
  • labels:每個 Pixel 所屬的 Label。

需要注意的是,背景也會被算作一個 Label

因此,如果圖片中有三個物體,num_labels 的結果會是 4,其中 Label 0 代表背景。

將 Label 視覺化

labels 本身是一個矩陣,每個數字代表不同的物體。

我們可以利用 Matplotlib,把不同的 Label 顯示成不同顏色。

plt.figure(figsize=(10, 4))

plt.subplot(1, 2, 1)
plt.imshow(binary, cmap="gray")
plt.title("Binary")
plt.axis("off")

plt.subplot(1, 2, 2)
plt.imshow(labels, cmap="nipy_spectral")
plt.title("Connected Components")
plt.axis("off")

plt.tight_layout()
plt.show()

執行結果如下:

https://ithelp.ithome.com.tw/upload/images/20260907/201817805coUwZv1v8.png

可以看到,每個物體都會以不同顏色顯示,因此很容易確認哪些 Pixel 被判定為同一個物體。

不只能知道有幾個物體

如果只是知道物體數量,其實還不夠。

OpenCV 另外提供了 connectedComponentsWithStats(),除了 Label 之外,還可以取得每個物體的統計資訊。

import cv2

img = cv2.imread("binary.png", cv2.IMREAD_GRAYSCALE)
_, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary)

for label in range(1, num_labels):
    x = stats[label, cv2.CC_STAT_LEFT]
    y = stats[label, cv2.CC_STAT_TOP]
    w = stats[label, cv2.CC_STAT_WIDTH]
    h = stats[label, cv2.CC_STAT_HEIGHT]
    area = stats[label, cv2.CC_STAT_AREA]

    print(
        f"Object {label}: "
        f"Position=({x}, {y}), "
        f"Size={w}×{h}, "
        f"Area={area}"
    )

透過這些資訊,我們可以知道每個物體的位置、大小以及面積。

例如,如果想把面積太小的區域視為雜訊,只要根據 area 進行篩選即可。

Connected Component 的應用

Connected Component 常出現在影像處理的最後幾個步驟。

例如:

  • OCR:找出每一個文字區塊。
  • 細胞分析:計算細胞數量。
  • 工業檢測:統計產品數量。
  • 車牌辨識:將每個字元分割出來。

可以發現,它是在物體已經分割完成後,進一步分析每一個物體。

今天總結

今天介紹了 Connected Component。

它會把彼此相連的 Pixel 分配相同的 Label,讓電腦知道哪些 Pixel 屬於同一個物體。

搭配 connectedComponentsWithStats(),我們還可以取得每個物體的位置、大小、面積和中心點,方便進一步分析或篩選。

一路看到這裡,我們已經學會利用 Pixel 的亮度、鄰近關係以及形狀來分析圖片。

不過,這些方法都有一個共同點:

它們都是直接在圖片本身進行運算,也就是所謂的空間域(Spatial Domain)

那如果換個角度,不再觀察每一個 Pixel,而是分析整張圖片包含哪些不同頻率的資訊,會發生什麼事?

下一篇,我們就來介紹 Fourier Transform(傅立葉轉換),看看如何把圖片從空間域轉換到另一個完全不同的世界。


上一篇
Day 20 | Morphology:怎麼把二值化後的圖片整理乾淨?
下一篇
Day 22 | Fourier Transform:圖片也能分析頻率?
系列文
從像素到 Computer Vision:30 天理解數位影像處理25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言