Python圖像分割之區域增長法


  原文鏈接:https://blog.csdn.net/sgzqc/article/details/119682864

一、簡介

  區域增長法是一種已受到計算機視覺界十分關注的圖像分割方法。它是以區域為處理對象的,它考慮到區域內部和區域之間的同異性,盡量保持區域中像素的臨近性和一致性的統一。這樣就可以更好地分辨圖像真正的邊界。

  基於區域的分割方法的關鍵在於定義一個一致性准則,用來判斷兩個鄰接的區域是否可以合並,一致則將兩區域合並,直到不能合並為止。區域增長的方法是在圖像上選定一個種子點,記錄下該點的灰度值,作為一致性判斷的標准閾值,此外還需要定義一個標准差。
算法的主要過程是,依次用圖像的每一個像素的灰度值和標准閾值相減,判斷結果是否小於標准差,是則將該點和種子點合並,不是則保持像素點的灰度值不變。這樣處理后的圖像就是用區域分割法處理后的邊緣分割圖像。

二、實例

下面我們通過一個例子來進行詳細的解釋

  上圖示意的是區域增長的過程,圖中的方格表示圖像的像素點,方格中的數值表示像素點的灰度值。(a)表示開始選取的生長點,在生長的過程中,每個生長點都將本身上下左右4個像素點和初試選取的生長點比較灰度值,如果灰度值的差的絕對值在設定的閾值內,則認為這些點是屬於相同區域並將其合並,否則將灰度差大於設定閾值的點刪除,重復檢查區域內的像素點,直到沒有像素點可以合並位置。不妨設上圖的閾值為2,(b)中4個點和初始點的灰度差都不大於2,所以合並;(c)中只有部分滿足條件,所以只合並滿足條件的像素點,並且(c)區域周圍鄰域中沒有點再滿足條件,因此生長結束。

三、算法步驟

通過上述示例,我們可以總結出區域增長法的一般步驟如下:
1)對圖像自上而下,自左而右掃描,找到第1個還沒有訪問過的像素, 設該像素為(x0, y0);
2)以(x0, y0)為中心, 考慮(x0, y0)的8鄰域像素(x, y),如果其鄰域滿足生長准則, 將(x, y)與(x0, y0)合並(在同一區域內), 同時將(x, y)壓入堆棧;
3)從堆棧中取出一個像素, 把它當作(x0, y0)返回到上一步驟;
4)當堆棧為空時 返回到步驟1;
5)重復步驟1 - 4直到圖像中的每個點都被訪問過時,算法結束。

四、代碼實現

1 讀入彩色圖像

img_name = "test.jpg"
img = cv2.imread(img_name)

結果如下:

2 灰度化

gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

結果如下:

3 二值化

def get_binary_img(img):
    # gray img to bin image
    bin_img = np.zeros(shape=(img.shape), dtype=np.uint8)
    h = img.shape[0]
    w = img.shape[1]
    for i in range(h):
        for j in range(w):
            bin_img[i][j] = 255 if img[i][j] > 127 else 0
    return bin_img
# 調用
bin_img = get_binary_img(gray_img)

結果如下:

4 選取初始種子點

  這里選擇三個種子點作為初始點,種子點的坐標如下圖紫色十字所示。

out_img = np.zeros(shape=(bin_img.shape), dtype=np.uint8)
# 選擇初始3個種子點
seeds = [(176,255),(229,405),(347,165)]
for seed in seeds:
    x = seed[0]
    y = seed[1]
    out_img[y][x] = 255

5 區域增長結果

# 8 鄰域
directs = [(-1,-1), (0,-1), (1,-1), (1,0), (1,1), (0,1),(-1,1),(-1,0)]
visited = np.zeros(shape=(bin_img.shape), dtype=np.uint8)
while len(seeds):
    seed = seeds.pop(0)# 將元素從列表中刪彈出,默認最后一個
    x = seed[0]
    y = seed[1]
    # visit point (x,y)
    visited[y][x] = 1
    for direct in directs:
        cur_x = x + direct[0]
        cur_y = y + direct[1]
        # 非法
        if cur_x <0 or cur_y<0 or cur_x >= w or cur_y >=h :
            continue
        # 沒有訪問過且屬於同一目標
        if (not visited[cur_y][cur_x]) and (bin_img[cur_y][cur_x]==bin_img[y][x]) :
            out_img[cur_y][cur_x] = 255
            visited[cur_y][cur_x] = 1
            seeds.append((cur_x,cur_y))

結果如下:

6 獲取目標

  以上步得到的二值圖作為mask,去彩色圖中取對應的部分即可。代碼如下:

