标注工具核心代码解析——load_image【canvas.py]
🏗️ 图像加载函数设计思路分析
📋 执行流程图
开始↓
🧹 清理旧场景↓
📊 加载图像数据 (numpy数组)↓
🖼️ 创建图像显示项 (Z=0, 底层)↓
🎭 创建蒙版显示项 (Z=1, 上层)↓
🎨 设置图像内容↓
📐 调整场景边界↓
👁️ 切换到查看模式↓
完成
🎯 核心设计理念
📚 分层架构:
Z=1: 蒙版层 (标注结果)
Z=0: 图像层 (原始图像)
- 🔄 数据双重存储:
-
self.image_data
(numpy) → 用于算法处理self.image_item
(QPixmap) → 用于界面显示
- 🛡️ 安全机制:
-
- 先清理 → 再加载 (避免内存泄漏)
- 加载后进入查看模式 (防止误操作)
📸 load_image
函数逐行解析
def load_image(self, image_path: str):# 🧹 清理场景:移除之前加载的所有图形项,为新图像做准备self.clear()# 🤖 【已注释】Segment Anything 相关代码# if self.mainwindow.use_segment_anything:# self.mainwindow.segany.reset_image()# 📊 图像数据处理:使用PIL读取图像并转换为numpy数组# 这样便于后续的图像处理和分析操作self.image_data = np.array(Image.open(image_path))# 🤖 【已注释】Segment Anything 图像预处理逻辑# 包含了单通道转三通道、格式验证等功能# if self.mainwindow.use_segment_anything and self.mainwindow.can_be_annotated:# if self.image_data.ndim == 3 and self.image_data.shape[-1] == 3: # 三通道图# self.mainwindow.segany.set_image(self.image_data)# elif self.image_data.ndim == 2: # 单通道图# self.image_data = self.image_data[:, :, np.newaxis]# self.image_data = np.repeat(self.image_data, 3, axis=2) # 转换为三通道# self.mainwindow.segany.set_image(self.image_data)# else:# self.mainwindow.statusbar.showMessage(# "Segment anything don't support the image with shape {} .".format(self.image_data.shape))# 🖼️ 创建图像显示项:QGraphicsPixmapItem是Qt中用于显示像素图的图形项self.image_item = QtWidgets.QGraphicsPixmapItem()# 📚 设置图层顺序:Z值决定图形项的堆叠顺序,0表示最底层# 图像作为背景层,应该在最底部self.image_item.setZValue(0)# ➕ 添加到场景:将图像项加入到QGraphicsScene中进行管理# QGraphicsScene负责管理所有图形项的位置、碰撞检测等self.addItem(self.image_item)# 🎭 创建蒙版显示项:用于显示分割结果或高亮区域self.mask_item = QtWidgets.QGraphicsPixmapItem()# 📚 蒙版层级设置:Z值为1,确保蒙版显示在图像上方# 这样标注结果可以覆盖在原图像上self.mask_item.setZValue(1)# ➕ 添加蒙版到场景self.addItem(self.mask_item)# 🎨 加载并显示图像:将图像文件转换为Qt可显示的Pixmap格式# QPixmap是Qt中优化的图像显示格式self.image_item.setPixmap(QtGui.QPixmap(image_path))# 📐 设置场景边界:根据图像的实际大小调整场景的可视范围# boundingRect()返回图像项的边界矩形,确保场景完全包含图像self.setSceneRect(self.image_item.boundingRect())# 👁️ 切换到查看模式:禁用编辑功能,进入纯浏览状态# 防止用户在图像刚加载时误操作self.change_mode_to_view()