23.OpenCV的影像分割——分水嶺演算法、影像金字塔演算法
文章目錄
- 前言
- 一、使用分水嶺演算法分割影像
- 1、cv2.distanceTransform()函式
- 2、cv2.connectedComponents()函式
- 3、cv2.watershed()函式
- 二、影像金字塔
- 1、高斯金字塔向下采樣
- 2、高斯金字塔向上采樣
- 3、拉普拉斯金字塔
- 4、應用影像金字塔實作影像的分割和融合
- 三、OpenCV-Python資源下載
- 總結
前言
??主要介紹OpenCV中的分水嶺演算法、影像金字塔對影像進行分割的方法,
一、使用分水嶺演算法分割影像
??分水嶺演算法的基本原理為:將任意的灰度影像視為地形圖表面,其中灰度值高的部分表示山峰和丘陵,而灰度值低的地方表示山谷,用不同顏色的水(標簽)填充每個獨立的山谷(區域最小值);隨著水平面的上升,來自不同山谷(具有不同顏色)的水將開始合并,為了避免出現這種情況,需要在水匯合的位置建造水壩;持續填充水和建造水壩,直到所有的山峰和丘陵都在水下,整個程序中建造的水壩將作為影像分割的依據,
??使用分水嶺演算法執行影像分割操作時通常包含下列步驟:
(1) 將原圖轉換為灰度影像
(2) 應用形態變換中的開運算和膨脹操作,去除影像噪聲,獲得影像邊緣資訊,確定影像背景
(3) 進行距離轉換,再進行閾值處理,確定影像前景
(4) 確定影像的未知區域(用影像的背景減去前景剩余的部分)
(5) 標記背景影像
(6) 執行分水嶺演算法分割影像
1、cv2.distanceTransform()函式
??OpenCV中的cv2.distanceTransform()函式用于計算非0值像素點到0值(背景)像素點的距離,其基本格式如下:
dst = cv2.distanceTransform(src, distanceType, maskSize[, dstType])
dst為回傳的距離轉換結果影像
src為原影像, 必須是8為單通道二值影像
distanceType為距離型別
maskSize為掩膜的大小, 可設定為0, 3或5
dstType為回傳的影像型別, 默認值為CV_32F(32位浮點數)
import cv2
import numpy as np
import matplotlib.pyplot as plt
# cv2.distanceTransform()函式,計算非0值像素點到0值(背景)像素點的距離
img = cv2.imread('home.jpg')
cv2.imshow('original', img)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度操作
cv2.imshow('gray', img_gray)
ret, thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 閾值操作
cv2.imshow('thresh', thresh)
kernel = np.ones((3, 3), np.uint8)
img_open = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) # 形態學操作
cv2.imshow('open', img_open)
img_dilate = cv2.dilate(img_open, kernel, iterations=2) # 膨脹操作,確定背景
cv2.imshow('img_dilate', img_dilate)
img_dist = cv2.distanceTransform(img_dilate , cv2.DIST_L2, 5) # 距離轉換
cv2.imshow('img_dist', img_dist)
cv2.waitKey(0)
cv2.destroyAllWindows()

2、cv2.connectedComponents()函式
??OpenCV中的cv2.connectedComponents()函式用于將影像中的背景標記為0,將其他影像標記為從1開始的整數,其基本格式如下:
ret, labels = cv2.connectedComponents(image[, connectivity[, ltype]])
labels為回傳的標記結果影像, 和image大小一樣
image為要標記的8位單通道影像
connectivity為4或8(默認值), 表示連接性
ltype為回傳的標記結果影像的型別
# cv2.connectedComponents()函式,將影像中的背景標記為0,將其他影像標記為從1開始的整數
ret, imgfg = cv2.threshold(img_dist, 0.7*img_dist.max(), 255, cv2.THRESH_TRUNC)
imgfg = np.uint8(imgfg)
ret, markers = cv2.connectedComponents(imgfg)
plt.imshow(imgfg,cmap='gray')
plt.title('imgfg')
plt.axis('off')
plt.show()
plt.imshow(markers,cmap='gray')
plt.title('markers')
plt.axis('off')
plt.show()


