參考文獻:
OTSU閾值分割+孔洞填充+海陸分離_SwordKii的博客-CSDN博客
drawContours函數(shù)_普通網(wǎng)友的博客-CSDN博客_drawcontours
R329-opencv閾值分割算法——自適應閾值_Third Impact的博客-CSDN博客_opencv自適應閾值分割
分水嶺算法的python實現(xiàn)及解析_進不去的博客-CSDN博客_python分水嶺算法
分水嶺算法的理解和應用_Evonne_H的博客-CSDN博客_分水嶺算法詳細介紹與應用
目錄
OTSU大津算法(常用于海陸分割)
1.原理:
2.代碼API
3.實現(xiàn):
自適應閾值算法(復雜顏色地物提取例如打魚船)
1.原理
2.代碼API
3.實現(xiàn)
分水嶺算法
OTSU大津算法(常用于海陸分割)
1.原理:
尋找海陸分割二值化的閾值,通過統(tǒng)計學方法,常用來處理直方圖中有倆個峰的圖像,就如同海陸倆個顏色比較多的圖片,找到方差最大的時候的灰度值
2.代碼API
#獲取二值圖像輪廓
contours, hierarchy=cv.findContours( img, mode,? method);
contours:輸出的輪廓,每一個輪廓用std::vector<std::vector<cv::Point> >來存儲;
hierarchy:輸出的輪廓關系的存儲;
img:二值圖像;
mode:輪廓模式
cv.RETR_EXTERNAL:只有最外層輪廓;
cv.RETR_LIST? : 檢測所有的輪廓,但是輪廓之間都是單獨的,沒有父子關系;
cv.RETR_CCOMP : 檢測所有的輪廓,但所有輪廓只建立兩個等級關系;如果超過兩個等級關系的,從頂層開始每兩層分解成一個輪廓;
cv.RETR_TREE : 檢測所有輪廓,所有輪廓按照真實的情況建立等級關系,層數(shù)不限;
method:輪廓處理:
cv.CHAIN_APPROX_NONE :不經(jīng)過處理
cv.CHAIN_APPROX_SIMPLE:壓縮輪廓
cv.CHAIN_APPROX_TC89_L1:用Teh-Chin chain approximation algorithm的一種算法壓縮輪廓;
cv.CHAIN_APPROX_TC89_KCOS:用Teh-Chin chain approximation algorithm的另一種算法壓縮輪廓;
#畫出二值圖像輪廓cv.drawContours( img, contours, contourIdx,color, thickness=1)
函數(shù)參數(shù)詳解:
contours:輸入的輪廓組,每一組輪廓由點vector構成,
contourIdx:int 指明畫第幾個輪廓,如果該參數(shù)為負值,則畫全部輪廓,
color:輪廓的顏色,
thickness:輪廓的線寬,如果為負值或CV_FILLED表示填充輪廓內(nèi)部,
#輪廓面積
area = cv.contourArea(contours[i])
#填充輪廓
cv.fillPoly(img,contours,color)
3.實現(xiàn):
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
#解決中文顯示問題,固定格式
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#1.轉化為灰度圖
pic1=cv.imread("DJI_0023.jpg")
#2.高斯濾波去噪
pic1 = cv.GaussianBlur(pic1, (5,5), 0) # 高斯濾波
gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)
#3.OUST算法轉換為二值圖
floatshold,bin = cv.threshold(gray, 0, 255, cv.THRESH_BINARY+cv.THRESH_OTSU) #方法選擇為THRESH_OTSU
#4.形態(tài)學操作,閉運算去除孔洞,鏈接細小邊緣
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (10, 10))
bin = cv.morphologyEx(bin, cv.MORPH_CLOSE, kernel)
#4.獲取輪廓
contours, hierarchy=cv.findContours(bin, cv.RETR_TREE,cv.CHAIN_APPROX_NONE)
#5.填充輪廓
len_contour = len(contours)
contour_list = []
mask = np.zeros_like(bin, np.uint8) # 純黑模板
for i in range(len_contour):
cv.drawContours(mask, contours,i,(255,255, 255), -1)
print(mask)
#6.彩色圖片去除黑色蒙版
pic2=cv.bitwise_and(pic1,pic1, mask=mask)
#繪制圖像
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))
axes[0,0].set_title("原圖")
axes[0,0].imshow(pic1[:,:,::-1])
axes[0,1].set_title("二值圖")
axes[0,1].imshow(bin,plt.cm.gray)
axes[1,0].set_title("輪廓合并")
axes[1,0].imshow(mask,plt.cm.gray)
axes[1,1].set_title("彩色圖片去除黑色蒙版")
axes[1,1].imshow(pic2[:,:,::-1])
plt.show()
cv.waitKey()
結果:
大津算法有利于海路分割,屏蔽海洋
自適應閾值算法(復雜顏色地物提取例如打魚船)
1.原理
對分割的小塊進行二值化閾值處理,而不考慮整體圖像,有利于處理光照不均勻的圖像
2.代碼API
dst = cv.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
src:要處理的圖像數(shù)據(jù),為單通道灰度圖像;
maxValue:double類型,二值化后的最大值;
adaptiveMethod:動態(tài)計算閾值的方法,有以下兩種:??? cv.ADAPTIVE_THRESH_MEAN_C:計算區(qū)域內(nèi)的平均值減去C;
??? cv.ADAPTIVE_THRESH_GAUSSIAN_C:計算區(qū)域內(nèi)的高斯均值減去C;thresholdType:二值化類型flags,在該函數(shù)中僅能使用cv.THRESH_BINARY和cv.THRESH_BINARY_INV兩種
blockSize:動態(tài)化計算閾值時所使用的區(qū)域的大小,類似卷積時的卷積核大小,需要為奇數(shù);
C:計算區(qū)域內(nèi)的均值后減去的常量,最后作為閾值;
3.實現(xiàn)
1.
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
#解決中文顯示問題,固定格式
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#1.轉化為灰度圖
pic1=cv.imread("DJI_0023.jpg")
#2.高斯濾波去噪
pic1 = cv.GaussianBlur(pic1, (5,5), 0) # 高斯濾波
gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)
#3.adaptiveThreshold轉換為二值圖
bin=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,5)
#4.形態(tài)學操作,閉運算去除孔洞,鏈接細小邊緣
bin2=255-bin
bin2=cv.medianBlur(bin2,5)#中值去噪
bin2=cv.dilate(bin2,np.ones(20,np.uint8))#膨脹
#5.獲取輪廓
contours, hierarchy=cv.findContours(bin2, cv.RETR_TREE,cv.CHAIN_APPROX_NONE)
#6.填充輪廓
len_contour = len(contours)
contour_list = []
for i in range(len_contour):
area=cv.contourArea(contours[i])
if(area<5000):
contour_list.append(contours[i])
cv.fillPoly(bin2,contour_list,(255,255,255))
#7.腐蝕
bin3=cv.erode(bin2,np.ones(20,np.uint8))#腐蝕
#8.彩色圖片去除黑色蒙版
pic2=cv.bitwise_and(pic1,pic1, mask=bin3)
#繪制圖像
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))
axes[0,0].set_title("原圖")
axes[0,0].imshow(pic1[:,:,::-1])
axes[0,1].set_title("自適應二值圖")
axes[0,1].imshow(bin,plt.cm.gray)
axes[1,0].set_title("人為進一步處理")
axes[1,0].imshow(bin3,plt.cm.gray)
axes[1,1].set_title("腐蝕后彩色圖片去除黑色蒙版")
axes[1,1].imshow(pic2[:,:,::-1])
plt.show()
cv.waitKey()
?第三幅圖靠作者的現(xiàn)階段能力只能處理到這了。。不要嫌棄
?噪聲影響比較嚴重,對于復雜顏色的漁船提取較好
可見自適應二值化,對于邊緣線提取比較有優(yōu)勢,但也提取了不必要的高亮海面部分
2.
如果擴大填充面積,area<50000,“船只”的提取情況更好一些,但相應不必要高亮海面也提取的更多
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
#解決中文顯示問題,固定格式
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#1.轉化為灰度圖
pic1=cv.imread("DJI_0023.jpg")
#2.高斯濾波去噪
pic1 = cv.GaussianBlur(pic1, (5,5), 0) # 高斯濾波
gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)
#3.adaptiveThreshold轉換為二值圖
bin=cv.adaptiveThreshold(gray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,5)
#4.形態(tài)學操作,閉運算去除孔洞,鏈接細小邊緣
bin2=255-bin
bin2=cv.dilate(bin2,np.ones(20,np.uint8))#膨脹
#5.獲取輪廓
contours, hierarchy=cv.findContours(bin2, cv.RETR_TREE,cv.CHAIN_APPROX_NONE)
#6.填充輪廓
len_contour = len(contours)
contour_list = []
# mask = np.zeros_like(bin, np.uint8) # 純黑模板
for i in range(len_contour):
area=cv.contourArea(contours[i])
if(area<50000):
contour_list.append(contours[i])
cv.fillPoly(bin2,contour_list,(255,255,255))
#7.腐蝕
bin3=cv.erode(bin2,np.ones(20,np.uint8))#腐蝕
#8.彩色圖片去除黑色蒙版
pic2=cv.bitwise_and(pic1,pic1, mask=bin3)
#繪制圖像
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))
axes[0,0].set_title("原圖")
axes[0,0].imshow(pic1[:,:,::-1])
axes[0,1].set_title("自適應二值圖")
axes[0,1].imshow(bin,plt.cm.gray)
axes[1,0].set_title("人為進一步處理")
axes[1,0].imshow(bin3,plt.cm.gray)
axes[1,1].set_title("腐蝕后彩色圖片去除黑色蒙版")
axes[1,1].imshow(pic2[:,:,::-1])
plt.show()
cv.waitKey()
?3.自己調參數(shù)改算法步驟吧。累了,陸地提取的一點不好。。。
分水嶺算法
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 解決中文顯示問題,固定格式,直接復制下面?zhèn)z行代碼就行
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def watershed_image(image):
"""分水嶺算法"""
# 圖像二值化
blurred = cv.pyrMeanShiftFiltering(image, 10, 50) # 均值遷移濾波
gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY) # 轉換成灰度圖
# cv.imshow("gray", gray)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU) # 圖像二值化
# cv.imshow("binary", binary)
# 去除噪聲
kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) # 構造25×25的方形結構元素
opening = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel=kernel, iterations=2) # 開操作(需要去除圖像中的任何白點噪聲),迭代次數(shù)2
# cv.imshow("noise removal", opening)
# 確定背景區(qū)域sure_bg
sure_bg = cv.dilate(opening, kernel, iterations=3) # 腐蝕,迭代次數(shù)3,會去除邊界像素
cv.imshow("sure_bg", sure_bg)
# 尋找前景區(qū)域sure_fg
""" 距離變換的基本含義是計算一個圖像中非零像素點到最近的零像素點的距離,也就是到零像素點的最短距離
一個最常見的距離變換算法就是通過連續(xù)的腐蝕操作來實現(xiàn),腐蝕操作的停止條件是所有前景像素都被完全腐蝕。
這樣根據(jù)腐蝕的先后順序,我們就得到各個前景像素點到前景中心像素點的距離。根據(jù)各個像素點的距離值,設置
為不同的灰度值。這樣就完成了二值圖像的距離變換。
cv2.distanceTransform(src, distanceType, maskSize)
distanceType為距離類型CV_DIST_L1, CV_DIST_L2 , CV_DIST_C;maskSize為距離轉換掩碼的大小
"""
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5) # 距離變換
dist_output = cv.normalize(dist_transform, 0, 1.0, cv.NORM_MINMAX) # 矩陣歸一化,主要是為了顯示出dist_output
cv.imshow("dist_transform", dist_output * 50) # dist_output不乘50看不出來
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0) # 圖像二值化
cv.imshow("sure_fg", sure_fg)
# 找到未知的區(qū)域unknown
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg) # 從sure_bg區(qū)域中減去sure_fg區(qū)域來獲得unknown
cv.imshow("unknown", unknown)
# 類別標記
ret, markers1 = cv.connectedComponents(sure_fg)
print(ret) # 計算數(shù)量,但此時會把圖像邊框也算進去,因此ret會多1
# print(markers1)
# 為所有的標記加1,保證背景是0而不是1
markers = markers1 + 1
# print(markers)
# 現(xiàn)在讓所有的未知區(qū)域為0
markers[unknown == 255] = 0
# 使用分水嶺算法
markers3 = cv.watershed(image, markers=markers) # 邊界區(qū)域將被修改標記為-1
image[markers3 == -1] = [0, 0,255] # 邊界區(qū)域畫紅色
#創(chuàng)建黑色蒙版
mask=np.zeros_like(image,np.uint8)
mask[markers3 == -1]=(255,255,255)
mask=cv.dilate(mask,np.ones(20,np.uint8))
# print(markers3)
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10))
axes[0, 0].set_title("邊框")
axes[0, 0].imshow(mask, plt.cm.gray)
axes[0, 1].set_title("原圖")
axes[0, 1].imshow(image[:,:,::-1])
axes[1, 0].set_title("sure_fg")
axes[1, 0].imshow(sure_fg, plt.cm.gray)
axes[1, 1].set_title("sure_bg")
axes[1, 1].imshow(sure_bg, plt.cm.gray)
plt.show()
cv.waitKey()
if __name__=="__main__":
image=cv.imread("DJI_0023.JPG")
watershed_image(image)
文章來源:http://www.zghlxwxcb.cn/news/detail-484116.html
?分水嶺算法提取的邊框比較規(guī)整,但是將頂上一部分水面也提取出來了,還是需要改進文章來源地址http://www.zghlxwxcb.cn/news/detail-484116.html
到了這里,關于[圖像處理]14.分割算法比較 OTSU算法+自適應閾值算法+分水嶺的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!