Renaming, resizing, and moving image files in python - python

I am trying to create a program that will resize any image in a directory to 299x299. Then, I want to rename that image and convert it to a jpeg, so that all of the images will be named 0.jpg, 1.jpg, 2.jpg, etc. I also want to move the converted files to their own directory.
I have already solved the resizing portion of it. However, when I added the code for renaming, i.e. (index = 0, new_image.save)file_name, str(index), + ".jpg", and index += 1), the resizing portion no longer works. Does anyone have any suggestions?
This is what I have so far:
#!usr/bin/python
from PIL import Image
import os, sys
directory = sys.argv[1]
for file_name in os.listdir(directory):
print ("Converting %s" % file_name + "...")
image = Image.open(os.path.join(directory, file_name))
size = 299, 299
image.thumbnail(size, Image.ANTIALIAS)
w, h = image.size
new_image = Image.new('RGBA', size, (255, 255, 255, 255))
new_image.paste(image, ((299 - w) / 2, (299 - h) / 2))
index = 0
new_image_file_name = os.path.join(directory, file_name)
new_image.save(file_name, str(index) + ".jpg")
index += 1
print ("Conversion process complete.")

From the documentation:
Image.save(fp, format=None, **params)
Saves this image under the given
filename. If no format is specified, the format to use is determined
from the filename extension, if possible.
The correct syntax for image.save is:
new_image.save(file_name, 'JPG')
To move a file, you can use shutil.move:
import shutil
shutil.move(file_name, 'full/path/to/dst/') # the second argument can be a directory

Related

How do I write file names to a new folder with an added prefix?

I'm trying to take a dir like ["cats.jpg", "dogs.jpg", "stars.jpg"] and resize them to 100x100 pixels and output the edited files into a new directory with the prefix "resized_" i.e ["resized_cats.jpg", "resized_dogs.jpg", "resized_stars.jpg"].
At the moment I'm getting the new directory but no files are being written to it.
batch = glob.glob("files/batch/*.jpg")
for file in batch:
img = cv2.imread(file,1)
resize = cv2.resize(img, (100,100))
if not os.path.exists("files/batchOut"):
os.makedirs("files/batchOut")
cv2.imwrite(f"files/batchOut/resized_{file}", resize)
You can use os.path.basename to isolate the file name from your path string like this:
batch = glob.glob("files/batch/*.jpg")
for file in batch:
img = cv2.imread(file,1)
resize = cv2.resize(img, (100,100))
if not os.path.exists("files/batchOut"):
os.makedirs("files/batchOut")
file_name = os.path.basename(file)
cv2.imwrite(f"files/batchOut/resized_{file_name}", resize)
You may find this to be a more robust approach. You certainly only want to call makedirs once:
import os
from glob import glob
import cv2
import sys
source_directory = '<your source directory>'
target_directory = '<your target directory>'
pattern = '*.jpg'
prefix = 'resized_'
dims = (100, 100)
os.makedirs(target_directory, exist_ok=True)
for filename in glob(os.path.join(source_directory, pattern)):
try:
img = cv2.imread(filename, cv2.IMREAD_COLOR)
newfile = f'{prefix}{os.path.basename(filename)}'
newfilepath = os.path.join(target_directory, newfile)
cv2.imwrite(newfilepath, cv2.resize(img, dims))
except Exception as e:
print(f'Failed to process {filename} due to {e}', file=sys.stderr)
Was able to alter the name using the replace() function.
Important for "batch\" double backward slashes are required i.e. "batch\\"
batch = glob.glob("files/batch/*.jpg")
for file in batch:
img = cv2.imread(file,1)
resize = cv2.resize(img, (100,100))
if not os.path.exists("files/batchOut"):
os.makedirs("files/batchOut")
cv2.imwrite("files/batchOut/resized_" + file.replace("files/batch\\", "" ) + ".jpg", resize)

Why are my cropped images being saved to the incorrect directory?

