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

嵌入式Python Flask图像流传输PIL转换瓶颈优化咨询

优化方案

你当前测得的Image.fromarray耗时偏高,并非完全是PIL本身性能差,两个容易被忽略的隐性开销占了近一半耗时:

  • 步长切片image_np[::4, ::4, :3]生成的是非连续内存的numpy视图,PIL处理这类非连续数组时,会隐式执行一次全量内存拷贝,这部分拷贝耗时经常被误算为fromarray本身的耗时
  • 代码中np.asarray(raw_stream[::])是完全冗余的操作,会无意义遍历拷贝一次全帧数据;循环内重复创建BytesIO对象也会带来额外的内存分配开销,在嵌入式设备上这类开销会被放大。

方案1:替换为libjpeg-turbo绑定库(嵌入式场景首选,性能提升最明显)

libjpeg-turbo是针对ARM/x86平台做了NEON/AVX SIMD指令集优化的JPEG编解码库,编解码速度是原生PIL自带libjpeg的4~6倍,在算力有限的嵌入式设备上收益极高。
Python端可以用PyTurboJPEG作为绑定,代码改动量极小:

  1. 先通过嵌入式设备的系统包管理器安装libjpeg-turbo运行库,再通过pip安装PyTurboJPEG
  2. 全局初始化一次编码器、复用内存对象,避免循环内重复分配资源,核心代码参考如下:
import io
import numpy as np
from turbojpeg import TurboJPEG, TJPF_RGB

# 全局初始化一次JPEG编码器、缓存对象,不要在循环内重复创建
jpeg_encoder = TurboJPEG()

@bp.route("/stream")
def stream():
    def loop():
        yield b"--frame\r\n"
        while True:
            raw_data = view[ frame_id * BUF_SIZE : (frame_id + 1) * BUF_SIZE ]
            # 移除冗余的asarray拷贝,直接从内存buffer解析RGBA数组
            image_np = np.frombuffer(raw_data, dtype=np.uint8).reshape((600, 1024, 4))
            # 下采样+去alpha通道后主动转为连续内存数组,避免编码时隐式拷贝
            small_rgb = np.ascontiguousarray(image_np[::4, ::4, :3])
            # 质量设为75即可满足普通视频流的视觉需求,编码速度比100质量快1倍以上
            jpeg_data = jpeg_encoder.encode(small_rgb, quality=75, pixel_format=TJPF_RGB)
            yield (
                b"Content-Type: image/jpeg\r\n\r\n"
                + jpeg_data
                + b"\r\n--frame\r\n"
            )
    return Response(loop(), mimetype="multipart/x-mixed-replace; boundary=frame")

该方案下你当前150*256分辨率的单帧编码耗时通常可以降到5ms以内,帧率可轻松跑到30FPS以上。

方案2:零代码改动替换为Pillow-SIMD

如果不想额外安装系统依赖,可以直接把原生Pillow替换为Pillow-SIMD。它是Pillow的兼容fork版本,针对常用图像操作做了全量SIMD优化,完全兼容原生Pillow的所有API,不需要修改任何业务代码,性能比原生Pillow高2~3倍。
操作方式为先卸载原生Pillow,再安装Pillow-SIMD:

pip uninstall -y pillow
pip install pillow-simd

使用时记得给切片后的数组加上np.ascontiguousarray()转换为连续内存,还能再省30%左右的耗时。

额外优化建议

  • JPEG质量不要设置过高,70~80的质量在普通监控、视频流场景下人眼几乎感知不到差异,编码效率提升明显
  • 不要在帧生成循环内创建编码器、IO缓存这类可复用对象,减少嵌入式设备上频繁内存分配、GC带来的卡顿
  • 如果对延迟要求极高,可以尝试关闭Flask的默认调试模式,或者用gevent替换Flask默认的WSGI服务器,减少网络IO层面的开销

内容的提问来源于stack exchange,提问作者Florian Guyot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:48:11