手机照片看起来是竖图,训练程序读出来却横着,可能是查看器按 EXIF 方向显示,而文件像素尚未按该方向重排。Pillow 的 exif_transpose 可以按方向标记调整像素,并去掉已处理的方向信息。下面用一张带标签的教学图验证尺寸与方向,保存独立副本。
像素方向与显示方向的区别
EXIF Orientation 可以表达旋转和镜像,标签不一定等于“转90度”。程序应根据实际标签处理;若盲目给所有图转90度,原本正确的图也会被改错。已经按标签处理并移除标签后,再重复手工旋转也可能造成二次错误。

ImageOps.exif_transpose 默认返回新的图像对象;有有效方向变化时按标签变换,并移除方向数据。无须变换时返回副本。这里不采用 in_place 修改源对象,输出另外保存。
环境与可复核的教学图片
示例在 Windows、Python 3.11.15 的本地 CPU 环境实际运行。新建空文件夹,将后面完整代码保存为 08-exif-orientation.py,在该目录用 PowerShell 执行:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install Pillow==11.3.0
.\.venv\Scripts\python.exe 08-exif-orientation.py
最后一行在保存代码后执行。macOS 或 Linux 使用 ./.venv/bin/python。输出文件留在当前目录,先用教学样本核对;代码不调用大模型 API,也不修改你的原始业务文件。
教学 JPEG 的上半部分红色、下半部分蓝色,像素宽160高80,方向标记为6。它只验证库的转置行为,未使用真实照片,也没有训练图像模型。
完整代码:应用方向并回读副本
把完整代码保存为 08-exif-orientation.py 后运行,查看源像素尺寸和方向标记,再打开 orientation_fixed.png 与 orientation_audit.json;换成真实图片时,保留原文件并检查标注坐标。
from pathlib import Path
import hashlib,json
from PIL import Image,ImageDraw,ImageOps
# 只创建一个带方向标签的教学图:上半红色,下半蓝色。
image=Image.new('RGB',(160,80),'red')
ImageDraw.Draw(image).rectangle((0,40,159,79),fill='blue')
exif=Image.Exif();exif[274]=6 # EXIF方向6:显示时顺时针旋转90度。
source=Path('orientation_demo.jpg')
image.save(source,quality=95,exif=exif.tobytes())
before=hashlib.sha256(source.read_bytes()).hexdigest()
with Image.open(source) as src:
src.load()
print('source pixels/orientation:',src.size,src.getexif().get(274))
fixed=ImageOps.exif_transpose(src)
print('fixed pixels/orientation:',fixed.size,fixed.getexif().get(274))
print('top-left dominant color:','blue' if fixed.getpixel((5,5))[2]>fixed.getpixel((5,5))[0] else 'other')
assert fixed.size==(80,160) and fixed.getexif().get(274) is None
fixed.save('orientation_fixed.png')
with Image.open('orientation_fixed.png') as saved:
assert saved.size==(80,160) and saved.getexif().get(274) is None
print('saved size:',saved.size)
assert before==hashlib.sha256(source.read_bytes()).hexdigest()
Path('orientation_audit.json').write_text(json.dumps(
{'source':source.name,'sha256':before,'source_size':[160,80],'source_orientation':6,
'output':'orientation_fixed.png','output_size':[80,160],'output_orientation':None},indent=2),encoding='utf-8')
print('original unchanged: True')
实际结果如何检查
source pixels/orientation: (160, 80) 6
fixed pixels/orientation: (80, 160) None
top-left dominant color: blue
saved size: (80, 160)
original unchanged: True
原图像素尺寸为 (160,80),EXIF 方向为6;处理后尺寸为 (80,160),方向标记变为 None,左上区域以蓝色为主。回读保存文件的尺寸一致,原始JPEG哈希没有变化。
方向6对应的这次转换把宽高交换;蓝色区域来到图的左侧。JPEG 的有损编码可能带来颜色数值末位变化,代码检查主色而非要求每个颜色字节完全相同。PNG 副本回读后宽高仍一致,方向标签不再要求查看器重复旋转。
检查真实图片时,应使用能显示实际像素方向的查看方式,并核对人物、文字或场景是否正向。仅靠宽高交换无法判断照片原来的拍摄意图;如果方向标签缺失或错误,需要人工确认,不应凭宽大于高自动猜方向。
训练数据带标签时如何处理
图像旋转或镜像会改变检测框、分割掩码和关键点的坐标。带标注的训练数据必须同步变换标注,或在校正后的图像上重新标注;只转图片不能保证训练标签仍正确。
本例没有任何检测框、掩码或关键点,未实现标注坐标变换。应先确定整个数据集的图像读取器是否已经应用 EXIF,避免图片预处理与训练读取阶段各转一次。为源路径、输出路径、方向标记、尺寸与哈希保存记录,可帮助定位问题。
不同时刻保存图像可能丢掉部分元数据;如果下游任务需要相机参数、色彩配置或来源信息,应单独决定保留字段。本文只核对像素尺寸与方向信息,没有承诺复制全部 EXIF 或保持有损JPEG像素完全不变。
遇到无法识别图片或文件截断时,应隔离输入并查来源。不要把读取失败文件默默排除后,还以原样本数量计算训练数据覆盖。本教程输出副本,原始文件哈希仍保持不变。
官方资料与核对范围
资料读取日期为 2026 年 10 月 1 日。接口行为依照以下官方文档或项目说明核对,输出来自上述本地教学代码。
- Pillow ImageOps:exif_transpose的方向处理、标签删除和副本行为。
- Pillow Image:图像读取、EXIF访问与保存接口。
Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/31825.html