Pillow program to do watermark - python

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).

Related

Video created in OpenCv does open, but shows nothing

I've been trying to merge some pictures to create a video, all of this using Opencv. But, the problem here is that Opencv does create the .avi file and it opens, using VLC Media Player, but when I'm trying to watch the video created, it shows nothing and doesn't show how long does the video last. However, the file size is around 6kb. There are 18 images and they have an average size os 252kb. I think that's too weird and incoherent.
Here's a look at my code:
import cv2
import os
frameSize = (500, 500)
with os.scandir('Taylor') as Taylor_Images:
for image in Taylor_Images:
print(image.name)
with os.scandir('Taylor_5') as Taylor5_Images:
for image in Taylor5_Images:
print(image.name)
image_Taylor = []
image_Taylor_5 = []
ext_2 = '.png'
adding = '_5'
path_2 = 'Taylor_5/'
ext = '.png'
path = 'Taylor/'
for i in range(1,10):
img_name = str(i) + ext
img = path + str(i) + ext
image_Taylor.append(img)
img_name_2 = str(i) + ext_2
img_2 = path_2 + str(i) + adding + ext_2
image_Taylor_5.append(img_2)
out = cv2.VideoWriter('output_video2.avi',cv2.VideoWriter_fourcc(*'DIVX'), 60, frameSize)
for i in range(0,9):
img = cv2.imread(image_Taylor[i])
out.write(img)
img_2 = cv2.imread(image_Taylor_5[i])
out.write(img_2)
out.release()
Update 1
As Vatsal suggested, I checked all the sizes of the images and I found that some of them didn't have the same size(Width,Height), so I resized them for having the same size(400,800).
With regard to what Tim said, the images do have that file size, I attach a picture of what I did according to your suggestion of making their file size a multiple of 4.
Checking the size of the images
This is the kind of pictures I'm using
However, the video generated from the script still has a size of 6kB.

How to save images with the same name to the different direction using PIL and os.path?

While trying to split the path to get a name, I get the traceback:
TypeError: expected str, bytes or os.PathLike object, not JpegImageFile . How can I solve it or is there other methods?
I try to save resized images with the same name to a different direction. For this reason, I use os.path.split() functions.
import glob
from PIL import Image
import os
images = glob.glob("/Users/marialavrovskaa/Desktop/6_1/*")
path = "/Users/marialavrovskaa/Desktop/2.2/"
quality_val=95
for image in images:
image = Image.open(image)
image.thumbnail((640, 428), Image.ANTIALIAS)
image_path_and_name = os.path.split(image)
image_name_and_ext = os.path.splitext(image[0])
name = image_name_and_ext[0] + '.png'
name = os.path.splitext(image)[0] + '.png'
file_path = os.path.join(path, name)
image.save(file_path, quality=quality_val)
import glob
from PIL import Image
import os
images = glob.glob("Source_path")
path = r"Destination_path"
quality_val=95
for image in images:
img = Image.open(image)
img.thumbnail((640, 428), Image.ANTIALIAS)
name = os.path.split(image)
file_path = os.path.join(path, name[1])
img.save(file_path, quality=quality_val)
The primary problem with your code was that you were using a variable and an object under the same name image. Which was causing problems.
LOGICAL ERRORS:-
image_path_and_name is a needless variable in the code, as it is
used for nothing.
name has been initialized with totally different values twice,
instead use name = os.path.split(image) which serves the purpose
of both.
you should not try to explicitly define the extension of each image
as .png as it might create issues when dealing with other image
formats.
for image in images:
image = Image.open(image)
image.thumbnail((640, 428), Image.ANTIALIAS)
image_path_and_name = os.path.split(image)
When you say image = Image.open(image), you're overwriting the loop variable also named image, and it's no longer a splittable string.
Change one of the image variables to a different name.
firstly,
image_name_and_ext = os.path.splitext(image[0])
should be
image_name_and_ext = os.path.splitext(image_path_and_name[1])
because image is string so image[0] just get first character of image not useless in this case
secondly,
name = os.path.splitext(image)[0] + '.png' equal image
name = os.path.splitext(image)[0] should return path of image not include extention
to solve this problem, you can try:
for image in images:
img = Image.open(image)
img.thumbnail((640, 428), Image.ANTIALIAS)
name = os.path.split(image)
file_path = os.path.join(path, name[1])
image.save(file_path, quality=quality_val)
By the code above you will get image in thumbnails I recommend to use resize function because from resize you can maintain you aspect ratio that helps you in getting better results.
image.thumbnail((640, 428), Image.ANTIALIAS)
this line of code is converting your thumbnail.which is not good approach of resizing. Try the code below.
import os
from PIL import Image
PATH = "F:\\FYP DATASET\\images\\outliers Dataset\\Not Outliers\\"
Copy_to_path="F:\\FYP DATASET\\images\\outliers Dataset\\"
for filename in os.listdir(PATH):
img = Image.open(os.path.join(PATH, filename)) # images are color images
img = img.resize((224,224), Image.ANTIALIAS)
img.save(Copy_to_path+filename+'.jpeg')
In this code you are taking images directly from folder resize them and saving them to other location with same name. All the images are processing one by one So you need not worry to load all the images at once into the memory.

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)

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)

