Skip to content

Commit

Permalink
[Optimize] Improve EXIF orientation handling with backup and logging
Browse files Browse the repository at this point in the history
  • Loading branch information
CVHub520 committed Sep 10, 2024
1 parent e67a79f commit 59a73fa
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 22 deletions.
21 changes: 0 additions & 21 deletions anylabeling/views/labeling/label_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,6 @@ def __init__(self, filename=None, image_dir=None):
@staticmethod
def load_image_file(filename, default=None):
try:
# NOTE: This method includes a temporary workaround for handling EXIF orientation.
# It may result in a slight performance overhead due to the additional processing and file I/O.
# A more efficient solution should be considered in the future.
from PIL import Image, ExifTags

with Image.open(filename) as img:
exif_data = None
if hasattr(img, "_getexif"):
exif_data = img._getexif()
if exif_data is not None:
for tag, value in exif_data.items():
tag_name = ExifTags.TAGS.get(tag, tag)
if tag_name != "Orientation":
continue
if value == 3:
img = img.rotate(180, expand=True)
elif value == 6:
img = img.rotate(270, expand=True)
elif value == 8:
img = img.rotate(90, expand=True)
img.save(filename)
with open(filename, "rb") as f:
return f.read()
except:
Expand Down
3 changes: 2 additions & 1 deletion anylabeling/views/labeling/label_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -3596,7 +3596,7 @@ def load_file(self, filename=None): # noqa: C901
basename = osp.basename(str(filename))
if self.image_list and filename in self.image_list:
num_images = len(self.image_list)
current_index = self.fn_to_index[str(filename)]
current_index = self.fn_to_index[str(filename)] + 1
msg = str(self.tr("Loaded %s [%d/%d]")) % (
basename,
current_index,
Expand Down Expand Up @@ -6029,6 +6029,7 @@ def import_image_folder(self, dirpath, pattern=None, load=True):
item.setCheckState(Qt.Unchecked)
self.file_list_widget.addItem(item)
self.fn_to_index[filename] = self.file_list_widget.count() - 1
utils.process_image_exif(filename)
self.open_next_image(load=load)

def scan_all_images(self, folder_path):
Expand Down
1 change: 1 addition & 0 deletions anylabeling/views/labeling/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
img_data_to_pil,
img_data_to_png_data,
img_pil_to_data,
process_image_exif,
)
from .qt import (
Struct,
Expand Down
35 changes: 35 additions & 0 deletions anylabeling/views/labeling/utils/image.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import os
import os.path as osp
import base64
import io
import shutil

import numpy as np
import PIL.ExifTags
Expand Down Expand Up @@ -70,6 +73,38 @@ def img_data_to_png_data(img_data):
return f.read()


def process_image_exif(filename):
"""Process image EXIF orientation and save if necessary."""
with PIL.Image.open(filename) as img:
exif_data = None
if hasattr(img, "_getexif"):
exif_data = img._getexif()
if exif_data is not None:
for tag, value in exif_data.items():
tag_name = PIL.ExifTags.TAGS.get(tag, tag)
if tag_name != "Orientation":
continue
if value == 3:
img = img.rotate(180, expand=True)
rotation = "180 degrees"
elif value == 6:
img = img.rotate(270, expand=True)
rotation = "270 degrees"
elif value == 8:
img = img.rotate(90, expand=True)
rotation = "90 degrees"
else:
return # No rotation needed
backup_dir = osp.join(osp.dirname(osp.dirname(filename)),
"x-anylabeling-exif-backup")
os.makedirs(backup_dir, exist_ok=True)
backup_filename = osp.join(backup_dir, osp.basename(filename))
shutil.copy2(filename, backup_filename)
img.save(filename)
print(f"Rotated {filename} by {rotation}, saving backup to {backup_filename}")
break


def apply_exif_orientation(image):
try:
exif = image._getexif()
Expand Down

0 comments on commit 59a73fa

Please sign in to comment.