【分割实战】三种图像分割方法实战对比: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

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

相关推荐
W_3260018 小时前
Python-OpenCV 轮廓进阶:旋转最小外接矩形、图像矩求质心、嵌套层级 hierarchy、轮廓形状匹配
图像处理·python·opencv·机器学习·计算机视觉
牧羊人.33320 小时前
计算机视觉基础 第 9 章|实战:银行卡号识别
图像处理·人工智能·opencv·计算机视觉·图搜索算法
欧特克_Glodon1 天前
OpenCV计算机视觉开发入门与实践<十三>:图像转换之灰度图、二值图
c++·人工智能·opencv·计算机视觉
AndrewHZ1 天前
图像处理入门010 | Pillow 与 OpenCV 对比:双库图像读写实战
图像处理·opencv·计算机视觉·pillow
欧特克_Glodon1 天前
OpenCV计算机视觉开发入门与实践<十二>:XML 和 YAML 文件读写
xml·c++·opencv·计算机视觉
W_326002 天前
Python-OpenCV边缘检测与阈值分割:Sobel、Scharr、Laplacian、Canny、全局与自适应阈值
开发语言·图像处理·python·opencv·机器学习
闻道且行之2 天前
图片处理助手|C++ 手搓离线 AI 抠图工具,U2Net 原理到落地一次讲透
开发语言·c++·人工智能·神经网络·opencv·计算机视觉
AndrewHZ2 天前
图像处理入门009 | OpenCV 图像读取与显示:imread/imshow 全解析
图像处理·python·opencv·算法·计算机视觉·图像显示
W_326003 天前
Python-OpenCV图像像素与通道:通道拆分合并、深浅拷贝
图像处理·人工智能·python·opencv·机器学习
欧特克_Glodon3 天前
OpenCV计算机视觉开发入门与实践<十一>:矩阵的复制和矩形类Rect
c++·opencv·计算机视觉·矩阵