采用电子设备拍摄照片时,如手机、相机等,由于手持朝向的不同,拍摄的照片可能会出现旋转 0、90、180、270 角度的情况,其 EXIF 信息中会保留相应的方位信息.
有些情况下,电脑上打开显示照片是正常的,但在用 PIL 或 OpenCV 读取图片后,图片出现旋转,且读取的图片尺寸也可能与直接在电脑上打开的尺寸不同的问题.
对此,需要在读取图片时,同时解析图片的 EXIF 中的方位信息,将图片转正,再进行后续的其他操作.
1. 解决方案一
实例如下.
from PIL import Image, ExifTags
img_file = '/path/to/img.jpg'
img_pil =Image.open(img_file)
try :
for orientation in ExifTags.TAGS.keys() :
if ExifTags.TAGS[orientation]=='Orientation' :
break
exif=dict(image._getexif().items())
if exif[orientation] == 3 :
image=image.rotate(180, expand=True)
elif exif[orientation] == 6 :
image=image.rotate(270, expand=True)
elif exif[orientation] == 8 :
image=image.rotate(90, expand=True)
image.thumbnail((THUMB_WIDTH , THUMB_HIGHT), Image.ANTIALIAS)
image.show()
except:
pass
2. 解决方案二
采用 PIL.ImageOps.exif_transpose()
函数,其功能为:如果图像具有EXIF Orientation标签,则返回相应地转置的新图像;否则,返回图像的副本.
示例如:
from PIL import Image, ImageOps
img_pil = Image.open('/path/to/test.jpg').convert('RGB')
width, height = img_pil.size
print("[INFO]Original width: {}, height: {}".format(width, height))
# Transpose with respect to EXIF data
img_pil = ImageOps.exif_transpose(img_pil)
width, height = img_pil.size
print("[INFO]Transpose width: {}, height: {}".format(width, height))
exif_transpose()
函数定义如:
def exif_transpose(image):
"""
If an image has an EXIF Orientation tag, return a new image that is
transposed accordingly. Otherwise, return a copy of the image.
:param image: The image to transpose.
:return: An image.
"""
exif = image.getexif()
orientation = exif.get(0x0112)
method = {
2: Image.FLIP_LEFT_RIGHT,
3: Image.ROTATE_180,
4: Image.FLIP_TOP_BOTTOM,
5: Image.TRANSPOSE,
6: Image.ROTATE_270,
7: Image.TRANSVERSE,
8: Image.ROTATE_90,
}.get(orientation)
if method is not None:
transposed_image = image.transpose(method)
transposed_exif = transposed_image.getexif()
if 0x0112 in transposed_exif:
del transposed_exif[0x0112]
if "exif" in transposed_image.info:
transposed_image.info["exif"] = transposed_exif.tobytes()
elif "Raw profile type exif" in transposed_image.info:
transposed_image.info[
"Raw profile type exif"
] = transposed_exif.tobytes().hex()
elif "XML:com.adobe.xmp" in transposed_image.info:
transposed_image.info["XML:com.adobe.xmp"] = re.sub(
r'tiff:Orientation="([0-9])"',
"",
transposed_image.info["XML:com.adobe.xmp"],
)
return transposed_image
return image.copy()