【分割实战】三种图像分割方法实战对比:Mask R-CNN + GrabCut + OpenCV【附源码】

引言

图像分割是计算机视觉中比目标检测更进一步的任务------不仅要知道"图里有什么、在哪",还要精确到像素级别,把每个物体的轮廓抠出来。这项技术在医学影像、自动驾驶、AR特效、图像编辑等领域都有广泛应用。

本文用三种方法完成同一件事:把目标从背景中分离出来。从深度学习到传统算法,从实例分割到前景提取,一次讲清楚各自的适用场景和效果差异。

项目简介

分别使用Mask R-CNN(深度学习)、GrabCut(图割算法)、K-Means聚类(传统图像处理)三种方法实现图像分割,对比不同技术路线的效果和适用场景。

  • 方法一:Mask R-CNN------实例级分割,每个物体独立mask
  • 方法二:GrabCut------交互式前景提取,需给定目标区域
  • 方法三:K-Means------无监督像素聚类,按颜色分区

功能特性

  • Mask R-CNN:检测+分割一体化,输出类别、边界框和像素级mask
  • GrabCut:用户只需框出目标区域,算法自动迭代分离前景/背景
  • K-Means:无需训练数据,直接基于像素颜色聚类分区
  • 三种方法覆盖深度学习、图优化、传统图像处理三条路线

环境配置

bash 复制代码
pip install torch torchvision pillow opencv-python matplotlib numpy

依赖项:

  • PyTorch + Torchvision:加载Mask R-CNN预训练模型
  • OpenCV:GrabCut与K-Means实现
  • PIL / Matplotlib:图像读取与可视化

核心实现

方法一:Mask R-CNN 实例分割

python 复制代码
import torch
import torchvision
from PIL import Image
import matplotlib.pyplot as plt
import torchvision.transforms as T
import numpy as np

# 加载预训练的Mask R-CNN模型(R50-FPN骨干)
model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)
model.eval()

# 读取图像并转换为张量
img = Image.open("image.jpeg").convert("RGB")
transform = T.Compose([T.ToTensor()])
img_tensor = transform(img)

# 推理
with torch.no_grad():
    prediction = model([img_tensor])[0]

img_np = np.array(img)

plt.figure(figsize=(10, 8))
plt.imshow(img_np)
plt.title("Mask R-CNN Segmentation")
plt.axis("off")

# 提取检测结果
boxes = prediction["boxes"].numpy()
scores = prediction["scores"].numpy()
masks = prediction["masks"].numpy()

# 遍历高置信度检测结果,绘制mask和边界框
for i in range(len(scores)):
    if scores[i] > 0.5:
        mask = masks[i, 0]
        # 半透明叠加mask
        plt.imshow(mask, alpha=0.5)

        x1, y1, x2, y2 = boxes[i]
        plt.gca().add_patch(
            plt.Rectangle(
                (x1, y1),
                x2 - x1,
                y2 - y1,
                fill=False,
                edgecolor="red",
                linewidth=2
            )
        )

plt.show()

核心思路:

  1. 加载torchvision预训练的maskrcnn_resnet50_fpn模型,骨干网络ResNet50搭配FPN特征金字塔,直接用于推理无需额外训练;
  2. model.eval()切换到推理模式,with torch.no_grad()禁用梯度计算以节省内存并加速;
  3. 模型返回prediction字典,包含boxes(边界框坐标)、scores(置信度分数)、masks(二值掩码,形状N,1,H,W)三个关键字段;
  4. 遍历scores>0.5的高置信度检测结果,用alpha=0.5半透明叠加mask到原图,并用红色空心矩形绘制边界框

关键参数说明:

  1. pretrained=True:加载在COCO数据集上预训练的权重,可直接检测80类常见目标;
  2. masksi, 0:每个检测结果对应一个mask,取第一个通道得到二值图;
  3. scores > 0.5:置信度阈值,低于0.5的检测结果被过滤,可根据实际需求调整

方法二:GrabCut 前景提取

python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像并转换颜色空间
img = cv2.imread("image.jpeg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 初始化GrabCut所需变量
mask = np.zeros(img.shape[:2], np.uint8)

bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)

h, w = img.shape[:2]

# 定义前景区域:图像中央偏内区域
rect = (int(w*0.15), int(h*0.15), int(w*0.7), int(h*0.7))

# 执行GrabCut,迭代8次
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 8, cv2.GC_INIT_WITH_RECT)

# 提取确定前景和可能前景区域
mask2 = np.where((mask == cv2.GC_FGD) | (mask == cv2.GC_PR_FGD), 1, 0).astype("uint8")

# 将mask应用到原图
result = img * mask2[:, :, np.newaxis]

print("Unique mask values:", np.unique(mask2))

# 并排显示原图与分割结果
plt.figure(figsize=(12,5))

plt.subplot(1,2,1)
plt.imshow(img)
plt.title("Input Image")
plt.axis("off")

plt.subplot(1,2,2)
plt.imshow(result)
plt.title("GrabCut Output")
plt.axis("off")

plt.show()

核心思路:

  1. 用户用矩形框标记目标区域后,算法用两个高斯混合模型(GMM)分别建模前景和背景的颜色分布;
  2. 通过最小化能量函数(包含颜色相似性项和空间平滑项)迭代优化每个像素的前景/背景标签;
  3. 每次迭代后重新估计GMM参数并更新分割结果,逐步精化前景区域边界;
  4. 最终将确定前景(GC_FGD)和可能前景(GC_PR_FGD)合并为二值mask,与原图逐像素相乘完成背景去除

