CustomTkinter+cv2实现图像矩形标注 修复仅绘制线条问题
问题根因
当前代码实现的是自由手绘逻辑,根本没写矩形框选的对应逻辑,具体问题点:
- 画布层:鼠标拖动事件
<B1-Motion>里持续调用create_line逐段拼接鼠标移动路径,最终呈现的就是手绘线条,没有任何矩形绘制逻辑。 - OpenCV图像层:拖动过程中反复以上一次鼠标瞬时位置、当前鼠标瞬时位置为对角点绘制极小的矩形,没有做预览刷新,所有小矩形沿鼠标路径堆叠后视觉上和线条一致,不是从按下起点到当前位置的完整选框。
- 事件缺失:没有绑定鼠标左键释放事件,无法确定矩形选框的终点,也没有临时预览图形的清除逻辑,拖动时会产生大量拖影残留。
修复方案
把绘制逻辑改成标准矩形框选流程:鼠标按下记录起点、拖动时实时刷新矩形预览、鼠标释放时确定最终选框并同步绘制到OpenCV图像用于后续保存,核心修改代码如下:
- 替换原有的事件绑定逻辑,补充鼠标释放事件绑定
def draw_action(self): self.color_code = ((255, 0, 0), '#ff0000') self.refresh_side_frame() # 绑定矩形绘制对应事件 self.canvas.bind('<ButtonPress-1>', self.start_draw) self.canvas.bind('<B1-Motion>', self.draw_preview) self.canvas.bind('<ButtonRelease-1>', self.finish_draw) self.draw_color_button = ttk.Button(self.side_frame, text='Pick A Color', command=self.choose_color) self.draw_color_button.grid(row=0, column=2, padx=5, pady=5, sticky='sw')
- 重写鼠标按下回调,记录矩形起点
def start_draw(self, event): # 记录选框起点坐标 self.rect_start_x = event.x self.rect_start_y = event.y self.temp_rect_id = None # 存储临时预览矩形的画布ID,用于拖动时刷新
- 替换原有的逐段画线逻辑,实现拖动时的矩形实时预览
def draw_preview(self, event): # 先删除上一帧的临时预览,避免拖影 if self.temp_rect_id is not None: self.canvas.delete(self.temp_rect_id) # 以起点和当前鼠标位置为对角点,绘制新的临时预览矩形 self.temp_rect_id = self.canvas.create_rectangle( self.rect_start_x, self.rect_start_y, event.x, event.y, width=2, outline=self.color_code[-1], dash=(4, 2) # 虚线显示预览状态,和最终确定的选框做区分 )
- 新增鼠标释放回调,确定最终选框并同步到OpenCV图像
def finish_draw(self, event): # 清除最后一帧临时预览 if self.temp_rect_id is not None: self.canvas.delete(self.temp_rect_id) rect_end_x, rect_end_y = event.x, event.y # 在画布上绘制最终确定的标注矩形 self.canvas.create_rectangle( self.rect_start_x, self.rect_start_y, rect_end_x, rect_end_y, width=2, outline=self.color_code[-1] ) # 坐标换算后将矩形同步绘制到OpenCV格式的源图,用于后续保存 cv2.rectangle( self.filtered_image, (int(self.rect_start_x * self.ratio), int(self.rect_start_y * self.ratio)), (int(rect_end_x * self.ratio), int(rect_end_y * self.ratio)), self.color_code[0], # 用用户选择的颜色,替换原代码写死的绿色 thickness=int(self.ratio * 2), lineType=8 )
补充说明
- 原代码中
prev_action、next_action方法内错误调用了颜色选择器,记得替换为上一张/下一张图片的切换逻辑,否则切换图片时会异常弹出取色窗口。 - 如果需要实现撤销功能,可将每次绘制的矩形画布ID、对应坐标存入列表,撤销时删除画布对应元素,同时将
self.filtered_image恢复到绘制前的状态即可。 - 标注完成后直接调用
cv2.imwrite(保存路径, self.filtered_image)即可导出带矩形标注的图像文件。
内容的提问来源于stack exchange,提问作者Suraj Kumar
相关产品推荐
相关产品推荐

