使用PIL打开图像报错UnidentifiedImageError的原因及解决方法
问题:调用libcamera-still生成图像后PIL无法识别的错误
代码实现
from io import StringIO import subprocess import os import time from datetime import datetime from PIL import Image import subprocess def captureTestImage(settings, width, height): command = "libcamera-still --width {} --height {} --autofocus-on-capture 1 -q 75 --tuning-file /usr/share/libcamera/ipa/rpi/vc4/imx708_wide.json -o DAY-AF1-q75--tuningfile-imx708_wide-06-21-2024-16-15-20.jpg".format(width, height) subprocess.run(command[0],shell=True,executable="/usr/bin/bash") imageData = StringIO() imageData.write(subprocess.check_output(command, shell=True)) imageData.seek(0) im = Image.open(imageData) buffer = im.load() imageData.close() return im, buffer
报错信息
Still capture image received im = Image.open(imageData) File "/home/user/.local/lib/python3.9/site-packages/PIL/Image.py", line 3339, in open raise UnidentifiedImageError(msg) PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x7f9df4db80>
问题原因
- 无效的subprocess调用:
subprocess.run(command[0], ...)完全错误,command是字符串,command[0]仅取了第一个字符(比如'l'),执行的是无意义命令,属于冗余且错误的代码。 - 图像数据来源错误:你的
libcamera-still命令带了-o参数,会直接把图像保存到指定文件,此时命令的标准输出(subprocess.check_output获取的内容)是程序日志(比如"Still capture image received"),而非图像二进制数据。把日志文本传给PIL,自然无法识别为图像。 - IO类型错误:图像是二进制数据,应该用
BytesIO而非处理文本的StringIO,即便能拿到图像数据,用StringIO也会导致数据损坏。
修复方案
方案一:直接读取已生成的图像文件(最简单)
既然libcamera-still已经把图像保存到文件,直接用PIL打开该文件即可:
from PIL import Image import subprocess from datetime import datetime def captureTestImage(settings, width, height): # 用datetime生成动态文件名,避免覆盖旧文件 filename = "DAY-AF1-q75--tuningfile-imx708_wide-{}.jpg".format(datetime.now().strftime("%m-%d-%Y-%H-%M-%S")) command = f"libcamera-still --width {width} --height {height} --autofocus-on-capture 1 -q 75 --tuning-file /usr/share/libcamera/ipa/rpi/vc4/imx708_wide.json -o {filename}" # 执行捕获命令并检查结果 result = subprocess.run(command, shell=True, executable="/usr/bin/bash", capture_output=True, text=True) if result.returncode != 0: raise Exception(f"捕获失败: {result.stderr}") # 直接从文件读取图像 im = Image.open(filename) buffer = im.load() return im, buffer, filename # 可选返回文件名,方便后续处理
方案二:从标准输出获取图像(不生成本地文件)
如果不想生成本地文件,修改libcamera-still命令,让它把图像输出到标准输出,再用BytesIO处理:
from io import BytesIO import subprocess from PIL import Image def captureTestImage(settings, width, height): # -o - 表示将图像输出到标准输出 command = f"libcamera-still --width {width} --height {height} --autofocus-on-capture 1 -q 75 --tuning-file /usr/share/libcamera/ipa/rpi/vc4/imx708_wide.json -o -" # 捕获二进制输出 image_bytes = subprocess.check_output(command, shell=True, executable="/usr/bin/bash") # 用BytesIO包装二进制数据 imageData = BytesIO(image_bytes) im = Image.open(imageData) buffer = im.load() imageData.close() return im, buffer
额外优化建议
- 移除重复的
import subprocess语句,保持代码整洁。 - 执行subprocess命令时,添加
capture_output=True和手动检查returncode,方便排查命令执行失败问题。 - 动态生成文件名避免覆盖旧文件,便于后续追溯。
内容的提问来源于stack exchange,提问作者Jshee
相关产品推荐
相关产品推荐

