基于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信息进行图片方向旋转修正》,最终效果如下:
完成!