+ convert images in sub-directories

+ exiftool: if xmp sidecar exists, use it. Otherwise: use image file
+ skip already blurred images
This commit is contained in:
Daniel Langbein 2021-09-13 13:39:27 +02:00
parent b92a65c67f
commit ce307c09d2
6 changed files with 57 additions and 21 deletions

8
.idea/blur-exif-face-tags.iml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.9 (venv39-2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

2
.idea/modules.xml generated
View File

@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/20210828_image-xml-metadata.iml" filepath="$PROJECT_DIR$/.idea/20210828_image-xml-metadata.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/blur-exif-face-tags.iml" filepath="$PROJECT_DIR$/.idea/blur-exif-face-tags.iml" />
</modules>
</component>
</project>

View File

@ -31,4 +31,4 @@ Many thanks to
* https://www.thregr.org/~wavexx/software/facedetect/#blurring-faces-within-an-image
* "Make blur all around a rectangle in image with PIL", https://stackoverflow.com/q/56987112/6334421
* Example image: https://unsplash.com/photos/1qfy-jDc_jo?utm_source=unsplash&utm_medium=referral&utm_content=creditShareLink
* Example image: https://unsplash.com/photos/1qfy-jDc_jo?utm_source=unsplash&utm_medium=referral&utm_content=creditShareLink

18
blur.py
View File

@ -12,7 +12,7 @@ import exif
class NormalizedRectangle:
"""
x, y, width and height are normalized: Their values are in the range [0, 1]
x, y, width and height are normalized: Their values are in the range [0, 1].
"""
x: float
@ -82,5 +82,19 @@ def blur_rectangle2(image_src: Path, normalized_rectangles: List[NormalizedRecta
# Save image
if image_dst is None:
image_dst = image_src.parent.joinpath(f'{image_src.stem}_blurred{image_src.suffix}')
image_dst = get_image_dst(image_src)
im.save(image_dst)
def get_image_dst(image: Path):
return image.parent.joinpath(f'{image.stem}{stem_suffix()}{image.suffix}')
def stem_suffix():
"""
Modified images will be saved with a different filename.
This suffix will be added to their stem.
"""
# return ' [blurred]'
return '_blurred'

32
exif.py
View File

@ -23,19 +23,12 @@ class Image:
if len(self.files) == 0:
raise Exception
else:
raise Exception
raise Exception(f'{image_file}')
def get_image_file(self):
return self.files[0]
def get_xmp_metadata(self) -> AnyStr:
# TODO: Try to read xmp metadata from the image file itself, if there is no sidecar xmp file
xmp_sidecar = self.get_xmp_sidecar()
with open(xmp_sidecar, "r") as f:
return f.read()
def get_xmp_sidecar(self):
def get_xmp_file(self):
"""
:return: The sidecar xmp file, if it exists. Otherwise None is returned.
"""
@ -46,6 +39,17 @@ class Image:
return file
return None
def get_metadata_file(self):
"""
If a sidecar xmp file exists, it is preferred over the image file itself.
:return: A file containing the image metadata.
"""
metadata = self.get_xmp_file()
if metadata is None:
metadata = self.get_image_file()
return metadata
def __str__(self):
return f'Image: {self.__dict__}'
@ -75,12 +79,12 @@ class ExifImageRegion:
def get_exif_image_regions(image: Image) -> List[ExifImageRegion]:
sidecar: Path = image.get_xmp_sidecar()
img_metadata_file: Path = image.get_metadata_file()
names_str = exec.execute_save(['exiftool', '-RegionName', str(sidecar)])
r_types_str = exec.execute_save(['exiftool', '-RegionType', str(sidecar)])
area_units_str = exec.execute_save(['exiftool', '-RegionAreaUnit', str(sidecar)])
rectangles_str = exec.execute_save(['exiftool', '-RegionRectangle', str(sidecar)])
names_str = exec.execute_save(['exiftool', '-RegionName', str(img_metadata_file)])
r_types_str = exec.execute_save(['exiftool', '-RegionType', str(img_metadata_file)])
area_units_str = exec.execute_save(['exiftool', '-RegionAreaUnit', str(img_metadata_file)])
rectangles_str = exec.execute_save(['exiftool', '-RegionRectangle', str(img_metadata_file)])
names = names_str.strip().split(':', 1)[1].strip().split(', ')
r_types = r_types_str.strip().split(':', 1)[1].strip().split(', ')

16
main.py
View File

@ -1,3 +1,4 @@
import os
from pathlib import Path
from typing import List
@ -29,9 +30,18 @@ def blur_image(image: exif.Image):
def main():
for child in image_directory.iterdir():
if child.suffix.lower() in image_extensions:
blur_image(exif.Image(child))
# Convert all images in the image_directory, including subdirectories.
for _, _, files in os.walk(image_directory):
for relative_file_str in files:
file: Path = Path.joinpath(image_directory, relative_file_str)
if file.suffix.lower() in image_extensions:
if file.stem.endswith(blur.stem_suffix()):
print(f'Skipped the following image as it is already blurred:\n\t{file}')
elif blur.get_image_dst(file).exists():
print(f'Skipped the following image as it\'s blurred output does already exist:\n\t{file}')
else:
blur_image(exif.Image(file))
if __name__ == '__main__':