实例分割、语义分割和 SAM(Segment Anything Model) 都是图像处理中的重要技术,它们的目标是通过分割图像中的不同对象或区域来帮助识别和分析图像,但它们的工作方式和适用场景各有不同。
1. 语义分割(Semantic Segmentation)
- 目标: 语义分割的目的是将图像中的每个像素归类到某一个类别中,不区分同类中的不同个体。
- 特点: 语义分割只关心“类别”,而不关心图像中有多少个对象。换句话说,如果图像中有多辆车,它们都被归类为“车”,但不会区分不同的车。
- 应用场景: 自动驾驶中的道路、建筑物、行人分割,医学图像中的器官分割。
例子: 在城市街景中,语义分割会将所有的树木标记为同一个类别“树”,所有的道路标记为“道路”,而不会区分某一棵树或某一段路。
2. 实例分割(Instance Segmentation)
- 目标: 实例分割不仅要将每个像素归类到某个类别,还要区分同类中的不同个体。
- 特点: 实例分割可以同时进行物体检测和像素级的分割。例如,它不仅会检测图像中的车,还会为每辆车生成单独的掩码,从而区分同一图像中的不同车辆。
- 应用场景: 实例分割常用于自动驾驶、增强现实(AR)、机器人视觉、视频监控等领域,在这些场景中需要区分同类物体的不同个体。
例子: 在同样的城市街景中,实例分割不仅会识别“车”这个类别,还会区分每一辆车。
3. SAM(Segment Anything Model)
- 目标: SAM 是一种通用的分割模型,旨在实现“一切的分割”。它结合了语义分割和实例分割的能力,但更加灵活。
- 特点: SAM 能够在提供提示(如边界框、点)的情况下进行精确的分割,而无需针对特定任务或类别进行专门训练。这意味着你可以通过简单的提示(如边界框、点击目标)来触发分割操作,无论图像中是什么物体,SAM 都可以尝试分割。
- 应用场景: SAM 可以在任何需要分割的场景下应用,尤其适用于需要用户交互的场景,如图像标注、医疗图像分析、用户定制分割等。它能够分割新类别的物体,而不依赖于预先定义的类别。
例子: SAM 可以根据给定的边界框分割出手、车、动物等,而不需要事先知道物体的类别。用户也可以通过点选某些区域来生成物体的分割掩码。
主要区别:
-
类别和个体的区分:
- 语义分割: 只关心类别,所有属于同一类别的物体都会被统一处理,不区分个体。
- 实例分割: 不仅分割类别,还区分每个个体,即使是同一类别的物体,也会生成单独的掩码。
- SAM: 可以基于提示(如点、边界框)分割任意物体,具有更大的灵活性,不局限于某一特定类别或预先定义的任务。
-
应用场景:
- 语义分割: 适合场景分类和大范围的物体分割,如识别整个场景中的类别。
- 实例分割: 适合需要区分多个同类物体的场景,如自动驾驶中的行人、车辆检测。
- SAM: 适合任意分割任务,可以应对未知类别和灵活的用户交互需求。
-
灵活性:
- 语义分割和实例分割通常依赖于预先定义的类别或特定任务进行训练。
- SAM 是一种通用分割工具,能够根据用户的提示分割出几乎任何类型的物体,无需预先训练。
小结:
- 语义分割 是针对类别的分割,适用于大范围的场景分析。
- 实例分割 通过区分同类个体,提供更精细的对象分割。
- SAM 则是一种通用分割工具,灵活且不局限于特定类别和任务。
首先我们写一段简单的代码来看一下语义分割,语义分割就是可以把具体的某个像素点分给某个物体,而不是像目标检测一样用一个框标出
import torch
from torchvision import models, transforms
from PIL import Image
import matplotlib.pyplot as plt
# 加载预训练的DeepLabV3模型
model = models.segmentation.deeplabv3_resnet101(pretrained=True).eval()
# 图像预处理
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
# 加载图像
image_path = "path/000000000257.jpg" # 替换为你的图片路径
image = Image.open(image_path)
input_tensor = preprocess(image).unsqueeze(0)
# 执行语义分割
with torch.no_grad():
output = model(input_tensor)['out'][0]
output_predictions = output.argmax(0) # 获取每个像素的类别
# 将分割结果可视化
plt.figure(figsize=(10, 5))
# 显示原图
plt.subplot(1, 2, 1)
plt.imshow(image)
plt.title("Original Image")
# 显示语义分割结果
plt.subplot(1, 2, 2)
plt.imshow(output_predictions.cpu().numpy())
plt.title("Semantic Segmentation")
plt.show()
把物体和背景有效进行区分了
实例分割
import torch
from PIL import Image
from torchvision import models, transforms
import matplotlib.pyplot as plt
import cv2
import numpy as np
# 加载预训练的Mask R-CNN模型
model = models.detection.maskrcnn_resnet50_fpn(pretrained=True).eval()
# 图像预处理
preprocess = transforms.Compose([
transforms.ToTensor(),
])
# 加载图像
image_path = "path/000000000257.jpg" # 替换为你的图片路径
image = Image.open(image_path)
input_tensor = preprocess(image).unsqueeze(0)
# 执行实例分割
with torch.no_grad():
output = model(input_tensor)
# 获取分割掩码
masks = output[0]['masks'].cpu().numpy()
boxes = output[0]['boxes'].cpu().numpy()
# 可视化边界框和实例掩码
image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
for i in range(len(masks)):
mask = masks[i, 0] # 获取掩码
mask = cv2.resize(mask, (image_cv.shape[1], image_cv.shape[0])) # 将掩码调整为与原图大小一致
# 将掩码叠加到图像上
image_cv[mask > 0.5] = [0, 0, 255] # 红色掩码
# 绘制边界框
box = boxes[i].astype(int)
cv2.rectangle(image_cv, (box[0], box[1]), (box[2], box[3]), (255, 0, 0), 2) # 蓝色边框
# 显示结果
plt.imshow(cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB))
plt.title("Instance Segmentation (Mask R-CNN)")
plt.show()
当然小编这里导入的语义分割和实例分割的模型差异导致了识别也有差异
SAM
import matplotlib.pyplot as plt
import numpy as np
from ultralytics import YOLO
from PIL import Image
import cv2
from segment_anything import SamPredictor, sam_model_registry
# 加载图像
image_path = r'F:/photos/photo_1.jpg' # 替换为你的图片路径
image = Image.open(image_path)
# 将图像转换为 OpenCV 格式以便显示
image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
# 加载 YOLO 模型
yolo_model = YOLO("F:/科研学习/yolo系列params/v10/YOLOv10x_gestures.pt")
# yolo_model = YOLO("F:/科研学习/yolov11/yolov11/yolov11/资料/模型文件/yolov8n.pt")
yolo_results = yolo_model(image)
# 加载 SAM 模型
sam_model = sam_model_registry["vit_l"](checkpoint="C:/Users/张佳珲/Downloads/sam_vit_l_0b3195.pth")
predictor = SamPredictor(sam_model)
# 将整个图像传递给 SAM 模型
predictor.set_image(np.array(image)) # 传递整个图像
# 遍历 YOLO 检测结果并绘制边界框
for result in yolo_results:
if len(result.boxes) > 0: # 检查是否有检测到物体
boxes = result.boxes.xyxy # YOLO 边界框
for box in boxes:
# 画出 YOLO 边界框 (蓝色)
x1, y1, x2, y2 = map(int, box)
cv2.rectangle(image_cv, (x1, y1), (x2, y2), (255, 0, 0), 2) # 蓝色框代表 YOLO 的检测
# 使用 SAM 模型预测分割掩码
masks, _, _ = predictor.predict(box=np.array([x1, y1, x2, y2]), multimask_output=False)
# 获取掩码并直接叠加到原图上
mask = masks[0] # 使用第一个掩码
mask_uint8 = mask.astype(np.uint8) # 将布尔掩码转换为 uint8 类型
# 调整掩码大小为与原图一致,并直接叠加到原图上
mask_resized = cv2.resize(mask_uint8, (image_cv.shape[1], image_cv.shape[0]), interpolation=cv2.INTER_NEAREST)
image_cv[mask_resized == 1] = [0, 0, 255] # 红色表示分割区域
# 使用 Matplotlib 显示 YOLO 边界框和 SAM 分割的对比
fig, ax = plt.subplots(1, 1, figsize=(10, 10))
# 显示叠加了 SAM 掩码和 YOLO 边界框的原图
ax.imshow(cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB))
ax.set_title("Original Image with SAM Segmentation and YOLO Bounding Box")
plt.show()