I'm writing a program that iterates over a directory of satellite images, crops each image to have a square aspect ratio (1:1), and then saves the cropped image in a different directory created at the beginning of the program. I'm able to crop each image successfully, but the cropped image is being saved to its original directory instead of the one created at the start of the program.
For example, the file path leading up to, but not including, the directory containing imagery is C:\Users\nickm\Documents\Projects\Platform\Imagery, while the directory containing the satellite imagery is dir (a subdirectory of Imagery). After each image is cropped, I want to save it to the directory created at the start of the program (e.g. 10-22-18 cropped, which will also be a subdirectory of Imagery). Instead, it's being saved in dir, overwriting the original image.
Here's my code:
# image.py
import datetime
import os
from PIL import Image
def make_new_dir(abs_path):
'''Creates the directory where our cropped imagery will be saved and
returns its absolute file path.
'''
date_obj = datetime.datetime.now()
date = date_obj.strftime('%x').replace('/', '-')
new_path = abs_path + '/' + date + ' cropped'
os.mkdir(new_path)
return new_path
def get_crop_area(image):
'''Crops each image to have a square aspect ratio (1:1) using the
image's size.
'''
image_width, image_height = image.size
diff = max(image_width, image_height) - min(image_width, image_height)
if image_width > image_height:
return [diff / 2, 0, image_width - diff / 2, image_height]
else:
return [0, diff / 2, image_width, image_height - diff / 2]
def crop_images(abs_path, image_dir, new_dir):
'''Iterates over the directory containing the satellite images
(abs_path + image_dir), cropping each image and saving it to our
new directory (the value returned from our make_new_dir function).
'''
new_dir = os.path.abspath(new_dir)
image_dir = os.path.join(abs_path, image_dir)
images = os.listdir(image_dir)
for image in images:
image_path = os.path.join(image_dir, image)
image = Image.open(image_path)
crop_area = get_crop_area(image)
cropped_image = image.crop(crop_area)
cropped_image_path = os.path.join(new_dir, image.filename)
cropped_image.save(cropped_image_path, 'JPEG')
The program is being run with run.py. abs_path and image_dir are being provided by the user at the command line and used as arguments in our make_new_dir and crop_images functions. This is what it looks like when I start my script from the command line:
C:\Users\nickm\Documents\Projects\Code\image>python run.py C:\Users\nickm\Documents\Projects\Platform\Imagery dir
Note that the absolute file path and the directory containing the images are two different command line arguments.
Here's my run.py script:
# run.py
import sys
from image import make_new_dir, get_crop_area, crop_images
if __name__ == '__main__':
filename, abs_path, image_dir = sys.argv
new_dir = make_new_dir(abs_path)
crop_images(abs_path, image_dir, new_dir)
This is the first program I've created that isn't just a basic coding exercise, so I'm wondering if I'm incorrectly implementing os.path.join. I've looked here and here for clarification, but neither employs the os module, which I'm pretty sure is where I'm encountering my issue.
Thanks in advance for any help provided.
If image.filename returns the full image path, you can get only the filename by doing this:
image_filename = os.path.basename(image.filename)

Pillow program to do watermark

I've done a python script using Pillow to automatically watermark the images on one folder and save the watermarked image to other folder. The program is made but I noticed that the new photos come with some more MB like the original one is 10Mb and the watermarked is 25Mb and the program also takes a lot of time to run. I don't know what to do in order to improve it.
Here's the code
from PIL import Image
import os
#foreground = Image.open("watermark.png").convert('RGBA')
#background = Image.open("FotosAntes\\21231891_468587483512430_7958322633319552407_n.jpg").convert('RGBA')
#
#maxsize = (300,300)
#foreground.thumbnail(maxsize, Image.ANTIALIAS)
#
#background.paste(foreground, (670, 500), foreground)
#background.convert('P', palette=Image.ADAPTIVE, colors=256)
#background.save("FotosDepois\\Foto1.png", "PNG")
#
#background.show()
original_path = ("FotosAntes")
destination_path = ("FotosDepois")
#maxsize = (500,500)
foreground = Image.open("arroz.png").convert('RGBA')
#foreground.thumbnail(maxsize, Image.ANTIALIAS)
for (dirName, subDirs, fileNames) in os.walk(original_path):
for i in fileNames:
file_name_op = (os.path.splitext(i)[0])
background = Image.open(os.path.join(dirName, i)).convert('RGBA')
background.paste(foreground, (4550, 2850), foreground)
background.convert('P', palette=Image.ADAPTIVE, colors=256)
outfile = os.path.split
background.save("FotosDepois\\" + file_name_op + ".png")
print("Foto complete")
The first comments was the version of my program that I tested to do only one photo and then I created the final program (the loop).

