python實現分水嶺算法分割遙感圖像


1. 定義

  分水嶺算法(watershed algorithm)可以將圖像中的邊緣轉化為“山脈”,將均勻區域轉化為“山谷”,在這方面有助於分割目標。
  分水嶺算法:是一種基於拓撲理論的數學形態學的分割方法。把圖像看作是測地學上的拓撲地貌,圖像中的每一個點像素值的灰度值表示該點的海拔高度,每一個局部極小值及其影響的區域稱為“集水盆”,集水盆的邊界可以看成分水嶺。在每一個局部極小值表面刺穿一個小孔,然后把整個模型慢慢浸入水中,隨着浸入的加深,每一個局部極小值的影響域慢慢的向外擴展,在兩個集水盆匯合處構建大壩,形成分水嶺。

迭代標注過程:

  1. 排序過程:對每個像素的灰度級進行從低到高的排序
  2. 淹沒過程:對每一個局部最小值在h階高度的影響域采用先進先出結構判斷及標注。

2.實現算法:watershed()函數

  這些標記的值可以使用findContours()函數和drawContours()函數由二進制的掩模檢索出來

3.程序代碼:

import numpy as np
import cv2
from osgeo import gdal, gdal_array
import shapefile
try:
    import Image
    import ImageDraw
except:
    from PIL import Image, ImageDraw

def tif_jpg(rasterfile):
    in_ds = gdal.Open(rasterfile)  # 打開樣本文件
    xsize = in_ds.RasterXSize  # 獲取行列數
    ysize = in_ds.RasterYSize
    bands = in_ds.RasterCount
    block_data = in_ds.ReadAsArray(0, 0, xsize, ysize).astype(np.float32)
    B = block_data[0, :, :]

    G = block_data[ 1,:, :]
    R = block_data[2,:, :]
    R1 =  (R/np.max(R)*255).astype(np.int16)
    G1 = (G / np.max(G) * 255).astype(np.int16)
    B1 = (B / np.max(B) * 255).astype(np.int16)
    data2 = cv2.merge([R1,G1,B1])
    return data2


def watershed(path,out):
    print("分水嶺分割")
    in_ds = gdal.Open(path)  # 打開樣本文件
    xsize = in_ds.RasterXSize  # 獲取行列數
    ysize = in_ds.RasterYSize
    bands = in_ds.RasterCount
    geotransform = in_ds.GetGeoTransform()
    projection = in_ds.GetProjectionRef()
    #tif轉jpg     非255通道轉換為255通道
    img=tif_jpg(path).astype(np.uint8)
    # 轉換為灰度圖片
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # canny邊緣檢測 函數返回一副二值圖,其中包含檢測出的邊緣。
    canny = cv2.Canny(gray_img, 80,120)
    # 尋找圖像輪廓 返回修改后的圖像 圖像的輪廓  以及它們的層次
    # canny, contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    contours, hierarchy = cv2.findContours(canny, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # 32位有符號整數類型,
    marks = np.zeros(img.shape[:2], np.int32)
    # findContours檢測到的輪廓
    imageContours = np.zeros(img.shape[:2], np.uint8)
    # 輪廓顏色
    compCount = 0
    index = 0
    # 繪制每一個輪廓
    for index in range(len(contours)):
        # 對marks進行標記,對不同區域的輪廓使用不同的亮度繪制,相當於設置注水點,有多少個輪廓,就有多少個輪廓
        # 圖像上不同線條的灰度值是不同的,底部略暗,越往上灰度越高
        marks = cv2.drawContours(marks, contours, index, (index, index, index), 1, 8, hierarchy)
        # 繪制輪廓,亮度一樣
        imageContours = cv2.drawContours(imageContours, contours, index, (255, 255, 255), 1, 8, hierarchy)
    # 查看 使用線性變換轉換輸入數組元素成8位無符號整型。
    markerShows = cv2.convertScaleAbs(marks)
    # cv2.imshow('imageContours',imageContours)
    # 使用分水嶺算法
    marks = cv2.watershed(img, marks)
    driver = gdal.GetDriverByName('GTiff')
    outfile_lake = out + "\\" + "watershed_cut.tif"
    out_dataset = driver.Create(outfile_lake, xsize, ysize, 1, gdal.GDT_Float32)
    out_band1 = out_dataset.GetRasterBand(1)
    out_band1.WriteArray(marks)
    out_dataset.SetGeoTransform(geotransform)  # 寫入仿射變換
    out_dataset.SetProjection(projection)
    return outfile_lake

if __name__ == "__main__":
    path = r"D:\data\實驗數據\fenlei2.tif"
    out = r"D:\data\實驗結果\分割結果"
    watershed(path, out)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM