首頁 > 軟體

Python經典案例之影象漫水填充分割詳解

2023-01-28 18:01:14

一.影象漫水填充

影象漫水填充(FloodFill)是指用一種特定的顏色填充聯通區域,通過設定可連通畫素的上下限以及連通方式來達到不同的填充效果。漫水填充通常被用來標記或分離影象的一部分以便對其進行深入的處理或分析。

影象漫水填充主要是遴選出與種子點聯通且顏色相近的畫素點,接著對畫素點的值進行處理。如果遇到掩碼,則根據掩碼進行處理。其原理類似Photoshop的魔術棒選擇工具,漫水填充將查詢和種子點聯通的顏色相同的點,而魔術棒選擇工具是查詢和種子點聯通的顏色相近的點,將和初始種子畫素顏色相近的點壓進棧作為新種子。基本工作步驟如下:

  • 選定種子點(x,y);
  • 檢查種子點的顏色,如果該點顏色與周圍連線點的顏色不相同,則將周圍點顏色設定為該點顏色;如果相同則不做處理。但是周圍點不一定都會變成和種子點的顏色相同,如果周圍連線點在給定的範圍(從loDiff到upDiff)內或在種子點的畫素範圍內才會改變顏色;
  • 檢測其他連線點,進行第2個步驟的處理,直到沒有連線點,即到達檢測區域邊界停止。

二.影象漫水填充分割實現

在OpenCV中,主要通過floodFill()函數實現漫水填充分割,它將用指定的顏色從種子點開始填充一個連線域。其函數原型如下所示:

floodFill(image, mask, seedPoint, newVal[, loDiff[, upDiff[, flags]]])

– image表示輸入/輸出1通道或3通道,6位或浮點影象

– mask表示操作掩碼,必須為8位元單通道影象,其長寬都比輸入影象大兩個畫素點。注意,漫水填充不會填充掩膜mask的非零畫素區域,mask中與輸入影象(x,y)畫素點相對應的點的座標為(x+1,y+1)。

– seedPoint為Point型別,表示漫水填充演演算法的起始點

– newVal表示畫素點被染色的值,即在重繪區域畫素的新值

– loDiff表示當前觀察畫素值與其部件鄰域畫素值或待加入該部件的種子畫素之間的亮度或顏色之負差的最大值,預設值為Scalar( )

– upDiff表示當前觀察畫素值與其部件鄰域畫素值或待加入該部件的種子畫素之間的亮度或顏色之正差的最大值,預設值為Scalar( )

– flags表示操作識別符號,此引數包括三個部分:低八位0-7bit表示鄰接性(4鄰接或8鄰接);中間八位8-15bit表示掩碼的填充顏色,如果中間八位為0則掩碼用1來填充;高八位16-31bit表示填充模式,可以為0或者以下兩種標誌符的組合,FLOODFILL_FIXED_RANGE表示此標誌會考慮當前畫素與種子畫素之間的差,否則就考慮當前畫素與相鄰畫素的差。FLOODFILL_MASK_ONLY表示函數不會去填充改變原始影象,而是去填充掩碼影象mask,mask指定的位置為零時才填充,不為零不填充。

在Python和OpenCV實現程式碼中,它設定種子點位置為(10,200);設定顏色為黃色(0,255,255);連通區範圍設定為loDiff和upDiff;標記引數設定為CV_FLOODFILL_FIXED_RANGE ,它表示待處理的畫素點與種子點作比較,在範圍之內,則填充此畫素,即種子漫水填充滿足:

src(seed.x, seed.y) - loDiff <= src(x, y) <= src(seed.x, seed.y) +upDiff

完整程式碼如下:

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

#讀取原始影象
img = cv2.imread('windows.png')

#獲取影象行和列
rows, cols = img.shape[:2]

#目標影象
dst = img.copy()

#mask必須行和列都加2且必須為uint8單通道陣列
#mask多出來的2可以保證掃描的邊界上的畫素都會被處理
mask = np.zeros([rows+2, cols+2], np.uint8)  

#影象漫水填充處理
#種子點位置(30,30) 設定顏色(0,255,255) 連通區範圍設定loDiff upDiff
#src(seed.x, seed.y) - loDiff <= src(x, y) <= src(seed.x, seed.y) +upDiff
cv2.floodFill(dst, mask, (30, 30), (0, 255, 255),
              (100, 100, 100), (50, 50, 50),
              cv2.FLOODFILL_FIXED_RANGE)

#顯示影象
cv2.imshow('src', img)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

輸出結果如圖1所示,左邊為原始影象,右邊為將Windows圖示周圍填充為黃色的影象。

三.影象漫水填充分割自動軟體