3、cv2.watershed()函式
??OpenCV中的cv2.watershed()函式用于執行分水嶺演算法分割影像,其基本格式如下:
ret = cv2.watershed(image, markers)
ret為回傳的8位或32位單通道影像
image為輸入的8位或32位單通道影像
markers為輸入的32位單通道影像
# cv2.watershed()函式,執行分水嶺演算法分割影像
img = cv2.imread('qizi.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度操作
ret, thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 閾值操作
kernel = np.ones((3, 3), np.uint8)
img_open = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) # 形態學操作
img_dilate = cv2.dilate(img_open, kernel, iterations=3) # 膨脹操作(確定背景)
img_dist = cv2.distanceTransform(img_open, cv2.DIST_L2, 0)
ret, img_fg = cv2.threshold(img_dist, 0.7*img_dist.max(), 255, 2) # 距離操作(確定前景)
img_fg = np.uint8(img_fg)
ret, markers = cv2.connectedComponents(img_fg)
unknown = cv2.subtract(img_dilate, img_fg) # 確定位置未知區域
markers = markers + 1 # 加1使背景不為0
markers[unknown == 255] = 0 # 將未知區域設定為0
img_water = cv2.watershed(img, markers) # 執行分水嶺演算法
plt.imshow(img_water, cmap='gray')
plt.title('watershed')
plt.axis('off')
plt.show()
img[img_water == -1] = [0, 255, 0] # 將原圖中的被標記點設定為綠色
cv2.namedWindow('watershed', cv2.WINDOW_NORMAL)
cv2.imshow('watershed', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

二、影像金字塔
??影像金字塔從解析度的角度分析處理影像,影像金字塔的底部為原始圖,對原始影像進行梯次向下采樣,得到金字塔的其他各層影像,層次越高,解析度越低,影像越小,通常,每向上一層,影像的寬度和高度就為下一層的一半,常見的影像金字塔可分為高斯金字塔和拉普拉斯金字塔,
??高斯金字塔有向上和向下兩種采樣方式,向下采樣時,原始影像為第0層,第1次向下采樣的結果為第1層,第2次向下采樣的結果為第2層,以此類推,每次采樣影像的寬度和高度都減小為原來的一半,所有的圖層構成高斯金字塔,向上采樣的程序和向下采樣的程序相反,每次采樣影像的寬度和高度都擴大為原來的二倍,
1、高斯金字塔向下采樣
??OpenCV中的cv2.pyrDown()函式用于執行高斯金字塔構造的向下采樣步驟,其基本格式如下:
ret = cv2.pyrDown(image[, dstsize[, borderType]])
ret為回傳的結果影像, 型別和輸入影像相同
image為輸入影像
dstsize為結果影像大小
borderType為邊界型別
# 高斯金字塔向下采樣
img = cv2.imread('qizi.jpg')
img1 = cv2.pyrDown(img)
img2 = cv2.pyrDown(img1)
cv2.imshow('img', img)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
print('0層的形狀:', img.shape)
print('1層的形狀:', img1.shape)
print('2層的形狀:', img2.shape)
cv2.waitKey(0)
cv2.destroyAllWindows()


2、高斯金字塔向上采樣
??OpenCV中的cv2.pyrUp()函式用于執行高斯金字塔構造的向下采樣步驟,其基本格式如下:
ret = cv2.pyrUp(image[, dstsize[, borderType]])
ret為回傳的結果影像, 型別和輸入影像相同
image為輸入影像
dstsize為結果影像大小
borderType為邊界型別


3、拉普拉斯金字塔
??拉普拉斯金字塔的第n層是該層高斯金字塔圖像減去n+1層向上采樣的結果獲得的影像,
# 拉普拉斯金字塔
img = cv2.imread('qizi.jpg')
img1 = cv2.pyrDown(img)
img2 = cv2.pyrDown(img1)
img3 = cv2.pyrDown(img2)
imgL0 = cv2.subtract(img, cv2.pyrUp(img1))
imgL1 = cv2.subtract(img1, cv2.pyrUp(img2))
imgL2 = cv2.subtract(img2, cv2.pyrUp(img3))
cv2.imshow('imgL0', imgL0)
cv2.imshow('imgL1', imgL1)
cv2.imshow('imgL2', imgL2)
cv2.waitKey(0)
cv2.destroyAllWindows()

4、應用影像金字塔實作影像的分割和融合
# 應用影像金字塔實作影像融合
img1 = cv2.imread('jiang1.jpg')
img2 = cv2.imread('jiang2.jpg')
#生成影像1的高斯金字塔,向下采樣6次
img = img1.copy()
img1Gaus = [img]
for i in range(6):
img = cv2.pyrDown(img)
img1Gaus.append(img)
#生成影像2的高斯金字塔,向下采樣6次
img = img2.copy()
img2Gaus = [img]
for i in range(6):
img = cv2.pyrDown(img)
img2Gaus.append(img)
#生成影像1的拉普拉斯金字塔,6層
img1Laps = [img1Gaus[5]]
for i in range(5,0,-1):
img = cv2.pyrUp(img1Gaus[i])
lap = cv2.subtract(img1Gaus[i-1],img) #兩個影像大小不同時,做減法會出錯
img1Laps.append(lap)
#生成影像2的拉普拉斯金字塔,6層
img2Laps = [img2Gaus[5]]
for i in range(5,0,-1):
img = cv2.pyrUp(img2Gaus[i])
lap = cv2.subtract(img2Gaus[i-1],img)
img2Laps.append(lap)
#拉普拉斯金字塔拼接:影像1每層左半部分與和影像2每層右半部分拼接
imgLaps = []
for la,lb in zip(img1Laps,img2Laps):
rows,cols,dpt = la.shape
ls=la.copy()
ls[:,int(cols/2):]=lb[:,int(cols/2):]
imgLaps.append(ls)
#從拉普拉斯金字塔恢復影像
img = imgLaps[0]
for i in range(1,6):
img = cv2.pyrUp(img)
img = cv2.add(img, imgLaps[i])
#影像1原影像的半部分與和影像2原影像的右左半部分直接拼接
direct = img1.copy()
direct[:,int(cols/2):]=img2[:,int(cols/2):]
cv2.imshow('Direct',direct) #顯示直接拼接結果
cv2.imshow('Pyramid',img) #顯示影像金字塔拼接結果
cv2.waitKey(0)
cv2.destroyAllWindows()

三、OpenCV-Python資源下載
OpenCV-Python測驗用圖片、中文官方檔案、opencv-4.5.4原始碼
總結
??以上內容介紹了OpenCV-Python的影像分割中分水嶺演算法、影像金字塔演算法的簡單操作,有關Python、資料科學、人工智能等文章后續會不定期發布,請大家多多關注,一鍵三連喲(●’?’●),
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/396349.html
標籤:其他
上一篇:CV系列經典論文(1) -- ResNet: Deep Residual Learning for Image Recognition
下一篇:U-Net論文詳解
