OpenCV与图像处理学习十——区域生长算法(含代码)

OpenCV与图像处理学习十——区域生长算法(含代码)

一、区域生长算法概要

区域生长是一种串行区域分割的图像分割方法。区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止

区域生长的好坏决定于:

  1. 初始点(种子点)的选取。
  2. 生长准则。
  3. 终止条件。

区域生长是从某个或者某些像素点出发,最后得到整个区域,进而实现目标的提取

二、区域生长算法原理

基本思想:将具有相似性质的像素集合起来构成区域。

步骤

  1. 对图像顺序扫描,找到第1个还没有归属的像素, 设该像素为(x0, y0);
  2. 以(x0, y0)为中心, 考虑(x0, y0)的4邻域像素(x, y)如果(x0,y0)满足生长准则, 将(x, y)与(x0, y0)合并(在同一区域内), 同时将(x, y)压入堆栈(即满足条件,被判定为和(x0, y0)属于一个区域,后面需要再从这些点往外继续生长,所以需要保存);
  3. 从堆栈中取出一个像素, 把它当作(x0, y0)返回到步骤2(继续往外生长);
  4. 当堆栈为空时,返回到步骤1(有像素可能不属于前面的区域);
  5. 重复步骤1 - 4直到图像中的每个点都有归属时;生长结束。

三、代码应用

这里为简单起见,我们只设置了一个区域,即上述步骤中的第四步改为,当堆栈为空时,生长结束。

我们需要分割的图像如下所示:
在这里插入图片描述
我们将生长准则设置为像素值之间的欧式距离小于某个阈值,也就是说相邻像素值的差异较小时,归类为一个区域,代码如下所示:

# -*- coding:utf-8 -*-
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('./image/222.jpg')
cv2.imshow('src', im)
cv2.waitKey(0)
cv2.destroyAllWindows()
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)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 建立空的图像数组,作为一类
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)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 取一点作为种子点
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)
cv2.destroyAllWindows()

分割得到的结果如下所示:
在这里插入图片描述
很显然,天空的像素值较为接近,所以被生长为一片区域,而房屋的像素与天空的差异较大,当天空的区域生长结束之后,因为这里只设置了分割一块区域,所以下面的房屋部分没有遍历到。

分水岭算法(watershed algorithm)是一种用于图像分割的算法,可以自动将图像分割成不同的区域OpenCV提供了分水岭算法的实现,可以通过调用cv2.watershed()函数来进行图像分割。 使用分水岭算法进行图像分割的基本步骤如下: 1. 读取图像并将其转换为灰度图像。 2. 对灰度图像进行二值化处理,得到前景(foreground)和背景(background)。 3. 对图像进行距离变换,得到每个像素到最近的背景像素的距离。 4. 对距离变换的结果进行阈值处理,得到一张标记(markers)图像。 5. 对标记图像进行分水岭算法处理,得到分割结果。 下面是一个简单的示例代码,演示了如何使用分水岭算法对图像进行分割: ```python import cv2 import numpy as np # 读取图像并转换为灰度图像 img = cv2.imread('image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 对灰度图像进行二值化处理 ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) # 进行距离变换 dist_transform = cv2.distanceTransform(thresh, cv2.DIST_L2, 5) ret, markers = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0) # 对标记图像进行分水岭算法处理 markers = cv2.watershed(img, markers) img[markers == -1] = [0,255,0] # 显示分割结果 cv2.imshow('Segmented Image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的代码中,我们首先读取一张名为"image.jpg"的图像,并将其转换为灰度图像。然后利用cv2.threshold()函数对灰度图像进行二值化处理,得到前景和背景。接下来,我们使用cv2.distanceTransform()函数进行距离变换,得到每个像素到最近的背景像素的距离。然后对距离变换的结果进行阈值处理,得到一张标记图像。最后,我们利用cv2.watershed()函数对标记图像进行分水岭算法处理,得到分割结果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值