🚀
adb経由でスクショをPythonに高速取り込み
遅延が気になってきたので見直しました。
今まで使っていた方法
adb exec-out screencap -p
で出力されるpngバイト列をホストにリダイレクトして保存し、PILやcv2で読み込んでいました。
import cv2
def screencap(fname="tmp.png"):
subprocess.run(f"adb exec-out screencap -p > {fname}", shell=True)
return cv2.imread(fname)
バイト列をメモリ上で変換して読み込む(ファイルを介さない)
np.fromstring
はwarningが出るので、np.frombuffer
に変えました。
cv2の方はpngに変換する処理をなんとかホスト側に持っていけないでしょうか?
画像のフォーマットとかよくわからないのでコピペですみません。
import cv2
import numpy as np
from PIL import Image
def screencap2cv2():
pipe = subprocess.Popen(
"adb shell screencap -p",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, shell=True)
image_bytes = pipe.stdout.read()
return cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR)
def screencap2pil(width: int, height: int):
pipe = subprocess.Popen(
"adb shell screencap",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, shell=True)
img_bytes = pipe.stdout.read()
return Image.frombuffer('RGBA', (width, height), img_bytes[12:], 'raw', 'RGBX', 0, 1)
scrcpyを経由する
少し方向性が変わってしまうのですが、adbを経由しているのは嘘ではないので載せておきます。
scrcpy
のpythonクライアントとして、比較的にメンテされているleng-yue/py-scrcpy-client
を使いました。
import scrcpy
import numpy as np
client = scrcpy.Client(device="YOUR_ANDROID_DEVICE_ID", max_fps=5)
client.start(threaded=True)
while True:
if isinstance(client.last_frame, np.ndarray):
# client.last_frame(cv2のRGB順序)をここで調理する
...
if flag_to_stop:
client.stop()
break
比較
最速は当然ですがscrcpy
です。ただ、ホストに負荷をかけないために実機を使っていることを踏まえると、scrcpy
は重量級すぎる気がします。
私の実機環境で上の2つを比べると、必要な時間は約66%早くなりました。お試しあれ。
Discussion