1. 项目概述:Python实现多显示器截图方案
在办公自动化和GUI测试领域,多显示器截图是个高频需求。传统截图工具往往只能捕获单个屏幕内容,而使用Python的mss模块可以轻松实现全平台多显示器截图功能。我最近在开发一个自动化报表系统时,就遇到了需要同时采集三台显示器数据的需求,mss以不到20行代码完美解决了这个问题。
mss(Multi-Screen-Shot)是一个跨平台的Python截图库,相比Pillow的ImageGrab,它最大的优势在于:
- 原生支持多显示器环境(Windows/macOS/Linux)
- 截图速度比传统方法快3-5倍
- 支持直接输出为PIL.Image或numpy数组
- 无需额外依赖OpenCV等图像处理库
2. 环境配置与基础用法
2.1 安装与基础检查
推荐使用Python 3.8+环境,通过pip安装:
bash复制pip install mss
pip install pillow # 可选,用于图像保存
验证安装是否成功:
python复制import mss
print(mss.__version__) # 应输出如6.1.0版本号
2.2 单屏幕截图基础版
python复制with mss.mss() as sct:
monitor = sct.monitors[1] # 主显示器
screenshot = sct.grab(monitor)
mss.tools.to_png(screenshot.rgb, screenshot.size, output="screen.png")
注意:monitors[0]包含所有显示器的联合区域,通常从[1]开始才是具体显示器
3. 多显示器高级应用
3.1 获取所有显示器信息
python复制def get_monitors_info():
with mss.mss() as sct:
for i, monitor in enumerate(sct.monitors[1:], 1):
print(f"显示器 {i}: {monitor['width']}x{monitor['height']} "
f"位置 ({monitor['left']}, {monitor['top']})")
输出示例:
code复制显示器 1: 1920x1080 位置 (0, 0)
显示器 2: 2560x1440 位置 (1920, -300)
3.2 全屏截图并保存
python复制import os
from datetime import datetime
def capture_all_screens():
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
os.makedirs("screenshots", exist_ok=True)
with mss.mss() as sct:
for i, monitor in enumerate(sct.monitors[1:], 1):
screenshot = sct.grab(monitor)
output = f"screenshots/monitor_{i}_{timestamp}.png"
mss.tools.to_png(screenshot.rgb, screenshot.size, output=output)
print(f"已保存: {output}")
4. 性能优化技巧
4.1 截图帧率提升方案
通过实测(i7-11800H + 双显示器环境):
python复制# 常规方式:约15fps
with mss.mss() as sct:
while True:
sct.grab(sct.monitors[1])
# 优化后:可达45fps
sct = mss.mss() # 移出循环
mon = sct.monitors[1]
try:
while True:
sct.grab(mon)
finally:
sct.close()
4.2 内存管理最佳实践
长时间运行时应定期释放资源:
python复制def safe_capture():
sct = mss.mss()
try:
for _ in range(1000):
img = sct.grab(sct.monitors[1])
process_image(img) # 自定义处理函数
del img # 显式释放内存
finally:
sct.close()
5. 常见问题解决方案
5.1 黑屏截图问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 纯黑图像 | 权限不足 | 以管理员权限运行 |
| 部分黑屏 | DPI缩放问题 | 设置DPI感知: |
python复制from ctypes import windll
windll.shcore.SetProcessDpiAwareness(2)
5.2 多显示器坐标系统
不同操作系统坐标系差异:
- Windows:主显示器左上角为(0,0),副显示器可能有负坐标
- macOS:所有显示器位于第一象限
- Linux:取决于X11/Wayland配置
获取精确区域示例:
python复制def get_active_area():
with mss.mss() as sct:
all_monitors = sct.monitors[1:]
left = min(m['left'] for m in all_monitors)
top = min(m['top'] for m in all_monitors)
right = max(m['left'] + m['width'] for m in all_monitors)
bottom = max(m['top'] + m['height'] for m in all_monitors)
return {'left': left, 'top': top, 'width': right-left, 'height': bottom-top}
6. 高级应用场景
6.1 屏幕变化检测
python复制import numpy as np
def detect_changes(threshold=10):
sct = mss.mss()
prev = np.array(sct.grab(sct.monitors[1]))
while True:
curr = np.array(sct.grab(sct.monitors[1]))
diff = np.mean(np.abs(curr - prev))
if diff > threshold:
print(f"检测到变化!差异值: {diff:.2f}")
prev = curr
6.2 与OpenCV协同工作
python复制import cv2
def video_capture(output="output.avi", fps=15):
sct = mss.mss()
monitor = sct.monitors[1]
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(output, fourcc, fps,
(monitor['width'], monitor['height']))
try:
while True:
frame = np.array(sct.grab(monitor))
frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR)
out.write(frame)
finally:
out.release()
sct.close()
在实际项目中,我发现mss与PyQt5结合使用时需要注意线程安全问题。建议在主线程初始化mss对象,或使用Qt的信号槽机制传递截图数据。对于需要高精度时间戳的场景,可以在grab()前后添加time.perf_counter()记录实际捕获时间。
