two-pass是一种找连通域的算法,只要对图做两次遍历,就能够对相同连通域内的点打上相同的label。
该图为4-邻域上的two-pass
第一遍:
对每个点打上
min(labeln(x,y))
,即其邻域中点的最小的label;如果发现邻域中出现了不同的label,把这些label放到并一个集合
Si
中去,即使得同一个连通域
Ci
的label在同一个集合,
label(x,y)∈Si,(x,y)∈Ci
。
第二遍:
对每个点的label进行更新,更新为其对于其集合中最小的label,
label(x,y)=min(Si),(x,y)∈Ci
。
two-pass就做完了。看看效果吧。
原图:
two-pass 加随机染色 去除小于100的连通块
集合的维护采用了并查集,让同一个连通域中的label的父亲都指向集合中最小的label,然后用并查集更新每个像素的label,这样就使得所有像素的label为集合中最小的label了。
python实现:
#find father and update
def find_fa(x):
global count,fa,cc
fx = fa[x]
if fa[fx] == fx:#if father has no father, no more search
return fx
else:#update x's father
fa[x] = find_fa(fx)
return fa[x]
def two_pass(img, mask=255, area=100):
#init merge and find set
global count,fa,cc
fa = range(img.shape[0]*img.shape[1]) #father node
cc = np.zeros(img.shape[0]*img.shape[1]) #count connected components area of fa[]
cc = cc+1
dx = [0,0,-1,1,-1,-1,1,1]
dy = [-1,1,0,0,-1,1,-1,1]
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if img[i,j] == mask:
for dir in range(8):
nx = dx[dir] + i
ny = dy[dir] + j
if nx >= 0 and nx < img.shape[0] and ny >= 0 and ny < img.shape[1] and img[nx,ny] == mask:
a = i*img.shape[1]+j
b = nx*img.shape[1]+ny
pa = find_fa(a)#shorten chain
pb = find_fa(b)#
#merge father
if pa<pb:
fa[pb]=pa
cc[pa]+=cc[pb]
cc[pb]=0
elif pa>pb:
fa[pa]=pb
cc[pb]+=cc[pa]
cc[pa]=0
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if img[i,j] == mask:
a = i*img.shape[1]+j
find_fa(a)
count = 0
colormap = np.zeros((img.shape[0],img.shape[1],3))#color hash table
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if img[i,j] == mask:
a = i*img.shape[1]+j
pa = find_fa(a)
if cc[pa] >= 100: # connected components with area >= 100 pixels
pa_i = pa / img.shape[1]
pa_j = pa % img.shape[1]
if np.max(colormap[pa_i,pa_j,:]) == 0:
colormap[pa_i,pa_j,:] = np.random.randint(256,size=3)
count += 1
colormap[i,j,:] = colormap[pa_i,pa_j,:]
print count
return colormap
方法调用:
des = two_pass(src,255,100)
255是白色的意思,100是连通区域阈值大小。