流光溢彩的Python屏幕截图(资源消耗较少)

时间:2015-11-28 14:09:26

标签: python windows winapi screen capture

我只是用Python开发一个用于屏幕捕获的小脚本并分析流光溢彩的数据。它已经运行,但我遇到了一些性能问题:

  • 我的脚本在观看youtube时占用了大约25%-50%的CPU资源(当前i5-2410M @ fullHD,脚本应针对i7-6670k @ 4k(我的新电脑)优化)
  • 我能够捕获大约11 fps,这对于流光溢彩来说足够了,但是如果我能够更快地捕获,我可以在镜头之间放置延迟并减少资源
  • 只有主监视器被捕获,如果可以选择的话会很棒。

我的剧本:

import time
import asyncio
import websockets
from PIL import ImageGrab
from PIL import ImageStat
from PIL import ImageEnhance

# Analyzing the image and deleting black borders from movies (21:9 or 4:3)
def analyze_borders(debug=False):
    min_size = 3
    im = ImageGrab.grab()
    width, height = im.size
    box = []
    for x in range(0, height):
        # check top
        line = im.crop((0, x, width, x + 1))
        if debug:
            print("TOP", ImageStat.Stat(line).median)
        if ImageStat.Stat(line).median > [1, 1, 1]:
            box.append(x)
            break
        if x >= height / min_size:
            box.append(int(height / min_size))
            break
    for x in range(height, 0, -1):
        # check bottom
        line = im.crop((0, x, width, x + 1))
        if debug:
            print("BOTTOM", ImageStat.Stat(line).median)
        if ImageStat.Stat(line).median > [1, 1, 1]:
            box.append(height - x - 1)
            break
        if x <= height / min_size:
            box.append(int(height / min_size))
            break
    for x in range(0, width):
        # check left
        line = im.crop((x, 0, x + 1, height))
        if debug:
            print("LEFT", ImageStat.Stat(line).median)
        if ImageStat.Stat(line).median > [1, 1, 1]:
            box.append(x)
            break
        if x >= width / min_size:
            box.append(int(width / min_size))
            break
    for x in range(width, 0, -1):
        # check right
        line = im.crop((x, 0, x + 1, height))
        if debug:
            print("RIGHT", ImageStat.Stat(line).median)
        if ImageStat.Stat(line).median > [1, 1, 1]:
            box.append(width - x - 1)
            break
        if x <= width / min_size:
            box.append(int(width / min_size))
            break
    return box


def capture():
    return ImageGrab.grab()


@asyncio.coroutine
def start():
    time1 = time.time()
    websocket = yield from websockets.connect('ws://localhost:8887/')
    for x in range(0, 1000):
        im = capture()
        im = ImageEnhance.Color(im).enhance(1)
        im = ImageEnhance.Contrast(im).enhance(1)
        box = [0, 0, 0, 0]
        if x % 100 == 0:
            box = analyze_borders()
            print(box)
        w, h = im.size
        im = im.crop((box[2], box[0], w - box[3], h - box[1]))
        w, h = im.size
        im1 = im.crop((0, 0, int(w / 2), h))
        im2 = im.crop((int(w / 2), 0, w, h))
        stat1 = ImageStat.Stat(im1)
        stat2 = ImageStat.Stat(im2)
        # print(str(x) + " Median1: " + str(stat1.median))
        # print(str(x) + " Median2: " + str(stat2.median))
        yield from websocket.send(str("C1:(" + str(stat1.median[0]) +
                                      ", " + str(stat1.median[1]) +
                                      ", " + str(stat1.median[2]) + ")"))
        yield from websocket.send(str("C2:(" + str(stat2.median[0]) +
                                      ", " + str(stat2.median[1]) +
                                      ", " + str(stat2.median[2]) + ")"))
    yield from websocket.close()
    duration = time.time() - time1
    print(str(duration))
    print(str(1000 / duration))


asyncio.get_event_loop().run_until_complete(start())

Websocket部分是因为我的LED条纹连接到接收消息的RaspberryPi。可能会有一些性能优化,但我认为主要问题在于PIL。

我找到了这个答案:https://stackoverflow.com/a/23155761/5481935

我认为这是最好的方法,但我不明白如何使用win32ui捕获整个屏幕并将其裁剪成部分因为我刚刚开始使用python。目前我只裁剪了两个部件,但只要我的数字LED条纹安装在我的屏幕后面,我就会捕获更多部件。

感谢德国, 约翰内斯

编辑:我认为捕获方法可以进行大多数优化。另外我认为上面链接的答案非常好,但我不明白如何将上面的答案与我的代码联系起来:那么如何用win32ui捕获整个屏幕并像我的代码一样处理结果或转换它到PIL图像?

1 个答案:

答案 0 :(得分:0)

PIL已经实现了analyze_borders之类的功能:getbbox。使用它代替更好的性能,因为迭代行和&amp; Python中的图像列将很慢。

您可能还想将PIL图像转换为numpy 2D阵列。可以通过各种方式轻松分析numpy个数组。例如,要计算所有行的中值像素值,您只需执行numpy.median(img, axis=1)