문제 설명
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 jhns、Jashandeep Sohi)