使用 OpenCV 和 Python-2.7 进行屏幕截图

Posted

技术标签:

【中文标题】使用 OpenCV 和 Python-2.7 进行屏幕截图【英文标题】:Screen Capture with OpenCV and Python-2.7 【发布时间】:2014-07-30 12:33:18 【问题描述】:

我正在使用 Python 2.7OpenCV 2.4.9

我需要捕获当前显示给用户的帧,并将其作为 Python 中的 cv::Mat 对象加载。

你们知道递归的快速方法吗?

我需要像下面示例中所做的那样,递归地从网络摄像头捕获 Mat 帧:

import cv2

cap = cv2.VideoCapture(0)
while(cap.isOpened()):
    ret, frame = cap.read()
    cv2.imshow('WindowName', frame)
    if cv2.waitKey(25) & 0xFF == ord('q'):
        cap.release()
        cv2.destroyAllWindows()
        break

在示例中,它使用了 VideoCapture 类来处理从网络摄像头捕获的图像。

使用 VideoCapture.read() 始终会读取新帧并将其存储到 Mat 对象中。

我可以将 “printscreens 流” 加载到 VideoCapture 对象中吗?我可以在 Python 中使用 OpenCV 创建计算机屏幕的流式传输,而无需每秒保存和删除大量 .bmp 文件吗?

我需要这些帧是 Mat 对象或 NumPy 数组,所以我可以执行一些计算机视觉具有此帧的实时例程。

【问题讨论】:

很难说你的问题到底是什么。您能否编辑您的问题以准确说明它是什么?例如,“递归”是什么意思? frame 已经包含图像。为什么不直接使用呢? @Aurelius 据我了解,他只是在寻找一种将打印屏幕作为帧而不是来自网络摄像头的图像注入的方法。由于监视器不包含在cv2.VideoCapture获取的设备列表中,您只需从其他地方抓取打印屏幕,例如PIL Image.Imagegrab.grab(),将其转换为numpy数组,然后注入在上面显示为框架的代码中... 【参考方案1】:

这是我使用@Raoul 提示编写的解决方案代码。

我使用 PIL ImageGrab 模块来抓取打印屏幕帧。

import numpy as np
from PIL import ImageGrab
import cv2

while(True):
    printscreen_pil =  ImageGrab.grab()
    printscreen_numpy =   np.array(printscreen_pil.getdata(),dtype='uint8')\
    .reshape((printscreen_pil.size[1],printscreen_pil.size[0],3)) 
    cv2.imshow('window',printscreen_numpy)
    if cv2.waitKey(25) & 0xFF == ord('q'):
        cv2.destroyAllWindows()
        break

【讨论】:

当使用这个解决方案时,我得到了 uint8 未定义的错误。用单引号将其包裹为 'uint8' 都开始起作用了。 你为什么要做 .reshape() 以及它是如何工作的?文档有点难以理解。我得到“ValueError:新数组的总大小必须保持不变” @jsleuth 对不起,我的错,你可以使用 dtype = numpy.uint8 @andii Reshape 是对象 numpy.ndarray 的一种方法。我重新调整了数组的形状,因为图像是一个矩阵 (n,m),具有 n 行和 m 列。我正在使用 reshape 方法将扁平数组转换为矩阵 (n,m)。 如果我将np.array(printscreen_pil.getdata(), dtype=uint8) 更改为np.array(printscreen_pil, dtype=uint8),速度(帧率)将提高近100 倍。【参考方案2】:

我在使用其他解决方案时遇到帧率问题,mss 解决了。

import numpy as np
import cv2
from mss import mss
from PIL import Image

mon = 'top': 160, 'left': 160, 'width': 200, 'height': 200

sct = mss()

while 1:
    sct.get_pixels(mon)
    img = Image.frombytes('RGB', (sct.width, sct.height), sct.image)
    cv2.imshow('test', np.array(img))
    if cv2.waitKey(25) & 0xFF == ord('q'):
        cv2.destroyAllWindows()
        break

【讨论】:

我的帧速率从使用 PIL ImageGrab 的 0.8 秒变为使用 mss 的 0.06 秒,谢谢先生! 默认 pip install mss 将安装 MSS 没有属性 get_pixels 的最新版本。需要pip install mss==2.0.22 sct.get_pixels() 才能工作。 看我的回答最新版mss【参考方案3】:

这是@Neabfi 的答案的更新答案

import time

import cv2
import numpy as np
from mss import mss

mon = 'top': 160, 'left': 160, 'width': 200, 'height': 200
with mss() as sct:
    # mon = sct.monitors[0]
    while True:
        last_time = time.time()
        img = sct.grab(mon)
        print('fps: 0'.format(1 / (time.time()-last_time)))
        cv2.imw('test', np.array(img))
        if cv2.waitKey(25) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            break

并保存为 mp4 视频

import time

import cv2
import numpy as np
from mss import mss


def record(name):
    with mss() as sct:
        # mon = 'top': 160, 'left': 160, 'width': 200, 'height': 200
        mon = sct.monitors[0]
        name = name + '.mp4'
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
        desired_fps = 30.0
        out = cv2.VideoWriter(name, fourcc, desired_fps,
                              (mon['width'], mon['height']))
        last_time = 0
        while True:
            img = sct.grab(mon)
            # cv2.imshow('test', np.array(img))
            if time.time() - last_time > 1./desired_fps:
                last_time = time.time()
                destRGB = cv2.cvtColor(np.array(img), cv2.COLOR_BGRA2BGR)
                out.write(destRGB)
            if cv2.waitKey(25) & 0xFF == ord('q'):
                cv2.destroyAllWindows()
                break


record("Video")

【讨论】:

【参考方案4】:

这是 Python 3 的实现

此函数在正在运行的应用程序列表中查找应用程序:

def capture_dynamic():
    toplist, winlist = [], []
    
    def enum_cb(hwnd, results):
        winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
        
    win32gui.EnumWindows(enum_cb, toplist)

    wnd = [(hwnd, title) for hwnd, title in winlist if 'spotify' in title.lower()]

    if wnd:
        wnd = wnd[0]
        hwnd = wnd[0]

        bbox = win32gui.GetWindowRect(hwnd)
        img = ImageGrab.grab(bbox)
        return img
    else:
        return None

此功能显示图像直到按下字母“q”:

import cv2
import numpy as np

while(True):
#   Dynamic Version
    screen_grab =  capture_dynamic()
    
    if(screen_grab == None):
        print("No Window Found! Please Try Again")
        break
        
    screen_grab = np.array(screen_grab)
    cv2.imshow('window',cv2.cvtColor(screen_grab, cv2.COLOR_BGR2RGB))
    
    if cv2.waitKey(25) & 0xFF == ord('q'):
        cv2.destroyAllWindows()
        break

确保您要捕获的应用程序应位于前台,而不是任何其他应用程序的后面

请点赞!

【讨论】:

以上是关于使用 OpenCV 和 Python-2.7 进行屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章

虚拟环境上的 Opencv3 和 Python 2.7 - AttributeError:“模块”对象没有属性“createLBPHFaceRecognizer”

有没有人在 MacOS 10.6 上使用过 OpenCV 与 Python 2.7 一起工作?

Python OpenCV:Python 2.7 到 Python 3.5 之间的 VideoCapture 差异

在 MAC 上为 python 2.7 安装 opencv

无法在 Windows 7 机器中使用 OpenCV 2.4.3、Python 2.7 打开“.mp4”视频文件

Python 2.7 Opencv 错误,ImportError: DLL load failed: 找不到指定的模块