Ambilight용 Python 화면 캡처(더 적은 리소스 집약적) (Python Screen Capture for Ambilight (less resource intensive))


문제 설명

Ambilight용 Python 화면 캡처(더 적은 리소스 집약적) (Python Screen Capture for Ambilight (less resource intensive))

저는 Python으로 화면을 캡처하고 Ambilight용 데이터를 분석하기 위한 작은 스크립트를 개발 중입니다. 이미 작동하고 있지만 몇 가지 성능 문제가 있습니다.

  • YouTube를 시청하는 동안 스크립트가 CPU 리소스를 약 25%‑50% 차지합니다(현재 i5‑2410M @ fullHD, 스크립트는 i7‑ 6670k @ 4k (내 새 PC))
  • 약 11fps를 캡처할 수 있어 앰비라이트에 충분하지만 더 빨리 캡처할 수 있다면 샷과 샷 사이에 지연을 넣을 수 있습니다. 리소스 줄이기
  • 메인 모니터만 캡처됩니다. 선택할 수 있다면 좋을 것입니다.

내 스크립트:

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 Stripes가 메시지를 수신하는 RaspberryPi에 연결되어 있기 때문입니다. 성능 최적화가 있을 수 있지만 주요 문제는 PIL에 있다고 생각합니다.

다음 답변을 찾았습니다. https: //stackoverflow.com/a/23155761/5481935

이 방법이 가장 좋은 방법이라고 생각하지만 win32ui로 전체 화면을 캡처하고 부분으로 자르는 방법을 이해하지 못합니다. 저는 이제 막 파이썬을 시작하고 있습니다. 지금은 두 부분만 자르지만 화면 뒤에 디지털 LED 스트라이프를 설치하면 더 많은 부분을 캡처할 예정입니다.

독일에서 감사합니다, Johannes

편집: 대부분의 최적화는 캡처 방식에서 가능하다고 생각합니다. 또한 위에 링크한 답변이 매우 좋다고 생각하지만,


참조 솔루션

방법 1:

PIL already implements an analyze_borders like function: getbbox. Use this instead for better performance, because iterating over the rows & columns of a image in Python will be slow.

You might also want to convert the PIL image into a numpy 2D array. numpy arrays can be easily analyzed in a variety of ways. For instance, to compute the median pixel value across all rows, you would simply do numpy.median(img, axis=1).

(by jhnsJashandeep Sohi)

참조 문서

  1. Python Screen Capture for Ambilight (less resource intensive) (CC BY‑SA 2.5/3.0/4.0)

#Python #capture #winapi #Windows #screen






관련 질문

Python - 파일 이름에 특수 문자가 있는 파일의 이름을 바꿀 수 없습니다. (Python - Unable to rename a file with special characters in the file name)

구조화된 배열의 dtype을 변경하면 문자열 데이터가 0이 됩니다. (Changing dtype of structured array zeros out string data)

목록 목록의 효과적인 구현 (Effective implementation of list of lists)

for 루프를 중단하지 않고 if 문을 중지하고 다른 if에 영향을 줍니다. (Stop if statement without breaking for loop and affect other ifs)

기본 숫자를 10 ^ 9 이상으로 늘리면 코드가 작동하지 않습니다. (Code fails to work when i increase the base numbers to anything over 10 ^ 9)

사용자 지정 대화 상자 PyQT5를 닫고 데이터 가져오기 (Close and get data from a custom dialog PyQT5)

Enthought Canopy의 Python: csv 파일 조작 (Python in Enthought Canopy: manipulating csv files)

학생의 이름을 인쇄하려고 하는 것이 잘못된 것은 무엇입니까? (What is wrong with trying to print the name of the student?)

다단계 열 테이블에 부분합 열 추가 (Adding a subtotal column to a multilevel column table)

여러 함수의 변수를 다른 함수로 사용 (Use variables from multiple functions into another function)

리프 텐서의 값을 업데이트하는 적절한 방법은 무엇입니까(예: 경사하강법 업데이트 단계 중) (What's the proper way to update a leaf tensor's values (e.g. during the update step of gradient descent))

Boto3: 조직 단위의 AMI에 시작 권한을 추가하려고 하면 ParamValidationError가 발생합니다. (Boto3: trying to add launch permission to AMI for an organizational unit raises ParamValidationError)







코멘트