如何基于PySimpleGUI实现图片加载及裁剪区域测量功能
PySimpleGUI 图片选区测量与裁剪实现方案
- 优先用
Graph元素承载图片,不要用普通的Image元素。Graph原生支持鼠标按下、拖拽、抬起事件监听,还可以直接绘制半透明选区预览框,不需要额外调用底层GUI接口。 - 坐标记录逻辑
- 监听
MouseDown事件:记录鼠标按下位置为起始坐标点(x1, y1),提前计算好展示图和原图的缩放比例,后续所有展示坐标都要通过比例还原为原图实际像素坐标,避免裁剪错位。 - 监听
MouseMove事件:鼠标按住拖拽时,先删除上一帧的临时选区框,再绘制从起始点到当前鼠标位置的半透明矩形,实时预览选区范围。 - 监听
MouseUp事件:记录鼠标抬起位置为结束坐标点(x2, y2),计算得到选区的标准参数:左上角坐标(min(x1,x2), min(y1,y2))、右下角坐标(max(x1,x2), max(y1,y2))、宽度abs(x2-x1)、高度abs(y2-y1),乘以缩放比例后就是对应原图的实际参数。
- 监听
- 裁剪与参数返回逻辑
- 直接裁剪:把还原后的原图坐标传入PIL的
Image.crop()方法即可,该方法的入参格式刚好是(左, 上, 右, 下),和你计算得到的参数完全匹配。 - 返回参数:可以把计算好的坐标、宽高参数存在变量里,也可以加个确认按钮,用户确认选区后再触发参数输出或者裁剪逻辑,避免误操作。
- 直接裁剪:把还原后的原图坐标传入PIL的
核心实现示例代码
import PySimpleGUI as sg from PIL import Image # 加载原图,此处替换为你自己的图片加载逻辑 original_img = Image.open("test.png") # 自定义展示缩放比例,根据你的界面尺寸调整 scale = 0.5 display_width = int(original_img.width * scale) display_height = int(original_img.height * scale) display_img = original_img.resize((display_width, display_height)) layout = [ [sg.Graph(canvas_size=(display_width, display_height), graph_bottom_left=(0, display_height), graph_top_right=(display_width, 0), key='-GRAPH-', enable_events=True, drag_submits=True)], [sg.Button('确认裁剪', key='-CROP-'), sg.Text('选区参数:', key='-PARAM-')] ] window = sg.Window('图片选区工具', layout, finalize=True) # 将展示图绘制到Graph组件上 window['-GRAPH-'].draw_image(data=display_img.tobytes(), location=(0,0)) start_pt = None current_rect = None crop_params = None while True: event, values = window.read() if event == sg.WIN_CLOSED: break # 处理鼠标点击/拖拽事件 if event == '-GRAPH-': x, y = values['-GRAPH-'] if not start_pt: # 首次点击记录起始点 start_pt = (x, y) else: # 拖拽中更新选区预览框 if current_rect: window['-GRAPH-'].delete_figure(current_rect) current_rect = window['-GRAPH-'].draw_rectangle(start_pt, (x,y), line_color='red', fill_color='yellow', opacity=0.3) # 处理鼠标抬起事件 elif event.endswith('+UP'): end_pt = values['-GRAPH-'] x1, y1 = start_pt x2, y2 = end_pt # 转换为原图实际像素坐标 orig_x1 = int(min(x1, x2) / scale) orig_y1 = int(min(y1, y2) / scale) orig_x2 = int(max(x1, x2) / scale) orig_y2 = int(max(y1, y2) / scale) crop_params = (orig_x1, orig_y1, orig_x2, orig_y2) # 展示选区参数 window['-PARAM-'].update(f'选区参数:左={orig_x1}, 上={orig_y1}, 右={orig_x2}, 下={orig_y2}, 宽={orig_x2-orig_x1}, 高={orig_y2-orig_y1}') start_pt = None current_rect = None # 处理裁剪请求 elif event == '-CROP-' and crop_params: cropped_img = original_img.crop(crop_params) # 此处可添加裁剪后图片的保存、展示逻辑 cropped_img.save('cropped_result.png') window.close()
提示:如果你的界面加了滚动条适配大尺寸图片,坐标计算时需要额外加上滚动条的偏移量,否则选区坐标会出现偏移。
内容的提问来源于stack exchange,提问作者katherinekelly2012
相关产品推荐
相关产品推荐