下面補充另一段程式碼,它將開啟一幅影象,點選滑鼠選擇種子節點,移動卷軸設定連通區範圍的loDiff和upDiff值,併產生動態的漫水填充分割。

注意,該部分程式碼中涉及滑鼠、鍵盤、卷軸等操作,希望讀者下來學習相關知識,該系列文章更多是講解Python影象處理的演演算法原理及程式碼實現。

# coding:utf-8
import cv2
import random
import sys
import numpy as np

#使用說明 點選滑鼠選擇種子點
help_message = '''USAGE: floodfill.py [<image>]
Click on the image to set seed point
Keys:
  f - toggle floating range
  c - toggle 4/8 connectivity
  ESC - exit
'''
 
if __name__ == '__main__':

    #輸出提示文字
    print(help_message)

    #讀取原始影象
    img = cv2.imread('scenery.png')

    #獲取影象高和寬
    h, w = img.shape[:2]

    #設定掩碼 長和寬都比輸入影象多兩個畫素點 
    mask = np.zeros((h+2, w+2), np.uint8)

    #設定種子節點和4鄰接
    seed_pt = None
    fixed_range = True
    connectivity = 4 

    #影象漫水填充分割更新函數
    def update(dummy=None):
        if seed_pt is None:
            cv2.imshow('floodfill', img)
            return
        
        #建立影象副本並漫水填充
        flooded = img.copy()
        mask[:] = 0 #掩碼初始為全0
        lo = cv2.getTrackbarPos('lo', 'floodfill') #畫素鄰域負差最大值
        hi = cv2.getTrackbarPos('hi', 'floodfill') #畫素鄰域正差最大值
        print('lo=', lo, 'hi=', hi)

        #低位位元包含連通值 4 (預設) 或 8
        flags = connectivity
        
        #考慮當前畫素與種子畫素之間的差(高位元也可以為0)
        if fixed_range:
            flags |= cv2.FLOODFILL_FIXED_RANGE
            
        #以白色進行漫水填充
        cv2.floodFill(flooded, mask, seed_pt,
                      (random.randint(0,255), random.randint(0,255),
                       random.randint(0,255)), (lo,)*3, (hi,)*3, flags)

        #選定基準點用紅色圓點標出
        cv2.circle(flooded, seed_pt, 2, (0, 0, 255), -1)
        print("send_pt=", seed_pt)

        #顯示影象
        cv2.imshow('floodfill', flooded)

    #滑鼠響應函數
    def onmouse(event, x, y, flags, param):
        global seed_pt #基準點

        #滑鼠左鍵響應選擇漫水填充基準點
        if flags & cv2.EVENT_FLAG_LBUTTON:
            seed_pt = x, y
            update()

    #執行影象漫水填充分割更新操作
    update()
    
    #滑鼠更新操作
    cv2.setMouseCallback('floodfill', onmouse)

    #設定進度條
    cv2.createTrackbar('lo', 'floodfill', 20, 255, update)
    cv2.createTrackbar('hi', 'floodfill', 20, 255, update)

    #按鍵響應操作
    while True:
        ch = 0xFF & cv2.waitKey()
        #退出
        if ch == 27:
            break
        #選定時flags的高位位元位0
        #鄰域的選定為當前畫素與相鄰畫素的差, 聯通區域會很大
        if ch == ord('f'):
            fixed_range = not fixed_range 
            print('using %s range' % ('floating', 'fixed')[fixed_range])
            update()
        #選擇4方向或則8方向種子擴散
        if ch == ord('c'):
            connectivity = 12-connectivity 
            print('connectivity =', connectivity)
            update()
    cv2.destroyAllWindows()

當滑鼠選定的種子點為(242,96),觀察點畫素鄰域負差最大值“lo”為138,觀察點畫素鄰域正差最大值“hi”為147時,影象漫水填充效果如圖2所示,它將天空和中心水面填充成黃色。

當滑鼠選定的種子點為(328, 202),觀察點畫素鄰域負差最大值“lo”為142,觀察點畫素鄰域正差最大值“hi”為45時,影象漫水填充效果如圖3所示,它將影象兩旁的森林和水面填充成藍紫色。

四.總結

寫到這裡,影象分割知識點就介紹完畢,包括基於閾值的影象分割方法、基於邊緣檢測的影象分割方法、基於紋理背景的影象分割方法和基於特定理論的影象分割方法。其中,基於特定理論的分割方法又分別講解了基於K-Means聚類、均值漂移、分水嶺演演算法的影象分割方法。最後通過漫水填充分割案例加深了讀者的印象。希望讀者能結合本章知識點,圍繞自己的研究領域或工程專案進行深入的學習,實現所需的影象處理。

以上就是Python經典案例之影象漫水填充分割詳解的詳細內容,更多關於Python影象漫水填充分割的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com