Python實(shí)現(xiàn)連通域標(biāo)記算法
問(wèn)題引入
通俗地說(shuō),如果把圖像分為前景和背景兩部分,那么連通域就是連通在一起的前景,這種關(guān)系對(duì)于二值圖像來(lái)說(shuō)比較明顯。
以下面的硬幣圖像,在二值化之后,可以很明顯看到,圖像被分為黑色和白色兩個(gè)部分,若以白色為背景,則黑色被白色隔開(kāi),彼此之間并不聯(lián)通。連通域標(biāo)記的目的,就是為不連通的這些黑色區(qū)域,標(biāo)上不同的序號(hào)。
其繪圖代碼如下,其中climb是此前實(shí)現(xiàn)的自動(dòng)ostu閾值算法,參考這篇:OTSU算法及其Python實(shí)現(xiàn)
import matplotlib.pyplot as plt import numpy as np path = r"coin.png" img = plt.imread(path).astype(float) img = np.mean(img, axis=2) th = 0.513 # climb(img, 0.1, 0, 0.01) b = img>th def drawImg(im1, im2, c1='gray', c2='gray'): fig = plt.figure() ax = fig.add_subplot(121) plt.imshow(im1, cmap=c1) plt.axis('off') ax = fig.add_subplot(122) plt.imshow(im2, cmap=c2) plt.axis('off') plt.show() drawImg(img, b)
實(shí)現(xiàn)
常用的連通域標(biāo)記算法是Two-Pass算法,顧名思義,就是迭代兩次,第一次用于記錄相鄰像素的連通域關(guān)系,第二次則把相連通的區(qū)域置以相同的標(biāo)簽。
在遍歷之前,先初始化一個(gè)編號(hào)矩陣,考慮到Python提供了字典這種數(shù)據(jù)類型,所以第一次遍歷,將關(guān)聯(lián)相鄰像素的編號(hào)。比如,點(diǎn)P12的編號(hào)是3,點(diǎn)P22的編號(hào)是4,而且二者均為目標(biāo),則將產(chǎn)生一組鍵值對(duì){3:4}。
下面就是這個(gè)字典的創(chuàng)建過(guò)程,由于在遍歷過(guò)程中,每個(gè)像素點(diǎn)要和它左側(cè)和上方的像素點(diǎn)進(jìn)行比較,所以這個(gè)字典的值應(yīng)該是一個(gè)列表。
from itertools import product def getIndDct(img): # 元素個(gè)數(shù) m,n = img.shape # 編號(hào)矩陣 indMat = np.arange(m*n).reshape([m,n]) dct = {} for i,j in product(range(m), range(n)): if img[i,j] == 0: continue ind = indMat[i,j] dct[ind] = [] if i>1 and img[i-1,j]!=0: dct[ind].append(indMat[i-1,j]) if i+1<m and img[i+1, j]!=0: dct[ind].append(indMat[i+1,j]) if j > 1 and img[i,j-1]!=0: dct[ind].append(indMat[i, j-1]) if j+1 < n and img[i, j+1] != 0: dct[ind].append(indMat[i, j+1]) return dct
在得到編號(hào)映射字典之后,需要將其歸一化,就是把類似a:[b,c]和]c:[d,e]合并為a:[b,c,d,e]。當(dāng)所有編號(hào)都已經(jīng)歸類之后,還可以繼續(xù)將其變?yōu)閇a,b,c,d,e]實(shí)現(xiàn)如下
from copy import deepcopy def mergeKey(dct, key): keys = [key] st, ed = 0, 1 while len(keys)>0: for i in range(st, ed): k = keys[i] if k in dct: keys += dct[k] del dct[k] if ed == len(keys): break st, ed = ed, len(keys) return keys def uniqueDct(dct): uDct = deepcopy(dct) for k in dct: if k in uDct: uDct[k] = list(set(mergeKey(uDct, k))) return [list(set([k]+v)) for k,v in uDct.items()]
最后,將其重新賦值,由于編號(hào)矩陣是按照自然數(shù)列的順序創(chuàng)建的,故而只需先把圖像展平,就可以通過(guò)編號(hào)矩陣的索引直接對(duì)圖像的某些區(qū)域重新賦值。
def cds(img): dct = getIndDct(img) lst = uniqueDct(dct) arr = img.reshape(-1)*0 for i,L in enumerate(lst, 1): arr[L] = i return arr.reshape(img.shape)
測(cè)試
接下來(lái),將這個(gè)連通域算法應(yīng)用到硬幣圖像上,由于上面的硬幣圖案有很多噪聲,會(huì)影響連通域計(jì)算結(jié)果,所以先對(duì)其進(jìn)行預(yù)處理
from scipy.ndimage import binary_erosion b = img>0.4 bb = binary_erosion(b, np.ones([5,5])) c = cds(bb) drawImg(img, c, 'gray', 'jet')
效果如下
到此這篇關(guān)于Python實(shí)現(xiàn)連通域標(biāo)記算法的文章就介紹到這了,更多相關(guān)Python連通域標(biāo)記內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python2.7簡(jiǎn)單連接與操作MySQL的方法
這篇文章主要介紹了Python2.7簡(jiǎn)單連接與操作MySQL的方法,涉及Python使用MySQLdb模塊操作MySQL連接及命令運(yùn)行的相關(guān)技巧,需要的朋友可以參考下2016-04-04Python(TensorFlow框架)實(shí)現(xiàn)手寫(xiě)數(shù)字識(shí)別系統(tǒng)的方法
這篇文章主要介紹了Python(TensorFlow框架)實(shí)現(xiàn)手寫(xiě)數(shù)字識(shí)別系統(tǒng)的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05如何利用Matplotlib庫(kù)繪制動(dòng)畫(huà)及保存GIF圖片
這篇文章主要給大家介紹了關(guān)于如何利用Matplotlib庫(kù)繪制動(dòng)畫(huà)及保存GIF圖片的相關(guān)資料,matplotlib模塊提供了很高級(jí)和非常友好的使用方式,使用起來(lái)也是非常方便的,需要的朋友可以參考下2021-06-06Python中Django框架利用url來(lái)控制登錄的方法
這篇文章主要介紹了Python中Django框架利用url來(lái)控制登錄的方法,實(shí)例分析了Django框架實(shí)現(xiàn)URL登陸的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07Django創(chuàng)建一個(gè)后臺(tái)的基本步驟記錄
這篇文章主要給大家介紹了關(guān)于Django創(chuàng)建一個(gè)后臺(tái)的基本步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10python爬蟲(chóng)Scrapy框架:媒體管道原理學(xué)習(xí)分析
這篇文章主要介紹了python爬蟲(chóng)Scrapy框架:媒體管道原理學(xué)習(xí)分析,有需要的朋友可以借鑒參考,希望可以對(duì)廣大一同學(xué)習(xí)的讀者朋友有所幫助2021-09-09只需7行Python代碼玩轉(zhuǎn)微信自動(dòng)聊天
今天小編就為大家分享一篇關(guān)于只需7行Python代碼玩轉(zhuǎn)微信自動(dòng)聊天,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01