关键参数说明:

  1. rect:初始前景矩形区域,格式为(x, y, width, height),示例取图像15%-85%范围,需确保目标完全落在矩形内;
  2. bgdModel和fgdModel:各65个分量(5个高斯分量 × 13维特征,13 = 3通道 × 4种像素邻域关系 + 1),用于GMM颜色建模;
  3. 迭代次数=8:迭代次数越多分割越精细,但计算量也越大,8次为常用经验值;
  4. cv2.GC_INIT_WITH_RECT:初始化模式,表示用矩形框初始化分割区域;
  5. GC_FGD(值为1):确定前景像素;GC_PR_FGD(值为3):可能前景像素;两者合并为最终前景mask;
  6. mask2:,:,np.newaxis:将二维mask(H,W)扩展为三维(H,W,1),利用numpy广播机制与原图逐像素相乘

方法三:K-Means 颜色聚类分割

python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像
img = cv2.imread("image.jpeg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 将图像展平为像素列表,每像素3通道(RGB)
pixel_values = img.reshape((-1, 3))
pixel_values = np.float32(pixel_values)

# K-Means聚类参数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
k = 3   # 聚类数

# 执行K-Means
_, labels, centers = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)

# 将聚类中心转为uint8
centers = np.uint8(centers)

# 用聚类中心颜色重建图像
segmented_image = centers[labels.flatten()]
segmented_image = segmented_image.reshape(img.shape)

# 并排显示原图与分割结果
plt.figure(figsize=(10,5))

plt.subplot(1,2,1)
plt.imshow(img)
plt.title("Input Image")
plt.axis("off")

plt.subplot(1,2,2)
plt.imshow(segmented_image)
plt.title("OpenCV Segmentation Output (K-Means)")
plt.axis("off")

plt.show()

核心思路:

  1. 将每个像素的RGB值视为三维空间中的一个点,通过K-Means迭代聚类将颜色相似的像素归为同一组;
  2. img.reshape((-1,3))将H×W×3的图像展平为(H*W, 3)的像素列表,作为聚类输入;
  3. 聚类收敛后,每个簇用其聚类中心的颜色替换该簇内所有像素,完成颜色分区重建

关键参数说明:

  1. k=3:聚类数量,将图像分为3个颜色区域,可根据图像内容和需求调整;
  2. criteria:停止条件,由TERM_CRITERIA_EPS(精度达到0.2时停止)和TERM_CRITERIA_MAX_ITER(最多迭代100次)组合;
  3. cv2.KMEANS_RANDOM_CENTERS:初始聚类中心随机选择方式;
  4. labels:每个像素所属的聚类标签;centers:每个聚类的平均RGB颜色值;
  5. 注意:K-Means仅按颜色空间距离分区,不保证每个区域对应一个语义物体,适合简单场景或预处理

效果展示

三种方法的效果对比:

方法 技术路线 输出类型 适用场景
Mask R-CNN 深度学习 实例mask+框+类别 多物体精确分割、自动驾驶
GrabCut 图割算法 二值前景mask 单目标抠图、图像编辑
K-Means 像素聚类 颜色分区图 简单颜色分割、预处理
  • Mask R-CNN:给出每个物体的独立mask和类别标签,但需要GPU和预训练模型
  • GrabCut:只需用户框出目标即可获得高质量前景提取,但对复杂背景效果下降
  • K-Means:最快最轻量,但只能按颜色分区无语义理解

总结

方案优势:

  • 三条技术路线覆盖深度学习、图优化、传统图像处理,适用不同资源条件
  • Mask R-CNN一行代码加载预训练模型,可直接用于80类COCO目标
  • GrabCut仅需OpenCV即可运行,无深度学习依赖
  • K-Means最为轻量,适合简单场景或预处理步骤

选型建议:

  • 需要识别+分割多个特定类别物体:Mask R-CNN
  • 只需从背景中抠出一个目标:GrabCut
  • 资源受限或仅需按颜色分区:K-Means

觉得有用,记得点个赞和在看

相关推荐
晨间晓3 天前
图片里的高频和低频是什么?用华为云码道开发 OpenCV 傅里叶频谱分析工具
opencv·计算机视觉·华为云
晨间晓3 天前
图片里的阴影能不能减弱?用华为云码道开发 OpenCV 光照校正工具
人工智能·opencv·华为云
晨间晓3 天前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭4 天前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓4 天前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云
晨间晓4 天前
二值图里的噪点怎么去掉?用华为云码道开发 OpenCV 形态学操作工具
人工智能·opencv·华为云
晨间晓4 天前
图片里的角点在哪里?用华为云码道开发 OpenCV Harris 角点检测工具
人工智能·opencv·华为云
晨间晓4 天前
图片细节丰富不丰富?用华为云码道开发 OpenCV 纹理复杂度分析工具
人工智能·opencv·华为云
把我格子衫拿来4 天前
Dice 很高就够了吗?分割评价中的 IoU、表面距离与 HD95
python·图像分割·模型评估·医学影像·dice
richard_yuu5 天前
OpenCV 实战第 15 篇:G-API 图计算,工业流水线的 CPU/GPU 混合执行
人工智能·opencv·计算机视觉