采用电子设备拍摄照片时,如手机、相机等,由于手持朝向的不同,拍摄的照片可能会出现旋转 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

更多可参考:Stackoverflow - PIL thumbnail is rotating my image?

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()
Last modification:August 27th, 2021 at 01:46 pm