本文目录导读:

- 方法一:使用 SegFormer(最推荐,高精度)
- 方法二:使用 SAM(Segment Anything Model,万物分割)
- 方法三:使用 DeepLabv3+(轻量级、速度快)
- 方法四:基于 Contour 的传统图像分割(无深度学习)
- 总结与选择建议
实现Python场景分割(图像分割)通常使用深度学习模型,最主流的方法是基于SegFormer(如Mask2Former)、DeepLabv3+ 或 SAM(Segment Anything Model)。
以下我将提供4种常见且实用的实现方式,从最强大的到最轻量的,并附上完整代码案例。
前置准备:安装依赖
pip install torch torchvision pip install transformers # 用于SegFormer pip install opencv-python # 用于图像处理 pip install matplotlib # 用于显示结果
使用 SegFormer(最推荐,高精度)
SegFormer是NVIDIA提出的高效Transformer分割模型,适合语义分割场景。
代码实现
import torch
import cv2
import numpy as np
import matplotlib.pyplot as plt
from transformers import SegformerImageProcessor, SegformerForSemanticSegmentation
def segment_with_segformer(image_path,save_path='seg_result.jpg'):
# 1. 加载预训练模型和处理器
# 选择模型:b0最快但精度一般,b5最慢但精度极高
model_name = "nvidia/segformer-b0-finetuned-ade-512-512"
processor = SegformerImageProcessor.from_pretrained(model_name)
model = SegformerForSemanticSegmentation.from_pretrained(model_name)
# 2. 读取图像
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 3. 预处理
inputs = processor(images=image_rgb, return_tensors="pt")
# 4. 推理
with torch.no_grad():
outputs = model(**inputs)
logits = outputs.logits # shape: [1, 150, 128, 128]
# 上采样到原图尺寸
upsampled_logits = torch.nn.functional.interpolate(
logits,
size=image_rgb.shape[:2],
mode="bilinear",
align_corners=False
)
# 获取每个像素的类别索引
predicted_map = upsampled_logits.argmax(dim=1).squeeze(0).cpu().numpy()
# 5. 可视化(将预测的类别映射为颜色)
# ADE20K数据集的默认颜色映射(150类)
color_map = np.random.randint(0, 255, (150, 3), dtype=np.uint8)
segmented_image = color_map[predicted_map]
# 6. 显示结果
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.imshow(image_rgb)
plt.title("原始图像")
plt.axis('off')
plt.subplot(1, 2, 2)
plt.imshow(segmented_image)
plt.title("语义分割结果")
plt.axis('off')
plt.savefig(save_path)
plt.show()
return predicted_map, segmented_image
# 使用示例
image_path = "/path/to/your/image.jpg" # 替换为你的图片路径
segment_with_segformer(image_path)
注:ADE20K数据集包含150个语义类别(道路、树木、天空、人等)。
使用 SAM(Segment Anything Model,万物分割)
如果你需要分割出图像中的每个物体(无需预先定义类别),SAM是最强的选择。
import torch
import cv2
import numpy as np
import matplotlib.pyplot as plt
from segment_anything import sam_model_registry, SamPredictor
def segment_with_sam(image_path, save_path='sam_result.jpg'):
# 1. 加载SAM模型(需要先下载权重文件)
# 下载地址:https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth
sam_checkpoint = "/path/to/sam_vit_h_4b8939.pth" # 替换为实际路径
device = "cuda" if torch.cuda.is_available() else "cpu"
sam = sam_model_registry["vit_h"](checkpoint=sam_checkpoint)
sam.to(device=device)
predictor = SamPredictor(sam)
# 2. 读取图像
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 3. 设置图像
predictor.set_image(image_rgb)
# 4. 自动生成全图掩码(不需要输入点)
# 使用`generate`模式或使用密集网格点
h, w = image_rgb.shape[:2]
point_grid_size = 32 # 网格密度
points_per_side = point_grid_size
from segment_anything import SamAutomaticMaskGenerator
mask_generator = SamAutomaticMaskGenerator(sam)
masks = mask_generator.generate(image_rgb)
# 5. 可视化所有分割结果
plt.figure(figsize=(12, 12))
plt.imshow(image_rgb)
for i, mask_data in enumerate(masks):
mask = mask_data['segmentation']
# 随机颜色
color = np.random.rand(3)
overlay = np.zeros_like(image_rgb, dtype=np.float32)
overlay[mask] = color * 255
plt.imshow(overlay, alpha=0.4)
plt.axis('off')
plt.savefig(save_path)
plt.show()
return masks
# 使用示例
image_path = "/path/to/your/image.jpg"
segment_with_sam(image_path)
使用 DeepLabv3+(轻量级、速度快)
适合实时应用或移动端部署,ResNet101作为backbone。
import torch
import torchvision.transforms as T
import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def segment_with_deeplab(image_path, save_path='deeplab_result.jpg'):
# 1. 加载预训练的DeepLabv3
model = torch.hub.load('pytorch/vision', 'deeplabv3_resnet101', pretrained=True)
model.eval()
# 2. 图像预处理
transform = T.Compose([
T.Resize(256),
T.CenterCrop(224),
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
# 3. 读取并处理图像
image = Image.open(image_path).convert('RGB')
input_tensor = transform(image).unsqueeze(0)
# 4. 推理
with torch.no_grad():
output = model(input_tensor)['out'][0]
output_predictions = output.argmax(0).byte().cpu().numpy()
# 5. 映射到原图尺寸
output_resized = cv2.resize(output_predictions, (image.size[0], image.size[1]),
interpolation=cv2.INTER_NEAREST)
# 6. 可视化(PASCAL VOC 21类)
# 创建一个简单的颜色映射
palette = np.array([
[0, 0, 0], # 背景
[128, 0, 0], # 飞机
[0, 128, 0], # 自行车
# ... 更多颜色可根据需要扩展
])
# 这里只显示后21种颜色(PASCAL VOC常用)
color_map = np.random.randint(0, 255, (21, 3), dtype=np.uint8)
color_map[0] = [0, 0, 0] # 背景为黑色
segmented = color_map[output_resized]
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.imshow(image)
plt.title("原始图像")
plt.axis('off')
plt.subplot(1, 2, 2)
plt.imshow(segmented)
plt.title("DeepLabv3分割结果")
plt.axis('off')
plt.savefig(save_path)
plt.show()
return output_resized
# 使用示例
segment_with_deeplab("/path/to/your/image.jpg")
基于 Contour 的传统图像分割(无深度学习)
如果场景简单(如分割前景和背景),可用OpenCV的轮廓检测方法。
import cv2
import numpy as np
import matplotlib.pyplot as plt
def simple_scene_segmentation(image_path, save_path='simple_seg.jpg'):
# 1. 读取图像
image = cv2.imread(image_path)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 2. 简单方法:使用自适应阈值或Canny边缘检测
# 方法A:Otsu阈值
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 方法B:Canny边缘检测 + 形态学操作(推荐)
edges = cv2.Canny(gray, 50, 150)
kernel = np.ones((5,5), np.uint8)
dilated = cv2.dilate(edges, kernel, iterations=2)
# 3. 找到轮廓
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 4. 创建空白的掩码图像
mask = np.zeros_like(gray)
# 5. 绘制所有轮廓(或者面积最大的几个)
for contour in contours:
area = cv2.contourArea(contour)
if area > 500: # 过滤掉小区域
cv2.drawContours(mask, [contour], -1, (255), thickness=cv2.FILLED)
# 6. 可视化结果
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.imshow(image_rgb)
plt.title("原始图像")
plt.subplot(1, 3, 2)
plt.imshow(binary, cmap='gray')
plt.title("Otsu二值化")
plt.subplot(1, 3, 3)
plt.imshow(mask, cmap='gray')
plt.title("轮廓分割结果")
plt.savefig(save_path)
plt.show()
return mask
# 使用示例
simple_scene_segmentation("/path/to/your/image.jpg")
总结与选择建议
| 方法 | 适用场景 | 精度 | 速度 | 需要GPU |
|---|---|---|---|---|
| SegFormer | 通用语义分割 | 高 | 中等 | 推荐 |
| SAM | 万物分割(无需预定义类别) | 最高 | 慢 | 必须 |
| DeepLabv3 | 实时分割、移动端 | 中 | 快 | 可选 |
| 传统方法 | 简单场景、前景背景分离 | 低 | 极快 | 不需要 |
最佳实践建议
- 如果你需要分割出特定物体类别(如道路、车辆、天空)→ 使用 SegFormer(方法一)
- 如果你想分割图像中的任意物体(无需定义类别)→ 使用 SAM(方法二)
- 如果你需要实时分割(如视频流)→ 使用 DeepLabv3+(方法三)
- 如果图像结构简单(如静止背景下的物体)→ 试用传统方法(方法四)
你可以根据自己的场景和硬件条件选择最合适的方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播