OpenCV自学笔记二十:图像分割和提取

1、用分水岭算法实现图像分割与提取

分水岭算法是一种经典的图像分割算法,用于将图像中的前景和背景进行分离。它基于图像中的灰度值和梯度信息来确定边界,并通过填充区域将图像分割成多个连通的区域。

以下是分水岭算法的基本原理:

1. 预处理:首先对输入图像进行预处理操作,例如灰度化、平滑滤波和边缘检测等,以便更好地捕捉图像的特征。

2. 计算梯度图:根据图像的梯度信息,生成一个梯度图像,用于表示图像中不同区域的边缘强度。

3. 标记种子点:选择一些合适的种子点作为分水岭算法的起始标记点。这些种子点可以手动选择,也可以通过其他分割算法自动选择。

4. 构建距离变换图:从种子点开始,计算每个像素到最近种子点的距离,并将其保存在一个距离变换图中。

5. 寻找最小值点:对距离变换图进行处理,寻找局部最小值点,这些点表示图像中的低谷区域。

6. 基于分水岭的图像分割:根据低谷区域,建立分水岭模型,并通过不断填充高度较小的区域来实现图像的分割。以下是一个简单的示例代码,演示如何使用Python和OpenCV库实现分水岭算法进行图像分割:

import cv2
import numpy as np

# 读取图像
image = cv2.imread('input_image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 预处理操作
blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 距离变换
dist_transform = cv2.distanceTransform(thresh, cv2.DIST_L2, 3)
_, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)

# 寻找未知区域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(thresh, sure_fg)

# 标记种子点
_, markers = cv2.connectedComponents(sure_fg)

# 添加标记
markers = markers + 1
markers[unknown == 255] = 0

# 应用分水岭算法
markers = cv2.watershed(image, markers)
image[markers == -1] = [0, 0, 255]

# 显示结果
cv2.imshow("Segmented Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()


在上述示例中,我们首先对输入图像进行预处理,然后通过距离变换找到前景区域,并确定未知区域。接下来,我们使用连通组件算法标记种子点,将其与未知区域结合,并应用分水岭算法进行图像分割。最后,通过在分水岭标记处添加红色边界线,可视化显示分割结果。

请注意,这只是分水岭算法的简单示例,实际应用中可能需要根据具体情况进行调整和优化。

2、交互式前景提取

交互式前景提取是一种图像处理技术,用于将图像中的前景对象从背景中分离出来。其原理基于计算机视觉和深度学习方法,以下是一个示例的交互式前景提取流程:

1. 输入图像:首先,用户提供一张包含前景对象和背景的图像。

2. 初始分割:使用图像分割算法(如GrabCut或基于超像素的方法),根据图像的纹理、颜色和边界信息对图像进行初步的前景-背景分割。

3. 用户交互:系统展示初始分割结果,并允许用户进行交互。用户可以通过绘制笔刷指示前景和背景的区域,或者通过标记像素为前景或背景来指定感兴趣的区域。

4. 更新分割:根据用户的交互信息,更新分割结果。通常使用图割(graph cuts)或随机游走(random walks)等优化方法来调整前景和背景的分割边界,使得分割结果更加准确。

5. 迭代交互:重复步骤3和步骤4,直到用户满意为止。用户可以通过多次交互来逐渐改进分割结果。

6. 输出前景:根据最终的分割结果,将前景对象从原始图像中提取出来,并生成一个包含前景的新图像。可以使用透明度通道或者二值掩码来表示前景对象。

交互式前景提取的示例应用广泛,例如抠图、图像编辑和虚拟背景等。通过与用户的交互,可以精确地选择所需的前景和背景区域,从而实现更加准确和自定义的前景提取效果。
下面是一个使用OpenCV实现交互式前景提取的简单示例:
 

import cv2

# 读取图像
image = cv2.imread('input_image.jpg')

# 创建一个窗口并设置鼠标回调函数
cv2.namedWindow('image')
mask = None

def mouse_callback(event, x, y, flags, param):
    global mask
    
    if event == cv2.EVENT_LBUTTONDOWN:
        # 初始化掩码
        mask = np.zeros(image.shape[:2], dtype=np.uint8)
        cv2.circle(mask, (x, y), 5, (255), -1)
        cv2.imshow('mask', mask)

        # 进行GrabCut算法
        bgdModel = np.zeros((1,65),np.float64)
        fgdModel = np.zeros((1,65),np.float64)
        rect = (x-50, y-50, 100, 100)  # 可根据具体情况调整矩形框的大小
        cv2.grabCut(image, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_MASK)

        # 更新掩码
        mask = np.where((mask==2)|(mask==0), 0, 1).astype('uint8')

        # 通过掩码提取前景
        foreground = image * mask[:, :, np.newaxis]

        cv2.imshow('foreground', foreground)

# 设置鼠标回调函数
cv2.setMouseCallback('image', mouse_callback)

while True:
    cv2.imshow('image', image)
    k = cv2.waitKey(1)
    
    # 按下ESC键退出循环
    if k == 27:
        break

cv2.destroyAllWindows()

上述示例中,我们首先读取输入图像。然后,创建一个窗口并设置鼠标回调函数。在鼠标回调函数中,我们使用GrabCut算法进行前景提取,并根据用户点击的位置生成初始掩码。然后,根据掩码提取前景,并显示在窗口中。用户可以通过点击图像来指定感兴趣的前景区域。按下ESC键退出程序。

你可能感兴趣的:(opencv,笔记,计算机视觉)