圖像分割:從基礎到實踐
學習目標
通過本課程,學員們將了解圖像分割的基本概念,掌握使用OpenCV實現圖像分割的方法,包括基于閾值的分割和基于區域的分割技術。同時,學員將能夠獨立完成簡單的圖像分割任務,并理解其背后的原理。
相關知識點
- Python OpenCV圖像分割
學習內容
1 Python OpenCV圖像分割
1.1 圖像分割基礎
圖像分割是計算機視覺中的一個基本問題,它涉及將圖像劃分為多個部分或區域,每個部分或區域具有相似的屬性,如顏色、紋理或亮度。圖像分割是許多高級圖像處理任務的基礎,如對象識別、圖像分析和醫學圖像處理等。在圖像分割中,目標是將圖像中的像素分組為多個區域,每個區域對應于圖像中的一個特定對象或部分。
圖像分割的重要性在于它能夠幫助計算機理解圖像的內容,從而為后續的圖像分析和處理提供基礎。例如,在醫學圖像處理中,通過分割可以準確地識別出腫瘤的位置和大小;在自動駕駛技術中,圖像分割可以幫助車輛識別道路、行人和其他障礙物。
在本課程中,學員將首先了解圖像分割的基本概念,包括分割的目的、常見的分割方法以及分割結果的評估標準。接下來,探討圖像分割在實際應用中的重要性,以及如何選擇合適的分割方法來解決特定的問題。
1.2 基于閾值的圖像分割
基于閾值的圖像分割是最簡單也是最常用的圖像分割方法之一。這種方法的基本思想是根據圖像的灰度值或顏色值將圖像中的像素分為不同的類別。閾值的選擇是基于閾值分割的關鍵,不同的閾值選擇方法適用于不同的圖像和應用場景。
1.2.1 簡單閾值分割
執行以下指令獲取測試圖片。
!wget https://model-community-picture.obs.cn-north-4.myhuaweicloud.com/ascend-zone/notebook_datasets/3c363b682faa11f09680fa163edcddae/example.jpg
簡單閾值分割是最基本的閾值分割方法,它通過設定一個固定的閾值來將圖像中的像素分為前景和背景。如果像素的灰度值大于閾值,則該像素被標記為前景;否則,被標記為背景。這種方法適用于背景和前景之間灰度值差異明顯的圖像。
import cv2
import numpy as np
from matplotlib import pyplot as plt# 讀取圖像
img = cv2.imread('example.jpg', 0)# 應用簡單閾值分割
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)# 顯示結果
plt.subplot(1, 2, 1), plt.imshow(img, 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(thresh1, 'gray')
plt.title('Thresholded Image'), plt.xticks([]), plt.yticks([])
plt.show()
1.2.2 自適應閾值分割
自適應閾值分割是一種更高級的閾值分割方法,它根據圖像的局部特性動態地選擇閾值。這種方法適用于圖像中背景和前景灰度值變化較大的情況。自適應閾值分割通過計算每個像素周圍的局部平均灰度值來確定閾值,從而更好地適應圖像的局部特性。
# 應用自適應閾值分割
thresh2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)# 顯示結果
plt.subplot(1, 2, 1), plt.imshow(img, 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(thresh2, 'gray')
plt.title('Adaptive Thresholded Image'), plt.xticks([]), plt.yticks([])
plt.show()
1.3 基于區域的圖像分割
基于區域的圖像分割方法通過分析圖像中的區域特性來實現分割。這些方法通常基于圖像的連通性、顏色或紋理等特征,將圖像中的像素分組為不同的區域。基于區域的分割方法適用于圖像中對象邊界不明顯或背景復雜的情況。
1.3.1 連通區域標記
連通區域標記是一種基于區域的分割方法,它通過標記圖像中的連通區域來實現分割。連通區域是指圖像中具有相同或相似屬性的像素集合。通過連通區域標記,可以將圖像中的不同對象或部分區分開來。
# 讀取圖像
img = cv2.imread('example.jpg', 0)# 二值化圖像
ret, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)# 連通區域標記
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary, connectivity=8)# 顯示結果
plt.imshow(labels, cmap='jet')
plt.title('Connected Components'), plt.xticks([]), plt.yticks([])
plt.show()
1.3.2 分水嶺算法
分水嶺算法是一種基于區域的分割方法,它通過模擬地形中的分水嶺來實現圖像分割。分水嶺算法將圖像中的每個像素視為地形中的一個點,通過模擬水從高處流向低處的過程,將圖像中的不同區域分隔開來。分水嶺算法適用于圖像中對象邊界不明顯或背景復雜的情況。
# 讀取圖像
img = cv2.imread('example.jpg')# 轉換為灰度圖像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化圖像
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# 距離變換
dist_transform = cv2.distanceTransform(binary, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)# 找到未知區域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(binary, sure_fg)# 標記連通區域
ret, markers = cv2.connectedComponents(sure_fg)# 將所有標記加1,確保背景為1
markers = markers + 1# 將未知區域標記為0
markers[unknown == 255] = 0# 應用分水嶺算法
markers = cv2.watershed(img, markers)
img[markers == -1] = [255, 0, 0]# 顯示結果
plt.subplot(1, 2, 1), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Watershed Segmentation'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(markers, cmap='jet')
plt.title('Markers'), plt.xticks([]), plt.yticks([])
plt.show()