bake_img = img.copy()
h = bake_img.shape[0]
w = bake_img.shape[1]
for i in range(h):
    for j in range(w):
        if out_img[i][j] != 255:
            bake_img[i][j][0] = 0
            bake_img[i][j][1] = 0
            bake_img[i][j][2] = 0

結果如下:

7 完整代碼

通過區域增長法來提取前景目標

# -*- coding:utf-8 -*-
import cv2
import numpy as np

def get_binary_img(img):
    # gray img to bin image
    bin_img = np.zeros(shape=(img.shape), dtype=np.uint8)
    h = img.shape[0]
    w = img.shape[1]
    for i in range(h):
        for j in range(w):
            bin_img[i][j] = 255 if img[i][j] > 80 else 0
    return bin_img
img_name = "test.jpg"
img = cv2.imread(img_name)
h = img.shape[0]
w = img.shape[1]
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 調用
bin_img = get_binary_img(gray_img)
out_img = np.zeros(shape=(bin_img.shape), dtype=np.uint8)
# 選擇初始3個種子點
seeds = [(176,255),(229,205),(307,165)]
for seed in seeds:
    x = seed[0]
    y = seed[1]
    out_img[y][x] = 255
# 8 鄰域
directs = [(-1,-1), (0,-1), (1,-1), (1,0), (1,1), (0,1),(-1,1),(-1,0)]
visited = np.zeros(shape=(bin_img.shape), dtype=np.uint8)
while len(seeds):
    seed = seeds.pop(0)
    x = seed[0]
    y = seed[1]
    # visit point (x,y)
    visited[y][x] = 1
    for direct in directs:
        cur_x = x + direct[0]
        cur_y = y + direct[1]
        # 非法
        if cur_x <0 or cur_y<0 or cur_x >= w or cur_y >=h :
            continue
        # 沒有訪問過且屬於同一目標
        if (not visited[cur_y][cur_x]) and (bin_img[cur_y][cur_x]==bin_img[y][x]) :
            out_img[cur_y][cur_x] = 255
            visited[cur_y][cur_x] = 1
            seeds.append((cur_x,cur_y))
bake_img = img.copy()
h = bake_img.shape[0]
w = bake_img.shape[1]
for i in range(h):
    for j in range(w):
        if out_img[i][j] != 255:
            bake_img[i][j][0] = 0
            bake_img[i][j][1] = 0
            bake_img[i][j][2] = 0

cv2.imshow('image',img)
cv2.imshow('rowgrow',bake_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

通過設置閾值來控制生長條件

# -*- coding:utf-8 -*-
import cv2
import numpy as np

def get_binary_img(img):
    # gray img to bin image
    bin_img = np.zeros(shape=(img.shape), dtype=np.uint8)
    h = img.shape[0]
    w = img.shape[1]
    for i in range(h):
        for j in range(w):
            bin_img[i][j] = 255 if img[i][j] > 150 else 0
    return bin_img
img_name = "test.jpg"
img = cv2.imread(img_name)
h = img.shape[0]
w = img.shape[1]
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
print(gray_img )

# 調用
# bin_img = get_binary_img(gray_img)
out_img = np.zeros(shape=(gray_img.shape), dtype=np.uint8)
# 選擇初始3個種子點
seeds = [(276,155)]
for seed in seeds:
    x = seed[0]
    y = seed[1]
    out_img[y][x] = 255
# 8 鄰域
directs = [(-1,-1), (0,-1), (1,-1), (1,0), (1,1), (0,1),(-1,1),(-1,0)]
visited = np.zeros(shape=(gray_img.shape), dtype=np.uint8)
while len(seeds):
    seed = seeds.pop(0)
    x = seed[0]
    y = seed[1]
    # visit point (x,y)
    visited[y][x] = 1
    for direct in directs:
        cur_x = x + direct[0]
        cur_y = y + direct[1]
        # 非法
        if cur_x <0 or cur_y<0 or cur_x >= w or cur_y >=h :
            continue
        # 沒有訪問過且屬於同一目標
        if (not visited[cur_y][cur_x]) and (abs(int(gray_img[cur_y][cur_x])-int(gray_img[y][x]))<5.0) :
            out_img[cur_y][cur_x] = 255
            visited[cur_y][cur_x] = 1
            seeds.append((cur_x,cur_y))
bake_img = img.copy()
h = bake_img.shape[0]
w = bake_img.shape[1]
for i in range(h):
    for j in range(w):
        if out_img[i][j] != 255:
            bake_img[i][j][0] = 0
            bake_img[i][j][1] = 0
            bake_img[i][j][2] = 0

cv2.imshow('rowgrow',bake_img)
cv2.waitKey(0)
cv2.destroyAllWindows()


免責聲明!

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



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