在 Windows 上使用 Python 进行区域选择和屏幕捕获

wei*_*fan 6 windows python-3.x

如何在 Windows 上使用 python 3 创建和获取基本选择框的坐标?我需要它在屏幕/任何窗口的任何地方工作。例如,理想情况下你运行程序,然后无论你点击/按住/拖动,都会出现一个半透明的浅蓝色框,python 将注册坐标(它需要保存以备后用)。

我正在创建一个桌面工具,允许您选择屏幕的某些部分,类似于Capture2Text的区域选择的工作方式。它应该允许您选择视频游戏屏幕的一个区域(即显示的任何内容,无论是什么程序,无论是浏览器、蒸汽还是模拟器)。然后它会以某种方式截取屏幕截图,在获得所需坐标后可能使用 PIL 或 PyAutoGUI。

所以,我坚持区域选择步骤。我已经使用 OpenCV、Matplotlib、pygame、tkiner 和 Qt 遇到了可能的解决方案,但前两个只能在指定的窗口中工作,我不知道后两个是否一般在屏幕上工作(我是不打算尝试了解所有这些不同的库,而不知道我是否在正确的轨道上,或者这是否可能)。我什至不知道哪个对我的用例来说最简单,或者哪些库允许这种通用功能。

这是基于我发现的另一个 SO 答案的随机尝试,但它仅适用于预先保存的图像。

#ref(best?):/sf/ask/484123811/
import numpy as np
from PIL import Image
import matplotlib.widgets as widgets


def onselect(eclick, erelease):
    if eclick.ydata>erelease.ydata:
        eclick.ydata,erelease.ydata=erelease.ydata,eclick.ydata
    if eclick.xdata>erelease.xdata:
        eclick.xdata,erelease.xdata=erelease.xdata,eclick.xdata
    ax.set_ylim(erelease.ydata,eclick.ydata)
    ax.set_xlim(eclick.xdata,erelease.xdata)
    fig.canvas.draw()

fig = plt.figure()
ax = fig.add_subplot(111)
filename="test.jpg"
im = Image.open(filename)
arr = np.asarray(im)
plt_image=plt.imshow(arr)
rs=widgets.RectangleSelector(
    ax, onselect, drawtype='box',
    rectprops = dict(facecolor='blue', edgecolor = 'black', alpha=0.5, fill=True))
plt.show()
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种直接在屏幕上工作而不需要提前截取屏幕截图的解决方案,因为我的应用程序应该与您正在玩的游戏一起使用而不会中断。

这只是我的应用程序所做的第一步(从用户的角度来看),我已经实现了之后发生的大部分事情(现在大约 3000 LoC),所以我正在寻找最直接的实现方式这样我就可以结束项目并使其可用。

Ame*_*hel 6

(免责声明:我现在无法测试示例。如果有一些错误,请告诉我修复它们)

您想要实现的目标是特定于操作系统的

  • 要访问屏幕资源,请使用pywin32参考) Win32 API的 Python 扩展。
  • 要处理鼠标请使用PyHook库,它是Windows Hooking API中的钩子包装器。

获取屏幕截图区域(来源):

import win32gui
import win32ui
import win32con
import win32api

def saveScreenShot(x,y,width,height,path):
    # grab a handle to the main desktop window
    hdesktop = win32gui.GetDesktopWindow()

    # create a device context
    desktop_dc = win32gui.GetWindowDC(hdesktop)
    img_dc = win32ui.CreateDCFromHandle(desktop_dc)

    # create a memory based device context
    mem_dc = img_dc.CreateCompatibleDC()

    # create a bitmap object
    screenshot = win32ui.CreateBitmap()
    screenshot.CreateCompatibleBitmap(img_dc, width, height)
    mem_dc.SelectObject(screenshot)


    # copy the screen into our memory device context
    mem_dc.BitBlt((0, 0), (width, height), img_dc, (x, y),win32con.SRCCOPY)

    # save the bitmap to a file
    screenshot.SaveBitmapFile(mem_dc, path)
    # free our objects
    mem_dc.DeleteDC()
    win32gui.DeleteObject(screenshot.GetHandle())
Run Code Online (Sandbox Code Playgroud)

处理鼠标事件:

# Callback function when the event is fired
def onMouseDown(event):
    # Here, the beginning of your rectangle drawing
    # [...]

# Subscribe the event to the callback:
hm = pyHook.HookManager()
hm.SubscribeMouseAllButtonsDown(onMouseDown)
Run Code Online (Sandbox Code Playgroud)

最后要绘制一个矩形选区,您可能必须这样处理:

  1. 按下鼠标按钮时,将坐标存储为第一条边
  2. 鼠标移动时,使用坐标作为第二条边更新矩形选择
  3. 松开鼠标按钮时,存储第二条边
  4. 处理捕获

绘制矩形的棘手部分是恢复先前绘制矩形的像素。我看到两种方法:

  • 在绘制矩形之前,将覆盖的像素存储在内存中;在绘制下一个矩形之前,您需要恢复之前的像素,依此类推。
  • 您绘制矩形,在其像素和要覆盖的像素之间执行XOR运算;在绘制下一个矩形之前,您可以使用 XOR 运算再次重新绘制前一个矩形。XOR 是一种逻辑运算,如果与另一个值应用两次,它会恢复一个值。

使用 XOR 运算绘制矩形的最简单方法是DrawFocusRect()

为了解决更多问题,请记住 pywin32包装了Win32 API。您可以在此范围内搜索以执行某些操作。