Resize multiple images in a folder (Python)

I already saw the examples suggested but some of them don't work.
So, I have this code which seems to work fine for one image:
im = Image.open('C:\\Users\\User\\Desktop\\Images\\2.jpg') # image extension *.png,*.jpg
new_width = 1200
new_height = 750
im = im.resize((new_width, new_height), Image.ANTIALIAS)
im.save('C:\\Users\\User\\Desktop\\resized.tif') # .jpg is deprecated and raise error....
How can I iterate it and resize more than one image ? Aspect ration need to be maintained.
Thank you
# Resize all images in a directory to half the size.
#
# Save on a new file with the same name but with "small_" prefix
# on high quality jpeg format.
#
# If the script is in /images/ and the files are in /images/2012-1-1-pics
# call with: python resize.py 2012-1-1-pics
import Image
import os
import sys
directory = sys.argv[1]
for file_name in os.listdir(directory):
print("Processing %s" % file_name)
image = Image.open(os.path.join(directory, file_name))
x,y = image.size
new_dimensions = (x/2, y/2) #dimension set here
output = image.resize(new_dimensions, Image.ANTIALIAS)
output_file_name = os.path.join(directory, "small_" + file_name)
output.save(output_file_name, "JPEG", quality = 95)
print("All done")
Where it says
new_dimensions = (x/2, y/2)
You can set any dimension value you want
for example, if you want 300x300, then change the code like the code line below
new_dimensions = (300, 300)
I assume that you want to iterate over images in a specific folder.
You can do this:
import os
from datetime import datetime
for image_file_name in os.listdir('C:\\Users\\User\\Desktop\\Images\\'):
if image_file_name.endswith(".tif"):
now = datetime.now().strftime('%Y%m%d-%H%M%S-%f')
im = Image.open('C:\\Users\\User\\Desktop\\Images\\'+image_file_name)
new_width = 1282
new_height = 797
im = im.resize((new_width, new_height), Image.ANTIALIAS)
im.save('C:\\Users\\User\\Desktop\\test_resize\\resized' + now + '.tif')
datetime.now() is just added to make the image names unique. It is just a hack that came to my mind first. You can do something else. This is needed in order not to override each other.
I assume that you have a list of images in some folder and you to resize all of them
from PIL import Image
import os
source_folder = 'path/to/where/your/images/are/located/'
destination_folder = 'path/to/where/you/want/to/save/your/images/after/resizing/'
directory = os.listdir(source_folder)
for item in directory:
img = Image.open(source_folder + item)
imgResize = img.resize((new_image_width, new_image_height), Image.ANTIALIAS)
imgResize.save(destination_folder + item[:-4] +'.tif', quality = 90)

Loading resized image with cv2.imread failed with TypeError [duplicate]

