You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python调用adb截屏的代码效率优化问题咨询

优化ADB循环截屏的内存与效率方案

一、解决单次循环创建Popen的内存开销问题

你最初的代码每次循环都启动新的adb进程,频繁的进程创建与销毁会带来额外的内存波动和性能开销,尤其高频循环时问题更明显。最优方案是保持单个adb进程长连接,复用进程而非每次重启。

优化后的代码(保存帧图片)

import subprocess
from time import sleep

# 启动单个adb交互进程,维持长连接
adb_process = subprocess.Popen(
    ['adb', 'shell'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    bufsize=0  # 无缓冲,确保实时读取输出
)

FRAME_COUNT = 0
while True:
    # 向adb进程发送截屏命令
    adb_process.stdin.write(b'screencap -p\n')
    adb_process.stdin.flush()
    
    # 读取截屏的PNG数据(截断adb shell的提示符)
    png_data = b''
    while True:
        chunk = adb_process.stdout.read(4096)
        if b'$' in chunk:
            # 分离PNG数据与shell提示符
            png_data += chunk[:chunk.find(b'$')]
            break
        png_data += chunk
    
    # 保存帧图片
    with open(f'./frames/frame_{FRAME_COUNT}.png', 'wb') as file:
        file.write(png_data)
    
    sleep(1)
    FRAME_COUNT += 1

优势说明

  • 仅启动一次adb进程,避免了循环中进程创建/销毁的资源消耗,内存占用更稳定。
  • 复用连接减少了ADB与设备的握手开销,整体效率提升明显。

二、OpenCV版本代码的效率优化

更新后的代码仍存在每次循环重启adb的问题,同时还有可优化的计算环节,以下是针对性改进:

优化后的代码(实时显示+FPS计算)

import subprocess
import cv2
import numpy as np
from time import time

# 启动单个adb交互进程
adb_process = subprocess.Popen(
    ['adb', 'shell'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    bufsize=0
)

# 预获取屏幕尺寸,提前计算缩放目标尺寸(避免重复运算)
# 先执行一次截屏获取初始图像尺寸
adb_process.stdin.write(b'screencap -p\n')
adb_process.stdin.flush()
init_png = b''
while True:
    chunk = adb_process.stdout.read(4096)
    if b'$' in chunk:
        init_png += chunk[:chunk.find(b'$')]
        break
    init_png += chunk
init_img = cv2.imdecode(np.frombuffer(init_png, np.uint8), cv2.IMREAD_COLOR)
TARGET_WIDTH = int(init_img.shape[1] * 0.45)
TARGET_HEIGHT = int(init_img.shape[0] * 0.45)

# 滑动平均计算FPS,避免单次波动导致的数值跳变
fps_samples = []
MAX_SAMPLES = 10

while True:
    t_start = time()
    
    # 发送截屏命令
    adb_process.stdin.write(b'screencap -p\n')
    adb_process.stdin.flush()
    
    # 读取PNG数据
    png_data = b''
    while True:
        chunk = adb_process.stdout.read(4096)
        if b'$' in chunk:
            png_data += chunk[:chunk.find(b'$')]
            break
        png_data += chunk
    
    # 解码图像并缩放
    img = cv2.imdecode(np.frombuffer(png_data, np.uint8), cv2.IMREAD_COLOR)
    # 缩小图像用INTER_AREA插值,效率更高且画质更好
    resized_img = cv2.resize(img, (TARGET_WIDTH, TARGET_HEIGHT), interpolation=cv2.INTER_AREA)
    
    # 计算滑动平均FPS
    t_end = time()
    current_fps = 1 / (t_end - t_start)
    fps_samples.append(current_fps)
    if len(fps_samples) > MAX_SAMPLES:
        fps_samples.pop(0)
    avg_fps = sum(fps_samples) / len(fps_samples)
    
    # 绘制FPS文本
    cv2.putText(resized_img, f'FPS: {avg_fps:.2f}', (10, 30),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    
    cv2.imshow('Screen Capture', resized_img)
    # 按q键退出循环
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 清理资源
adb_process.stdin.close()
adb_process.stdout.close()
adb_process.stderr.close()
adb_process.terminate()
cv2.destroyAllWindows()

核心优化点

  1. 长连接adb进程:彻底消除每次循环启动adb的开销,这是提升效率的核心。
  2. 预计算缩放尺寸:避免每次循环重复计算宽高,减少冗余运算。
  3. 滑动平均FPS:让显示的FPS数值更稳定,避免单次帧耗时波动影响观感。
  4. 指定缩放插值方法:INTER_AREA在缩小图像时比默认插值更高效,画质更清晰。
  5. 资源清理:添加进程终止和窗口销毁逻辑,避免资源泄漏。

额外进阶优化:改用RAW格式截屏

如果不需要PNG的压缩特性,可以用screencap -c获取RAW格式屏幕数据,跳过PNG解压缩步骤,进一步提升解码速度:

# 先获取屏幕分辨率
adb_process.stdin.write(b'wm size\n')
adb_process.stdin.flush()
size_data = b''
while True:
    chunk = adb_process.stdout.read(1024)
    if b'$' in chunk:
        size_data += chunk[:chunk.find(b'$')]
        break
    size_data += chunk
# 解析分辨率(示例:"Physical size: 1080x2340")
size_str = size_data.decode().strip().split(': ')[1]
SCREEN_WIDTH, SCREEN_HEIGHT = map(int, size_str.split('x'))

# 后续截屏改用RAW格式
adb_process.stdin.write(b'screencap -c\n')
adb_process.stdin.flush()
# RAW格式为RGBA,每个像素4字节,读取对应长度的数据
raw_data = adb_process.stdout.read(SCREEN_WIDTH * SCREEN_HEIGHT * 4)
# 转换为numpy数组并转成OpenCV支持的BGR格式
img = np.frombuffer(raw_data, np.uint8).reshape((SCREEN_HEIGHT, SCREEN_WIDTH, 4))
img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR)

RAW格式无压缩,读取和解码速度远快于PNG,能显著提升高分辨率屏幕下的FPS。

内容的提问来源于stack exchange,提问作者Muhammad Ikhwan Perwira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 22:48:10