第一次接触街景语义分割是在去年帮朋友做智慧城市项目的时候。当时我们需要快速分析大量街拍图像中的道路、车辆和行人分布,手动标注根本不可能完成。后来发现用深度学习模型自动标注,效率直接提升了几百倍。不过每次都要写脚本处理图片实在太麻烦,这才萌生了开发可视化工具的想法。
街景语义分割的核心价值在于它能将图像中的每个像素分类。比如自动驾驶汽车需要准确识别道路边界,城市规划部门要统计不同区域的植被覆盖率,甚至外卖机器人也需要理解人行道和障碍物的位置。传统方法要么依赖人工标注(成本极高),要么使用简单的颜色识别(准确率极低)。
我设计的这个工具最大的特点就是零门槛。即使完全不懂深度学习的小白,也能通过简单点击完成专业级的图像分割。工具内置了预训练好的模型,你只需要:
记得第一次配置环境时,我踩了不少坑。比如Python版本冲突、CUDA驱动不兼容等等。后来总结出最稳定的方案是使用conda创建虚拟环境:
bash复制conda create -n seg_tool python=3.8
conda activate seg_tool
pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 -f https://download.pytorch.org/whl/torch_stable.html
pip install pillow numpy opencv-python
这里特别说明几个关键点:
+cu111后缀安装CPU版本验证安装是否成功可以运行以下测试代码:
python复制import torch
print(torch.__version__) # 应输出1.9.0
print(torch.cuda.is_available()) # 显示True表示GPU可用
很多教程只教怎么调用模型,却不解释背后的原理。这里我拆解下关键步骤:
颜色编码直接影响可视化效果。经过多次测试,我发现这些原则最实用:
python复制# 优化后的颜色映射方案
class_to_color = {
0: (128, 64, 128), # 道路 - 深紫
1: (244, 35, 232), # 人行道 - 亮粉
2: (70, 70, 70), # 建筑 - 中性灰
8: (107, 142, 35), # 植被 - 自然绿
13: (0, 0, 142) # 汽车 - 深蓝
}
加载预训练模型时要注意:
python复制def predict_image(img_path, model):
img = Image.open(img_path).convert('RGB')
original_size = img.size
# 预处理
img_tensor = transforms.ToTensor()(img)
img_tensor = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])(img_tensor)
img_tensor = img_tensor.unsqueeze(0).to(device)
# 预测+后处理
with torch.no_grad():
output = model(img_tensor)
output = F.interpolate(output, size=original_size[::-1], mode='bilinear')
pred_mask = output.argmax(1).squeeze().cpu().numpy()
return pred_mask
用Tkinter做GUI最头疼的就是布局管理。经过多个项目迭代,我总结出这套黄金布局方案:
python复制class MainWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title("街景分割神器 v1.0")
self.geometry("1200x600")
# 左侧画布 - 原始图像
self.left_canvas = tk.Canvas(self, width=512, height=512, bg='white')
self.left_canvas.pack(side=tk.LEFT, padx=20, pady=20)
# 右侧画布 - 分割结果
self.right_canvas = tk.Canvas(self, width=512, height=512, bg='white')
self.right_canvas.pack(side=tk.RIGHT, padx=20, pady=20)
# 底部控制面板
control_frame = tk.Frame(self)
control_frame.pack(side=tk.BOTTOM, fill=tk.X)
tk.Button(control_frame, text="打开图片", command=self.load_image).pack(side=tk.LEFT)
tk.Button(control_frame, text="运行分割", command=self.run_segmentation).pack(side=tk.LEFT)
tk.Button(control_frame, text="保存结果", command=self.save_result).pack(side=tk.LEFT)
直接显示高清图片会导致界面卡顿,我的解决方案是:
python复制def load_image(self):
filepath = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg *.png")])
if not filepath: return
# 异步加载
def _load():
img = Image.open(filepath)
img.thumbnail((512, 512))
self.photo = ImageTk.PhotoImage(img)
self.left_canvas.create_image(256, 256, image=self.photo)
threading.Thread(target=_load).start()
把各个模块串联起来时,要注意这些细节:
python复制class SegmentationApp:
def __init__(self):
self.model = self._load_model()
self.window = MainWindow()
self.window.protocol("WM_DELETE_WINDOW", self.on_close)
def _load_model(self):
model = torch.hub.load('pytorch/vision', 'deeplabv3_resnet101', pretrained=True)
model.eval()
return model.to(device)
def on_close(self):
torch.cuda.empty_cache()
self.window.destroy()
if __name__ == "__main__":
app = SegmentationApp()
app.window.mainloop()
最后分享一个实用技巧:在predict方法中添加进度条显示。我用的是ttk.Progressbar配合多线程,这样在处理大图时用户能看到进度,体验会好很多。