基于exif信息进行坐标旋转、翻转修正

基于exif信息进行图片方向旋转修正

上次完成《基于exif信息进行图片方向旋转修正》后,出现了一个新的问题: 第一次标注了实例的外边框,第二次标注了实例的文本区域,合并后前后两次标注的坐标点无法与图片匹配吻合。
基于exif信息进行坐标旋转、翻转修正产生这个问题的原因是两次标注的图片方向不一致,第二次标注时图片没有被exif信息进行旋转,所以合并后第一次的标注坐标出现了问题,现在需要从exif中读取出图片方向,对坐标进行旋转。

import cv2
import numpy as np
import json
import base64
import os
import glob
import imageio
from io import BytesIO
import math
import PIL.ExifTags
import PIL.Image
import PIL.ImageOps
import re

def apply_exif_orientation(image):
    """
    从图片exif信息中读取旋转角度
    :param image:
    :return:
    """
    try:
        exif = image._getexif()
    except AttributeError:
        exif = None

    if exif is None:
        return None, None

    exif = {
        PIL.ExifTags.TAGS[k]: v
        for k, v in exif.items()
        if k in PIL.ExifTags.TAGS
    }

    orientation = exif.get('Orientation', None)
    # return orientation
    if orientation == 1:
        # do nothing
        return None, None
    elif orientation == 2:
        # left-to-right mirror
        return 'mirror', None
    elif orientation == 3:
        # rotate 180
        return None, 180
    elif orientation == 4:
        # top-to-bottom mirror
        return 'flip', None
    elif orientation == 5:
        # top-to-left mirror
        return 'mirror', -90
    elif orientation == 6:
        # rotate 270
        return None, -90
    elif orientation == 7:
        # top-to-right mirror
        return 'mirror', 90
    elif orientation == 8:
        # rotate 90
        return None, 90
    else:
        return image

def flip_point(h, points):
    """
    点上下翻转
    :param h: int, eg 10
    :param point: ndarray, [ [1, 2] [1, 8 ] ]
    :return:[ [1, 8] [1, 2 ] ]
    """
    points[:,0:1] = h-points[:,0:1]
    return points

def mirror_point(w, points):
    """
    点左右翻转
    :param w: int, eg. 10
    :param point:NDarray, eg. array([[1, 2], [7, 4]])
    :return:NDarray,eg array([[9, 2], [3, 4]])
    """
    points[:,1:2] = w-points[:,0:1]
    return points

def rotation_point(h, w, angle, point):
    """
    坐标点旋转
    :param h: 图片高度
    :param w: 图片宽度
    :param angle: 旋转角度
    :param point: 坐标点 eg. NDarray([[1,2],[2,3]])
    :return: point: 坐标点 eg. NDarray([[1,2],[2,3]])
    """
    cols = h
    rows = w
    M = cv2.getRotationMatrix2D((cols / 2, rows / 2), angle, 1)
    heightNew = int(cols * math.fabs(math.sin(math.radians(angle))) + rows * math.fabs(math.cos(math.radians(angle))))
    widthNew = int(rows * math.fabs(math.sin(math.radians(angle))) + cols * math.fabs(math.cos(math.radians(angle))))

    M[0, 2] += (widthNew - cols) / 2
    M[1, 2] += (heightNew - rows) / 2
    a = M[:, :2]
    b = M[:, 2:]
    b = np.reshape(b, newshape=(1, 2))
    a = np.transpose(a)
    point = np.reshape(point, newshape=(len(point), 2))
    if angle == 180:
        point = np.dot(point, a) + np.array([b[0][1], b[0][0]])
    else:
        point = np.dot(point, a) + b

    return point


def main():
    image_path = "xx.jpg"
    pil_image = PIL.Image.open(open(image_path))
    h, w = pil_image.size
    transform, angle = apply_exif_orientation(pil_image)
    print(f"angle:{angle}, transform:{transform}")
    pts = np.array([[90, 230], [160, 230], [160, 250], [90, 250]])
    if angle in [-90, 90, 180]:
        pts = rotation_point(h, w, angle, pts).astype(np.int32)
    if transform in ['mirror']:
        pts = mirror_point(w, pts)
    elif transform in ['flop']:
        pts = flip_point(h, pts)
  


if __name__ == "__main__":
    main()

以上是坐标旋转,我进行了图片旋转修正,请参考《基于exif信息进行图片方向旋转修正》,最终效果如下:

基于exif信息进行坐标旋转、翻转修正
完成!

上一篇:2021 暑假水题选做


下一篇:每日一题_190914