Difficulty in writing crops of images using OpenCV and Python

I am using the following code to read multiple images from a folder and to take a specific crop from all of them and also write them at the end. The cropping part does not seem to work meaning the cropped parts are not getting written.
# import the necessary packages
import cv2
import os, os.path
#image path and valid extensions
imageDir = "C:\\Users\\Sayak\\Desktop\\Training\\eye\\1" #specify your path here
image_path_list = []
valid_image_extensions = [".jpg", ".jpeg", ".png", ".tif", ".tiff"] #specify your vald extensions here
valid_image_extensions = [item.lower() for item in valid_image_extensions]
#create a list all files in directory and
#append files with a vaild extention to image_path_list
for file in os.listdir(imageDir):
extension = os.path.splitext(file)[1]
if extension.lower() not in valid_image_extensions:
continue
image_path_list.append(os.path.join(imageDir, file))
#loop through image_path_list to open each image
for imagePath in image_path_list:
image = cv2.imread(imagePath)
# display the image on screen with imshow()
# after checking that it loaded
if image is not None:
cv2.imshow(imagePath, image)
elif image is None:
print ("Error loading: " + imagePath)
#end this loop iteration and move on to next image
continue
crop_img = image[200:400, 100:300]
cv2.imwrite('pic{:>05}.jpg'.format(imagePath), crop_img)
# wait time in milliseconds
# this is required to show the image
# 0 = wait indefinitely
# exit when escape key is pressed
key = cv2.waitKey(0)
if key == 27: # escape
break
# close any open windows
cv2.destroyAllWindows()
I have modified your code posted above. The problem lies with your string formatting used in cv2.imwrite(). The first argument must be an absolute path to where the file should be saved, but your code is passing in something like this.
pic{:>05}.jpg => pic/home/ubuntu/Downloads/10_page.png.jpg. When I used a valid file name there is no problem saving the cropped image at all.
#loop through image_path_list to open each image
for i,imagePath in enumerate(image_path_list):
image = cv2.imread(imagePath)
# display the image on screen with imshow()
# after checking that it loaded
if image is not None:
cv2.imshow(imagePath, image)
elif image is None:
print ("Error loading: " + imagePath)
#end this loop iteration and move on to next image
continue
# Please check if the size of original image is larger than the pixels you are trying to crop.
(height, width, channels) = image.shape
if height >= 400 and width >= 300:
plt.imshow(image)
plt.title('Original')
plt.show()
crop_img = image[100:400, 100:400]
# Problem lies with this path. Ambiguous like pic/home/ubuntu/Downloads/10_page.png.jpg
print('pic{:>05}.jpg'.format(imagePath))
# Try a proper path. A dirname + file_name.extension as below, you will have no problem saving.
new_image = os.path.join(imageDir,'{}.png'.format(str(i)))
cv2.imwrite(new_image, crop_img)
plt.imshow(crop_img)
plt.title('Cropped')
plt.show()

Categories

Resources