I'm trying to edit all images within a specified directory (and subdirs) using PIL, and then save the edited versions in a different location but under the same subdirectory structure.
ie. Input:
Root directory
|
|---------Subdir 1
| |---Image_1
| |---Image_2
| |---Image_3
|
|---------Subdir 2
| |---Image_1
| |---Image_2
And Output:
{Specified directory}
|
|---------Subdir 1
| |---Edited_Image_1
| |---Edited_Image_2
| |---Edited_Image_3
|
|---------Subdir 2
| |---Edited_Image_1
| |---Edited_Image_2
Where the subdirs share same names, and are created when os.walk is run.
I've constructed this as a function so I can later run it in a Linux terminal with options changed upon calling the function.
from PIL import Image, ImageDraw, ImageOps
import os
from os.path import isfile, join
def editimage(image_directory="image_directory",
version="B", #Specify which version of ImageDraw edit to do
resize=False, #choose whether or not to resize image
new_size=(800,428), #choose new size
output_directory="output_directory"):
for directory, subdirs, files in os.walk(image_directory):
for dirname in subdirs:
if not os.path.exists(output_directory + dirname):
os.mkdir(output_directory + image_directory + dirname) #This does exactly what I want it to do
for directory, subdirs, files in os.walk(image_directory):
for f in files:
if f.endswith('.JPG'):
img = Image.open(directory + f)
draw= ImageDraw.Draw(img)
if version=="A":
draw.ellipse((1823, 1472, 2033, 1536), fill = (0,0,0), outline=None)
draw.rectangle((0, 0, 2048, 32), fill = (0,0,0), outline=None)
draw.rectangle((0, 1504, 2048, 1536), fill = (0,0,0), outline=None)
img=ImageOps.pad(img, size=(2731,1536), color="grey")
elif version=="B":
draw.rectangle((0, 1231, 2304, 1296), fill = (0,0,0), outline=None)
if resize==True:
img = img.resize(new_size)
else:
pass
img.save(output_directory + "/" + f + ".png")
This would let the user enter:
editimage("Path/to/input/", version="A", resize= False, output_directory="Path/to/output/")
I've tried using img.save(output_directory + subdirs + ".png" or creating a variable for that, but Python returns: TypeError: can only concatenate list (not "str") to list, or otherwise wants the input directory within the output directory. It doesn't seem to walk every subdirectory.
I previously used
imagelist = [join(directory, f)
for directory, subdirs, files in os.walk(image_directory)
for f in files
if isfile
if f.endswith('.JPG')]
for f in imagelist:
img = Image.open(f) #etc..
to construct read and edit the images, but then img.save(f) keeps the entire path and cannot save the image to a new location.
The rest of the function works perfectly, and will overwrite images within the original directory (and subdirs) if I remove the output_directory argument in the img.save line. I had no issues until realising that the output directory wasn't being used.
Because the version A set of images are not named uniquely between folders, I need to be able to reconstruct the directory paths.
How can I fix this? Thanks!
The function below will create a new directory for annotated images with the same tree structure as the input directory. I used
pathlibfrom the core Python library even though you asked how to useos.walk(). I like its object-oriented methods and find that the code is cleaner. PEP428 provides more detail on the rationale behind pathlib.