用OpenCV和Python打造你的简易“QQ截图”工具:鼠标交互式绘图实战

张开发
2026/4/28 12:19:32 15 分钟阅读

分享文章

用OpenCV和Python打造你的简易“QQ截图”工具:鼠标交互式绘图实战
用OpenCV和Python打造你的简易“QQ截图”工具鼠标交互式绘图实战每次需要快速截取屏幕上的某个区域时你是否厌倦了那些臃肿的截图工具作为Python开发者我们完全可以用OpenCV打造一个轻量级的截图工具既能学习计算机视觉基础知识又能获得一个实用的工具。本文将带你从零开始实现一个支持矩形框选、实时预览和撤销功能的截图工具。1. 环境准备与基础概念在开始编码之前我们需要确保开发环境准备就绪。推荐使用Python 3.8版本和OpenCV 4.x版本可以通过以下命令安装pip install opencv-python numpyOpenCV的鼠标事件处理基于回调机制核心函数是cv2.setMouseCallback()。这个函数允许我们将自定义的回调函数绑定到特定窗口的鼠标事件上。回调函数的基本结构如下def mouse_callback(event, x, y, flags, param): # event: 鼠标事件类型移动、点击等 # x, y: 当前鼠标坐标 # flags: 事件标志如是否按下Ctrl键 # param: 用户自定义参数 pass鼠标事件类型包括cv2.EVENT_MOUSEMOVE: 鼠标移动cv2.EVENT_LBUTTONDOWN: 左键按下cv2.EVENT_LBUTTONUP: 左键释放cv2.EVENT_RBUTTONDOWN: 右键按下理解这些基础概念后我们就可以开始构建截图工具的核心逻辑了。2. 实现基本矩形框选功能QQ截图的核心功能是通过鼠标拖拽绘制矩形框。我们需要跟踪鼠标的三个状态按下、移动和释放。下面是实现这一功能的关键代码import cv2 import numpy as np # 初始化全局变量 drawing False # 标记是否正在绘制 start_point (-1, -1) # 矩形起点 current_point (-1, -1) # 当前鼠标位置 image None # 原始图像 temp_image None # 临时图像用于实时预览 def mouse_callback(event, x, y, flags, param): global drawing, start_point, current_point, image, temp_image if event cv2.EVENT_LBUTTONDOWN: drawing True start_point (x, y) current_point (x, y) temp_image image.copy() elif event cv2.EVENT_MOUSEMOVE: if drawing: current_point (x, y) # 在临时图像上绘制实时预览 temp_image image.copy() cv2.rectangle(temp_image, start_point, current_point, (0, 255, 0), 2) elif event cv2.EVENT_LBUTTONUP: drawing False current_point (x, y) # 在原始图像上绘制最终矩形 cv2.rectangle(image, start_point, current_point, (0, 0, 255), 2) temp_image None # 创建黑色背景图像 image np.zeros((500, 800, 3), dtypenp.uint8) cv2.namedWindow(Screenshot Tool) cv2.setMouseCallback(Screenshot Tool, mouse_callback) while True: # 显示当前图像优先显示临时预览 display_image temp_image if temp_image is not None else image cv2.imshow(Screenshot Tool, display_image) key cv2.waitKey(1) 0xFF if key 27: # ESC键退出 break cv2.destroyAllWindows()这段代码实现了基本的矩形框选功能包括左键按下时开始绘制鼠标移动时显示实时预览左键释放时完成绘制3. 增强功能撤销操作与多矩形支持一个实用的截图工具应该支持撤销操作和同时绘制多个矩形。我们可以通过维护一个绘制历史列表来实现这些功能import cv2 import numpy as np # 初始化全局变量 drawing False start_point (-1, -1) current_point (-1, -1) image None temp_image None history [] # 绘制历史 def mouse_callback(event, x, y, flags, param): global drawing, start_point, current_point, image, temp_image, history if event cv2.EVENT_LBUTTONDOWN: drawing True start_point (x, y) current_point (x, y) temp_image image.copy() # 在临时图像上绘制历史矩形 for rect in history: cv2.rectangle(temp_image, rect[0], rect[1], rect[2], rect[3]) elif event cv2.EVENT_MOUSEMOVE: if drawing: current_point (x, y) temp_image image.copy() # 绘制历史矩形 for rect in history: cv2.rectangle(temp_image, rect[0], rect[1], rect[2], rect[3]) # 绘制当前预览矩形 cv2.rectangle(temp_image, start_point, current_point, (0, 255, 0), 2) elif event cv2.EVENT_LBUTTONUP: drawing False current_point (x, y) # 将当前矩形加入历史 history.append((start_point, current_point, (0, 0, 255), 2)) temp_image None # 创建黑色背景图像 image np.zeros((500, 800, 3), dtypenp.uint8) cv2.namedWindow(Screenshot Tool) cv2.setMouseCallback(Screenshot Tool, mouse_callback) while True: display_image temp_image if temp_image is not None else image.copy() # 在显示图像上绘制所有历史矩形 for rect in history: cv2.rectangle(display_image, rect[0], rect[1], rect[2], rect[3]) cv2.imshow(Screenshot Tool, display_image) key cv2.waitKey(1) 0xFF if key 27: # ESC键退出 break elif key ord(u): # u键撤销 if history: history.pop() cv2.destroyAllWindows()现在我们的工具支持按u键撤销上一次绘制同时显示多个矩形框保持历史绘制结果4. 高级功能屏幕截图与保存真正的截图工具需要能够捕获屏幕内容并保存选区。我们可以使用pyautogui库来捕获屏幕然后在此基础上实现截图功能import cv2 import numpy as np import pyautogui from datetime import datetime # 初始化全局变量 drawing False start_point (-1, -1) current_point (-1, -1) screen None # 屏幕截图 temp_image None history [] def capture_screen(): 捕获整个屏幕 global screen # 使用pyautogui捕获屏幕 screenshot pyautogui.screenshot() # 转换为OpenCV格式 screen cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR) return screen.copy() def mouse_callback(event, x, y, flags, param): global drawing, start_point, current_point, temp_image, history if event cv2.EVENT_LBUTTONDOWN: drawing True start_point (x, y) current_point (x, y) temp_image screen.copy() # 绘制历史选区 for rect in history: cv2.rectangle(temp_image, rect[0], rect[1], rect[2], rect[3]) elif event cv2.EVENT_MOUSEMOVE: if drawing: current_point (x, y) temp_image screen.copy() # 绘制历史选区 for rect in history: cv2.rectangle(temp_image, rect[0], rect[1], rect[2], rect[3]) # 绘制当前预览 cv2.rectangle(temp_image, start_point, current_point, (0, 255, 0), 2) elif event cv2.EVENT_LBUTTONUP: drawing False current_point (x, y) # 保存当前选区 history.append((start_point, current_point, (0, 0, 255), 2)) temp_image None # 自动保存选区 save_selection(start_point, current_point) def save_selection(pt1, pt2): 保存选区图像 x1, y1 pt1 x2, y2 pt2 # 确保x1,y1是左上角x2,y2是右下角 x1, x2 min(x1, x2), max(x1, x2) y1, y2 min(y1, y2), max(y1, y2) # 截取选区 selection screen[y1:y2, x1:x2] if selection.size 0: timestamp datetime.now().strftime(%Y%m%d_%H%M%S) filename fscreenshot_{timestamp}.png cv2.imwrite(filename, selection) print(fSaved selection to {filename}) # 首次捕获屏幕 capture_screen() cv2.namedWindow(Screenshot Tool, cv2.WINDOW_NORMAL) cv2.setMouseCallback(Screenshot Tool, mouse_callback) while True: display_image temp_image if temp_image is not None else screen.copy() # 绘制历史选区 for rect in history: cv2.rectangle(display_image, rect[0], rect[1], rect[2], rect[3]) cv2.imshow(Screenshot Tool, display_image) key cv2.waitKey(1) 0xFF if key 27: # ESC键退出 break elif key ord(u): # u键撤销 if history: history.pop() elif key ord(r): # r键刷新屏幕 capture_screen() cv2.destroyAllWindows()这个增强版工具新增了以下功能按r键刷新屏幕截图自动保存选区图像到文件支持全屏截图基础上的区域选择5. 界面美化与用户体验优化为了让我们的截图工具更加专业我们可以添加一些界面元素和交互改进def draw_ui(image, drawing_mode): 绘制用户界面元素 # 添加状态信息 status Drawing if drawing_mode else Ready cv2.putText(image, fStatus: {status}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) # 添加帮助信息 help_text ESC:Exit U:Undo R:Refresh S:Save cv2.putText(image, help_text, (10, image.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1) # 添加半透明背景提升文字可读性 overlay image.copy() cv2.rectangle(overlay, (0, 0), (300, 50), (0, 0, 0), -1) cv2.rectangle(overlay, (0, image.shape[0]-30), (image.shape[1], image.shape[0]), (0, 0, 0), -1) cv2.addWeighted(overlay, 0.5, image, 0.5, 0, image) def mouse_callback(event, x, y, flags, param): # ... (之前的回调函数代码保持不变) # 在显示图像前调用draw_ui draw_ui(display_image, drawing)此外我们还可以添加以下改进支持调整矩形边框粗细和颜色添加网格线辅助对齐实现选区拖动功能添加放大镜功能精确选择这些改进虽然会增加代码复杂度但会显著提升工具的专业性和易用性。

更多文章