import cv2
import numpy as np
from PIL import Image
from win32api import GetSystemMetrics
import ctypes
import os
import time
# 定义BITMAPINFOHEADER的结构
class BITMAPINFOHEADER(ctypes.Structure):
_fields_ = [
('biSize', ctypes.c_ulong),
('biWidth', ctypes.c_long),
('biHeight', ctypes.c_long),
('biPlanes', ctypes.c_ushort),
('biBitCount', ctypes.c_ushort),
('biCompression', ctypes.c_ulong),
('biSizeImage', ctypes.c_ulong),
('biXPelsPerMeter', ctypes.c_long),
('biYPelsPerMeter', ctypes.c_long),
('biClrUsed', ctypes.c_ulong),
('biClrImportant', ctypes.c_ulong)
]
class ScreenCapture:
def __init__(self, output_dir='screenshots', use_key_frame_detection=True, threshold=100000):
"""初始化函数,设定是否使用关键帧检测以及阈值和保存图片的目录"""
self.output_dir = output_dir
self.use_key_frame_detection = use_key_frame_detection
self.threshold = threshold
self.last_image = None
if not os.path.exists(self.output_dir):
os.makedirs(self.output_dir)
def capture(self):
"""使用win32api和ctypes捕捉屏幕内容"""
width = GetSystemMetrics(0)
height = GetSystemMetrics(1)
hwin = ctypes.windll.user32.GetDesktopWindow()
hwindc = ctypes.windll.user32.GetWindowDC(hwin)
srcdc = ctypes.windll.gdi32.CreateCompatibleDC(hwindc)
srcbmp = ctypes.windll.gdi32.CreateCompatibleBitmap(hwindc, width, height)
ctypes.windll.gdi32.SelectObject(srcdc, srcbmp)
ctypes.windll.gdi32.BitBlt(srcdc, 0, 0, width, height, hwindc, 0, 0, 0x00CC0020)
bmpinfo = BITMAPINFOHEADER()
bmpinfo.biSize = ctypes.sizeof(BITMAPINFOHEADER)
bmpinfo.biWidth = width
bmpinfo.biHeight = height
bmpinfo.biPlanes = 1 # must be 1
bmpinfo.biBitCount = 32 # 4 bytes per pixel
bmpinfo.biCompression = 0 # BI_RGB, no compression
bmpinfo.biSizeImage = width * height * 4 # size of the image in bytes
bmpstr = ctypes.create_string_buffer(bmpinfo.biSizeImage)
ctypes.windll.gdi32.GetDIBits(srcdc, srcbmp, 0, height, bmpstr, ctypes.byref(bmpinfo), 0)
ctypes.windll.gdi32.DeleteObject(srcbmp)
ctypes.windll.user32.ReleaseDC(hwin, hwindc)
ctypes.windll.gdi32.DeleteDC(srcdc)
image = Image.frombuffer(
'RGB',
(bmpinfo.biWidth, bmpinfo.biHeight),
bmpstr,
'raw',
'BGRX',
0,
-1
)
image = cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB)
return np.array(image)
def capture_and_check_changes(self):
"""捕获屏幕并检查是否与上一个图像有显著的差异"""
current_image = self.capture()
if self.last_image is None:
self.last_image = current_image
return current_image, True
diff = cv2.absdiff(self.last_image, current_image)
gray_diff = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
has_changes = cv2.countNonZero(gray_diff) > self.threshold
return current_image, has_changes
def save_image(self, image):
"""保存图片"""
cv2.imwrite(f'{self.output_dir}/screenshot_{time.time()}.png', image)
def start_capture(self):
"""执行一次捕获并判断是否需要保存的过程"""
current_image, has_changes = self.capture_and_check_changes()
if not self.use_key_frame_detection or has_changes:
self.save_image(current_image)
self.last_image = current_image
# 使用示例:
# 创建ScreenCapture对象,并指定是否使用关键帧检测,以及阈值
capturer = ScreenCapture(output_dir='screenshots', use_key_frame_detection=True, threshold=100000)
# 执行一次捕获并判断是否需要保存的过程
while(True):
capturer.start_capture()