Opencv之区域生长和分裂

区域生长

1.基本原理

区域生长法是较为基础的一种区域分割方法

它的基本思想我说的通俗些,即是一开始有一个生长点(可以一个像素也可以是一个小区域),从这个生长点开始往外扩充,扩充的意思就是它会把跟自己有相似特征的像素或者区域拉到自己的队伍里,以此壮大自己的势力范围,每次扩大后的势力范围就是一个新的生长点,一直生长一直生长,直到不能生长为止。

所以很容易就能总结出来三个要点:

(1)一个合适的像素或者小区域作为开始的生长点

(2)生长准则,也就是通过什么标准你才能拉他入伙

(3)停止生长的条件 什么时候停止扩充

2.简单例子说明

下面是一个简单的例子:

3.代码

复制代码
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


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)
]


#####################################################################################
# 计算两个点间的欧式距离
def get_dist(seed_location1, seed_location2):
    l1 = im[seed_location1.x, seed_location1.y]
    l2 = im[seed_location2.x, seed_location2.y]
    count = np.sqrt(np.sum(np.square(l1 - l2)))
    return count


# import Image
im = cv2.imread('./7.jpg')
cv2.imshow('src', im)
im_shape = im.shape
height = im_shape[0]
width = im_shape[1]

print('the shape of image :', im_shape)

# 标记,判断种子是否已经生长
img_mark = np.zeros([height, width])
cv2.imshow('img_mark', img_mark)

# 建立空的图像数组,作为一类
img_re = im.copy()
for i in range(height):
    for j in range(width):
        img_re[i, j][0] = 0
        img_re[i, j][1] = 0
        img_re[i, j][2] = 0
cv2.imshow('img_re', img_re)

# 取一点作为种子点
seed_list = []
seed_list.append(Point(15, 15))
T = 7  # 阈值
class_k = 1  # 类别
# 生长一个类
while (len(seed_list) > 0):
    seed_tmp = seed_list[0]
    # 将以生长的点从一个类的种子点列表中删除
    seed_list.pop(0)

    img_mark[seed_tmp.x, seed_tmp.y] = class_k

    # 遍历8邻域
    for i in range(8):
        tmpX = seed_tmp.x + connects[i].x
        tmpY = seed_tmp.y + connects[i].y

        if (tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >= width):
            continue
        dist = get_dist(seed_tmp, Point(tmpX, tmpY))
        # 在种子集合中满足条件的点进行生长
        if (dist < T and img_mark[tmpX, tmpY] == 0):
            img_re[tmpX, tmpY][0] = im[tmpX, tmpY][0]
            img_re[tmpX, tmpY][1] = im[tmpX, tmpY][1]
            img_re[tmpX, tmpY][2] = im[tmpX, tmpY][2]
            img_mark[tmpX, tmpY] = class_k
            seed_list.append(Point(tmpX, tmpY))

########################################################################################
# 输出图像
cv2.imshow('OUTIMAGE', img_re)
cv2.waitKey(0)

区域生长法的优点是计算简单,对于较均匀的连通目标有较好的分割效果。

缺点是需要人为确定种子点,对噪声敏感,可能导致区域内有空洞。另外当目标较大时,分割速度较慢,因此在设计算法时,要尽量提高效率。

区域分裂和聚合

1.基本原理

分裂和聚合

具体来说 举个例子

区域分裂与聚合就是判断一个区域的均值和方差是不是在人为设定的阈值中,如果是的话这个区域分割出来,不是的话就将这个区域分为左上、右上、左下、右下四个部分再递归判断,直到最后结束。

代码

复制代码
import cv2 as cv
import numpy as np


class region_div:

    def __init__(self, img):
        self.img = img
        self.res = np.zeros(img.shape)

    def region_div_group(self, range1, range2):
        if range1[1] - range1[0] == 0 or range2[1] - range2[0] == 0:
            return

        mean = self.img[range1[0]:range1[1], range2[0]:range2[1]].mean()
        var = self.img[range1[0]:range1[1], range2[0]:range2[1]].var()
        # print(self.img[range1[0]:range1[1],range2[0]:range2[1]])
        # print(range1, range2, var)
        if var < 10:
            self.res[range1[0]:range1[1], range2[0]:range2[1]] = 255
        else:
            if range1[1] - range1[0] >= 2 and range2[1] - range2[0] >= 2:
                self.region_div_group(
                    [range1[0], (range1[0] + range1[1]) // 2],
                    [range2[0], (range2[0] + range2[1]) // 2])
                self.region_div_group(
                    [(range1[0] + range1[1]) // 2, range1[1]],
                    [range2[0], (range2[0] + range2[1]) // 2])
                self.region_div_group(
                    [range1[0], (range1[0] + range1[1]) // 2],
                    [(range2[0] + range2[1]) // 2, range2[1]])
                self.region_div_group(
                    [(range1[0] + range1[1]) // 2, range1[1]],
                    [(range2[0] + range2[1]) // 2, range2[1]])


image = cv.imread('./8.jpg')
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
# print(gray.shape)
# print(gray[0:1, 5:11])
res = np.zeros(gray.shape)
rd = region_div(gray)
rd.region_div_group([0, gray.shape[0]], [0, gray.shape[1]])

res = rd.res
cv.namedWindow("gray")
cv.imshow("gray", gray)
cv.waitKey(0)

cv.namedWindow("res")
cv.imshow("res", res)
cv.waitKey(0)
相关推荐
IT_陈寒16 小时前
Vue这个坑我跳了两次,原来问题出在这
前端·人工智能·后端
新新技术迷16 小时前
Node给AI接口做SSE代理与鉴权
人工智能
redreamSo17 小时前
大模型是不是到顶了?瓶颈到底在哪
人工智能·openai
Oo92017 小时前
Tool Use 背后的技术逻辑
人工智能
姗姗来迟了17 小时前
Vue3封装AI流式对话组件踩坑实录
人工智能
码上天下17 小时前
用Pinia管理AI多会话状态
人工智能
用户0543243297018 小时前
Next.js接大模型流式SSE实操踩坑
人工智能
Assby18 小时前
从 Function Calling 到 MCP:理解 Agent 工具调用的底层通信机制
人工智能·后端
小星AI19 小时前
Claude Code 从入门到精通,一步到位
人工智能
后端小肥肠19 小时前
Codex + Obsidian 做人生副本视频:输入主题文案,直通剪映草稿
人工智能·aigc·agent