Difficulty in writing crops of images using OpenCV and Python - 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()

Related

Python Program Doesn't Recognize Input

I have a program that is supposed to convert an image to a squared png with transparent borders (if the image is 1000x1500 then the png is 1500x1500 and then the image will be placed on the middle of the png creating a transparent border of 250x1500 on both sides). The program is supposed to import the image from a folder which I you can choose which you wish to import from, and then export it to another folder that you can also choose. I use recursion to go throw all images from the folder, however it says that the input is not recognizable. Can anyone help me with this one? You have everything you need explained on the code I'll send right now:
from PIL import Image
from os import listdir
from os.path import isfile, join,splitext
Folder_Input = 'D:\\0Pi_\Downloads\ScpServer\Originais' #directory where we will upload images
Folder_Output ='D:\\0Pi_\Downloads\ScpServer\PNGs' #directory where we will save images
typelist = ['.png','.jpg','.jpeg']
images_list = [f for f in listdir(Folder_Input) if isfile(join(Folder_Input, f)) and splitext(f)[1].lower() in typelist]
for im in images_list:
try:
image = Image.open(im) #this is supposed to open the image, however it doesn't. what's missing
except:
print(f'Problem opening image{im}!\n')
image.close()
continue
width, height = image.size
if height >= width:
new_width = height
new_height = height
else:
new_width = width
new_height = width
result = Image.new(mode = 'RGBA', size = (new_width, new_height) ,color = (0,0,0,0)) #creates a new transparent squared png
offset = ((new_width - width) // 2, (new_height - height) // 2) #centers the image in relation to the squared png
result.paste(image,offset) #unites both the image and the squared layer
image.close() #closes the file now finished
output_file = join(Folder_Output,splitext(im)[0] + '.png')
if not isfile(output_file):
result.save(output_file) #saves file on the output folder
else:
print(f"The file {splitext(im)[0] + '.png'} was not saved because it already exists on {Folder_Output}!\n")
This is the Tracebak:
Traceback (most recent call last):
File "D:/0Pi_/Documents/add_borders.py", line 16, in <module>
image.close()
builtins.NameError: name 'image' is not defined
If the try/except block fails, it may not have assigned the object to the image variable.
try:
image = Image.open(im) # this is supposed to open the image, however it doesn't. what's missing
except:
print(f'Problem opening image{im}!\n')
image.close() # will have problem here
Since, you are looking only to the Image.open(im) if it was succeed, just remove image.close() from the except or, use another try/except to close the object. Maybe the im is not readable or have a wrong path, so that will cause to fail.

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.

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

cv2.resize() error: saves the same picture with different names

I am new in programming and trying to make an image resizer. I wanted to make possibility to write custom prefix by the user before in the filenames. Sizes are also customable.
The cv2.imshow() works fine, but cv2.resize() does not. If I check it with imshow, it shows only one picture despite of the for loop, and then cv2.imwrite saves only one picture with the names all the selected pictures.
The lists seems to be OK.
I hope I am clear, the code:
def openfiles():
global picture_original
global file_path
global f
# Valid filetypes
file_types=[("Jpeg files","*.jpg"),("PNG files","*.png"),("BMP files","*.bmp"),("all files","*.*")]
window.filenames = filedialog.askopenfilenames(initialdir = "/",title = "Select file",filetypes = (file_types)) # TUPLE of filepath/filenames
#f = []
# Creating a list from the tuple
for pics in window.filenames:
f.append(pics)
f = [picture.replace('/', "\\") for picture in f]
try:
for picture in f:
picture_original = cv2.imread(picture, 1)
#cv2.imshow("Preview", picture_original)
#cv2.waitKey(1)
except:
msgbox_openerror() # Error opening the file
# Getting the filepath only from the list "f":
file_path = f[0].rsplit("\\",1)[0]
view_list()
def save_command():
"""
function to save the resized pictures
"""
global picture_resized
global prefix
prefix = "Resized_"
lst_filename = []
lst_renamed = []
for i in f:
#print(f)
path,filename = os.path.split(i) # path - only filepath | filename - only filename with extension
lst_filename.append(prefix+filename)
for i in range(len(f)):
lst_renamed.append(os.path.join(path, lst_filename[i]))
for i in range(len(f)):
picture_resized = cv2.resize(picture_original, ((int(width.get())), int(height.get())))
cv2.imshow("Preview", picture_resized)
cv2.waitKey(1)
for i in lst_renamed:
cv2.imwrite(i, picture_resized)
I hope someone have some ideas. Thank you in advance!
This is an example to resize by a ratio and saves your image
def ResizeImage(filepath, newfileName,ratio):
image = cv2.imread(filepath) #Open image
height, width = image.shape[:2] #Shapes
image2 = cv2.resize(image, (width/ratio, height/ratio), interpolation = cv2.INTER_AREA)
cv2.imwrite(newfileName,image2) #saves, True if OK
return filepath
So if you call
image = "originalpath"
resized = ResizeImage(image,"Resized_"+image,2)
newImage = cv2.imread(resized)
cv2.imshow("new",newImage)
cv2.waitKey(1)
You should get your Image resized by half

Categories

Resources