python 代码实现二值图像连通域查找

本文介绍了两种二值图像连通域查找的方法:Two-Pass算法和Seed-Filling算法。通过Python实现,并提供了相关代码示例。利用skimage或opencv库也可完成,但作者更倾向于自定义实现以便于业务调整。

通常来说有两种方法,Two-Pass算法和Seed-Filling算法。前者是通过遍历两次图像,将图像中存在的所有联通区域找出来并标记;后者是源于计算机图形学对于某个图形进行填充,其思路是区域生长算法。想了解更具体的原理自己去搜资料吧,我懒。其实现在skimage或者opencv库都有相应的封装函数,但是一向喜欢造轮子的我喜欢手撕,最重要的,我可以根据业务需要随时进行改动源码。废话不多说,上源码,我知道这就是你们来csdn的原因。。。代码只是基本的思路实现,加速啥的自己做吧。

import cv2
import numpy as np
import sys
import matplotlib.pyplot as plt

N_hoods_4=True
N_hoods_8=False   #尽可能少定义全局变量,在python里会让代码速度变慢;固定参数较多,可以考虑写成config文件导入使用;
OFFSETS_4=[[0,-1],[0,0],[1,0],[0,1]]
OFFSETS_8=[[-1,-1],[0,-1],[1,-1],
           [-1,0],[0,0],[1,0],
           [-1,1],[0,1],[1,1]]

def Research(img:np.array):
    index_List=[]
    points_List=[]
    index=-1
    assert(img.shape[2]==1)
    h,w=img.shape
    for i in range(h):
        for j in range(w):   #使用for循环比while要高效
            pixel=img[i][j]
            if pixel<0.5:
                continue
            if pixel in index_List:
                index=index_List.index(pixel)
                num=index+1
            else:
                index_Lenght=len(index_List)
                num=index+1
                index_List.append(pixel)
                points_List.append([])
            img[i][j]=num
            points_List[index].append([i,j])
    return img,points_List

def neighbor_value(img:np.array,offsets,flag=False):
    assert(img.shape[2]==1)
    h,w=img.shape
    label_id=0
    new_rows=[0,h,1] if flag==False else [h-1,-1,-1]
    new_cols=[0,w,1] if flag==False else [w-1,-1,-1]
    threshold=0.5
    for i in range(new_rows[0],new_rows[1],new_rows[2]):
        for j in range(new_cols[0],new_cols[1],new_cols[2]):
            label=255
            if img[i][j]<threshold:
                continue
            for offset in offsets:
                nh_row=min(max(0,i+offset[0]),h-1)
                nh_col=min(max(0,j+offset[1]),w-1)
                nh_value=img[nh_row,nh_col]
                if nh_value<threshold:
                    continue
                label=nh_value if nh_value<label else label
            if label==255:
                label_id+=1
                label=label_id
            img[i][j]=label
    return img

def TwoPass(img:np.array,nh_matrix):
    if nh_matrix==N_hoods_4:
        offsets=OFFSETS_4
    elif nh_matrix==N_hoods_8:
        offsets=OFFSETS_8
    else:
        sys.stderr.write("error in TwoPass!\n")
    img=neighbor_value(img,offsets,False)
    img=neighbor_value(img,offsets,True)
    return img

def recursive_seed(img:np.array,row,col,offsets,Num,max_num):  
    assert(img.shape[2]==1)
    h,w=img.shap
    img[row][col]=Num
    for offset in offsets:
        nh_row=min(max(0,row+offset[0]),h-1)
        nh_col=min(max(0,col+offset[1]),w-1)
        var=img[nh_row][nh_col]
        if var<max_num:
            continue
        img=recursive_seed(img,nh_row,nh_col,offsets,max_num)
    return img
    
def Seed_filling(img:np.array,nh_matrix,max_num=100):
    if nh_matrix==N_hoods_4:
        offsets=OFFSETS_4
    elif nh_matrix==N_hoods_8:
        offsets=OFFSETS_8
    else:
        sys.stderr.write("error in Seed_filling!\n")
    num=1
    assert(img.shape[2]==1)
    h,w=img.shap
    for i in range(h):
        for j in range(w):
            pixel=img[i][j]
            if pixel<=max_num:
                continue
            img=recursive_seed(img,h,w,offsets,num,max_num)
            num+=1
    return img

if __name__ == "__main__":    #使用例子
    imgPath="demo.png"
    img=cv2.imread(imgPath,0)
    fig, ax1 = plt.subplots(nrows=1, ncols=1, figsize=(10, 10))
    ax1.imshow(img, cmap=plt.cm.gray)
    ax1.axis('off')      
    ax1.set_title('rawdata', fontsize=20)
    fig.tight_layout()
    plt.show()
    mode=0
    if mode==0:
        binary_img=TwoPass(img,OFFSETS_8)
        binary_img,P=Research(binary_img)
    elif mode==1:
        binary_img=Seed_filling(img,OFFSETS_8)
        binary_img,P=Research(binary_img)
    print(binary_img," ",P)

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值