I have the following code that I thought would resize the images in the specified path
But when I run it, nothing works and yet python doesn't throw any error so I don't know what to do. Please advise. Thanks.
from PIL import Image
import os, sys
path = ('C:\Users\Maxxie\color\complete')
def resize():
for item in os.listdir(path):
if os.path.isfile(item):
im = Image.open(item)
f, e = os.path.splitext(item)
imResize = im.resize((200,200), Image.ANTIALIAS)
imResize.save(f + ' resized.jpg', 'JPEG', quality=90)
resize()
#!/usr/bin/python
from PIL import Image
import os, sys
path = "/root/Desktop/python/images/"
dirs = os.listdir( path )
def resize():
for item in dirs:
if os.path.isfile(path+item):
im = Image.open(path+item)
f, e = os.path.splitext(path+item)
imResize = im.resize((200,200), Image.ANTIALIAS)
imResize.save(f + ' resized.jpg', 'JPEG', quality=90)
resize()
Your mistake is belong to full path of the files. Instead of item must be path+item
John Ottenlips's solution created pictures with black borders on top/bottom i think because he used
Image.new("RGB", (final_size, final_size))
which creates a square new image with the final_size as dimension, even if the original picture was not a square.
This fixes the problem and, in my opinion, makes the solution a bit clearer:
from PIL import Image
import os
path = "C:/path/needs/to/end/with/a/"
resize_ratio = 0.5 # where 0.5 is half size, 2 is double size
def resize_aspect_fit():
dirs = os.listdir(path)
for item in dirs:
if item == '.jpg':
continue
if os.path.isfile(path+item):
image = Image.open(path+item)
file_path, extension = os.path.splitext(path+item)
new_image_height = int(image.size[0] / (1/resize_ratio))
new_image_length = int(image.size[1] / (1/resize_ratio))
image = image.resize((new_image_height, new_image_length), Image.ANTIALIAS)
image.save(file_path + "_small" + extension, 'JPEG', quality=90)
resize_aspect_fit()
In case you want to keep the same aspect ratio of the image you can use this script.
from PIL import Image
import os, sys
path = "/path/images/"
dirs = os.listdir( path )
final_size = 244;
def resize_aspect_fit():
for item in dirs:
if item == '.DS_Store':
continue
if os.path.isfile(path+item):
im = Image.open(path+item)
f, e = os.path.splitext(path+item)
size = im.size
ratio = float(final_size) / max(size)
new_image_size = tuple([int(x*ratio) for x in size])
im = im.resize(new_image_size, Image.ANTIALIAS)
new_im = Image.new("RGB", (final_size, final_size))
new_im.paste(im, ((final_size-new_image_size[0])//2, (final_size-new_image_size[1])//2))
new_im.save(f + 'resized.jpg', 'JPEG', quality=90)
resize_aspect_fit()
Expanding on the great solution of #Sanjar Stone
for including subfolders and also avoid DS warnings you can use the glob library:
from PIL import Image
import os, sys
import glob
root_dir = "/.../.../.../"
for filename in glob.iglob(root_dir + '**/*.jpg', recursive=True):
print(filename)
im = Image.open(filename)
imResize = im.resize((28,28), Image.ANTIALIAS)
imResize.save(filename , 'JPEG', quality=90)
This code just worked for me to resize images..
from PIL import Image
import glob
import os
# new folder path (may need to alter for Windows OS)
# change path to your path
path = 'yourpath/Resized_Shapes' #the path where to save resized images
# create new folder
if not os.path.exists(path):
os.makedirs(path)
# loop over existing images and resize
# change path to your path
for filename in glob.glob('your_path/*.jpg'): #path of raw images
img = Image.open(filename).resize((306,306))
# save resized images to new folder with existing filename
img.save('{}{}{}'.format(path,'/',os.path.split(filename)[1]))
For those that are on Windows:
from PIL import Image
import glob
image_list = []
resized_images = []
for filename in glob.glob('YOURPATH\\*.jpg'):
print(filename)
img = Image.open(filename)
image_list.append(img)
for image in image_list:
image = image.resize((224, 224))
resized_images.append(image)
for (i, new) in enumerate(resized_images):
new.save('{}{}{}'.format('YOURPATH\\', i+1, '.jpg'))
Heavily borrowed the code from #Sanjar Stone. This code work well in Windows OS.
Can be used to bulky resize the images and assembly back to its corresponding subdirectory.
Original folder with it subdir:
..\DATA\ORI-DIR
├─Apolo
├─Bailey
├─Bandit
├─Bella
New folder with its subdir:
..\DATA\NEW-RESIZED-DIR
├─Apolo
├─Bailey
├─Bandit
├─Bella
Gist link: https://gist.github.com/justudin/2c1075cc4fd4424cb8ba703a2527958b
from PIL import Image
import glob
import os
# new folder path (may need to alter for Windows OS)
# change path to your path
ORI_PATH = '..\DATA\ORI-DIR'
NEW_SIZE = 224
PATH = '..\DATA\NEW-RESIZED-DIR' #the path where to save resized images
# create new folder
if not os.path.exists(PATH):
os.makedirs(PATH)
# loop over existing images and resize
# change path to your path
for filename in glob.glob(ORI_PATH+'**/*.jpg'): #path of raw images with is subdirectory
img = Image.open(filename).resize((NEW_SIZE,NEW_SIZE))
# get the original location and find its subdir
loc = os.path.split(filename)[0]
subdir = loc.split('\\')[1]
# assembly with its full new directory
fullnew_subdir = PATH+"/"+subdir
name = os.path.split(filename)[1]
# check if the subdir is already created or not
if not os.path.exists(fullnew_subdir):
os.makedirs(fullnew_subdir)
# save resized images to new folder with existing filename
img.save('{}{}{}'.format(fullnew_subdir,'/',name))
Expanded the answer of Andrei M. In order to only change the height of the picture and automatically size the width.
from PIL import Image
import os
path = "D:/.../.../.../resized/"
dirs = os.listdir(path)
def resize():
for item in dirs:
if item == '.jpg':
continue
if os.path.isfile(path+item):
image = Image.open(path+item)
file_path, extension = os.path.splitext(path+item)
size = image.size
new_image_height = 190
new_image_width = int(size[1] / size[0] * new_image_height)
image = image.resize((new_image_height, new_image_width), Image.ANTIALIAS)
image.save(file_path + "_small" + extension, 'JPEG', quality=90)
resize()
If you want to resize any image from a folder where without images files, other files also exist, then you can try this:
from genericpath import isdir
from PIL import Image
import os, sys
path = "C://...//...//....//...//"
save_path = "C://...//..//...//...//"
images = os.listdir(path)
if not os.path.isdir(save_path):
os.makedirs(save_path)
for image in images:
image_path = os.path.join(path, image)
iamge_save_path = os.path.join(save_path, image)
if image.split(".")[1] not in ["jpg", "png"]:
continue
if os.path.exists(image_path):
im = Image.open(image_path)
image_resized = im.resize((224,224))
image_resized.save(iamge_save_path, quality=90)
# print("saved")
Safer to use pathlib
As jwal commented on a similar question, use the object-oriented counterparts for os of pathlib:
p = Path('images') to define the path instance (here as directory relative to current)
Path.iterdir() to find files in the path instance
Path.absolute() to get the absolute-path for file-IO functions
Path.joinpath(*other) to add subfolders or filenames
Path.mkdir(parents=True, exist_ok=True)
Path.name to return the basename of the file (like picture.png)
from pathlib import Path
# folder = 'images'
# new_dimension = (width, height)
def resize(folder, new_dimension, new_subdir):
images_folder = Path(folder)
for child in images_folder.iterdir():
print("Found image:", child)
image_path = child.absolute()
image = Image.open(image_path)
resized_image = image.resize() # could also add Image.ANTIALIAS
# create if the subdir not exists
subdir = images_folder.join(new_subdir)
if not subdir.exists():
subdir.mkdir(parents=True, exist_ok=True)
to_path = subdir.joinpath(child.name) # join adds the path-separators
print("Saving resized to:", to_path)
resized_image.save(to_path) # could also add save-options like 'JPEG', quality=90

Categories

Resources