一、感谢:

向博主GlassySky0816致谢,参考其编辑书写的区域生长算法的python实现进行学习。
 

二、程序理解

2.1程序分析

import cv2
import numpy as np
 
class Point(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y
 
    def getX(self):
        return self.x
    def getY(self):
        return self.y
#计算像素之间的偏差 
def getGrayDiff(img,currentPoint,tmpPoint):
    return abs(int(img[currentPoint.x,currentPoint.y]) - int(img[tmpPoint.x,tmpPoint.y]))
 
#设定八邻域或四邻域(我对原程序进行改动,只选择了八邻域)    
#def selectConnects(p):
def selectConnects():
    #if p != 0:
    connects = [Point(-1, -1), Point(0, -1), Point(1, -1), Point(1, 0), Point(1, 1), \
                    Point(0, 1), Point(-1, 1), Point(-1, 0)]#八邻域
    #else:
        #connects = [ Point(0, -1),  Point(1, 0),Point(0, 1), Point(-1, 0)]#四邻域
    return connects
#生长函数 
def regionGrow(img,seeds,thresh,p = 1):
    #读取图像的宽高,并建立一个和原图大小相同的seedMark
    height, weight = img.shape
    seedMark = np.zeros(img.shape)
    #将定义的种子点放入种子点序列seedList
    seedList = []
    for seed in seeds:
        seedList.append(seed)
    label = 1
    #选择邻域,我更改程序默认8邻域
    #connects = selectConnects(p)
    connects = selectConnects()
    #逐个点开始生长,生长的结束条件为种子序列为空,即没有生长点
    while(len(seedList)>0):
        #弹出种子点序列的第一个点作为生长点
        currentPoint = seedList.pop(0)#弹出第一个元素
        #并将生长点对应seedMark点赋值label(1),即为白色
        seedMark[currentPoint.x,currentPoint.y] = label
        #以种子点为中心,八邻域的像素进行比较
        for i in range(8):
            tmpX = currentPoint.x + connects[i].x
            tmpY = currentPoint.y + connects[i].y
            #判断是否为图像外的点,若是则跳过。  如果种子点是图像的边界点,邻域点就会落在图像外
            if tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >= weight:
                continue
            #判断邻域点和种子点的差值
            grayDiff = getGrayDiff(img,currentPoint,Point(tmpX,tmpY))
            #如果邻域点和种子点的差值小于阈值并且是没有被分类的点,则认为是和种子点同类,赋值label,
            #并作为下一个种子点放入seedList
            if grayDiff < thresh and seedMark[tmpX,tmpY] == 0:
                seedMark[tmpX,tmpY] = label
                seedList.append(Point(tmpX,tmpY))
    return seedMark
 
#读入图像的灰度图像,这里当时没看清,一直奇怪为什么所有分类都被分成一个颜色 
img = cv2.imread('E:/pythonopencv/1picture/cross.jpg',0)
cv2.imshow('gray',img)
#选定种子点
seeds = [Point(145,140)]
#开始从种子点生长
binaryImg = regionGrow(img,seeds,5)
cv2.imshow('segment',binaryImg)
cv2.waitKey(0)
cv2.destroyAllWindows()

作者考虑很细致,对代码运行可能出现的区域外取点问题,已选点相互覆盖问题考虑都考虑进去。

展示读入的灰度图和输出结果:

python基于区域生长算法实现图像分割 python 区域生长_经验分享


图中可见,种子点所在的小十字图案完全从图中识别了出来。

但是,也有几点不足:

1、仅能对对比度灰度图处理。

2、在选择多个点后,目标识别出来后都是白的,无法对相似目标进行区分。输入图像原图:

python基于区域生长算法实现图像分割 python 区域生长_灰度图_02


目的想将彩色图片中的多个十字,并用不同颜色区分。

2.2我改的代码(目前不完善)

思路:将彩色分成三通(r,g,b),分别进行识别,最后再合成一副图。
代码:

import numpy as np
import cv2
 
class Point(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y
 
    def getX(self):
        return self.x
    def getY(self):
        return self.y
 
def getGrayDiff(img,currentPoint,tmpPoint):
    return abs(int(img[currentPoint.x,currentPoint.y]) - int(img[tmpPoint.x,tmpPoint.y]))
 
#def selectConnects(p):
def selectConnects():
    #if p != 0:
    connects = [Point(-1, -1), Point(0, -1), Point(1, -1), Point(1, 0), Point(1, 1), \
                    Point(0, 1), Point(-1, 1), Point(-1, 0)]#八邻域
    #else:
        #connects = [ Point(0, -1),  Point(1, 0),Point(0, 1), Point(-1, 0)]#四邻域
    return connects
 
def regionGrow(img,seeds,thresh,p = 1):
    height, weight = img.shape
    seedMark = np.zeros(img.shape)
    seedList = []
    for seed in seeds:
        seedList.append(seed)
    label = 1
    #connects = selectConnects(p)
    connects = selectConnects()
    while(len(seedList)>0):
        currentPoint = seedList.pop(0)#弹出第一个元素
 
        seedMark[currentPoint.x,currentPoint.y] = label
        for i in range(8):
            tmpX = currentPoint.x + connects[i].x
            tmpY = currentPoint.y + connects[i].y
            if tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >= weight:
                continue
            grayDiff = getGrayDiff(img,currentPoint,Point(tmpX,tmpY))
            if grayDiff < thresh and seedMark[tmpX,tmpY] == 0:
                seedMark[tmpX,tmpY] = label
                seedList.append(Point(tmpX,tmpY))
    return seedMark
 
 
img = cv2.imread('E:/pythonopencv/1picture/cross.jpg')
cv2.imshow("img",img)
b, g, r = cv2.split(img)
cv2.imshow("gsrc",g)
seeds = [Point(145,140)]
bbinaryImg = regionGrow(b,seeds,10)
gbinaryImg = regionGrow(g,seeds,10)
rbinaryImg = regionGrow(r,seeds,10)
binaryImg = cv2.merge([bbinaryImg,gbinaryImg,rbinaryImg])
cv2.imshow('b',bbinaryImg)
cv2.imshow('g',gbinaryImg)
cv2.imshow('r',rbinaryImg)
cv2.imshow('segment',binaryImg)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

python基于区域生长算法实现图像分割 python 区域生长_灰度图_03


g通道阈值设置比较高,小十字就和背景被归为一类了。导至g通道分离不明确,最后合成时出现了原图中的其他十字。

另一个代码想直接进行三通的比较,但是结果偏差太大。。。

大家如果有好的想法,一起交流讨论~