Python Attribute Error Raised while using Thumbnail method of PIL - python

I am using PIL to make an application to open all images in a folder. I sought for tutorials for PIL. I tried to find tutorials with list of images, but I failed to do so. I found some, but I had to list the file location beforehand. It annoyed me. So, instead I want the user to choose a folder, and the application would load all the images for the user. But, while making the thumbnails for the list of images, I got an error which I'm not familiar with. This is the exact error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Admin\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line
1892, in __call__
return self.func(*args)
File "f:\OG\Python\ImageViewer.py", line 47, in openFolder
GetFiles()
File "f:\OG\Python\ImageViewer.py", line 87, in GetFiles
with Image.open(i) as img:
prefix = fp.read(16)
raise AttributeError(name)
The minimal code to get this error is:
import glob
from PIL import Image, ImageTk
fileDir = "Your Folder"
imageList = []
image_list = []
for filename in glob.glob(fileDir + '/*.jpg'): # gets jpg
im = Image.open(filename)
imageList.append(im)
for i in imageList:
with Image.open(i) as img: # This raises the error
imageList[i] = img.thumbnail((550, 450))
for i in image_list: # Would this work?
image_list[i] = ImageTk.PhotoImage(imageList[i])
I would like to know if the code that is commented with 'Would this work?' would work or not.

Just remove the reading part again which doesn't make sense
import glob
from PIL import Image, ImageTk
fileDir =r"your path"
imageList = []
for filename in glob.glob(fileDir + '/*.jpg'): # gets jpg
im = Image.open(filename)
imageList.append(im)
imageList will look like this :
[<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=200x200 at 0x25334A87D90>]
here is the blockbuster solution
import glob
from PIL import Image, ImageTk
import PIL
from pathlib import Path
fileDir = r"your_path_here"
imageList = []
for filename in glob.glob(fileDir + '/*.jpg'): # gets jpg
im = Image.open(filename)
imageList.append(im)
im.thumbnail((550, 450))
im.save(fileDir+'/'+Path(filename).name.split('.')[0]+'_thumbnail.png')

I solved it, I edited the code as follows:
import glob
from PIL import Image, ImageTk
fileDir = "Your Folder"
imageList = []
image_list = []
count = 0
for filename in glob.glob(fileDir + '/*.jpg'): # gets jpg
imageList.append(filename)
for i in imageList:
with Image.open(i) as img:
i = img.thumbnail((550, 450))
for i in imageList: # This gives a Key Error Now
image_list.append(ImageTk.PhotoImage(imageList[count]))
count = count + 1
Basically, Introduced a new variable count with a value of 0, removed open from first for loop, used append method for the last for loop and added count 1 each time :)

Related

Add white background and resize images in a folder

I want to add a white background to my transparant images (png) and resize them. The images are located in a folder. I need to do bulk work, not 1 image at the time.
I removed the background from the images first with rembg (works good) and now I want to change the images.
My code
import rembg
import glob
from pathlib import Path
from rembg import remove, new_session
session = new_session()
for file in Path(r'C:\test\images').glob('*.jpg'):
input_path = str(file)
output_path = str(file.parent / (file.stem + ".out.png"))
with open(input_path, 'rb') as i:
with open(output_path, 'wb') as o:
input = i.read()
output = remove(input, session=session)
o.write(output)
I do not know how to add the white backgroud and resize with python because I'm fairly new to this. Thank you in advance!
I think you want a helper function to do the work, something like:
from PIL import Image
import rembg
def process(session, image, *, size=None, bgcolor='white'):
"session is a rembg Session, and image is a PIL Image"
if size is not None:
image = image.resize(size)
else:
size = image.size
result = Image.new("RGB", size, bgcolor)
out = rembg.remove(image, session=session)
result.paste(out, mask=out)
return result
The idea being that you pass a rembg Session and a Pillow Image in and it will remove the background and flatten that image, resizing along the way.
As a working example, you could do something like:
from io import BytesIO
import requests
session = rembg.new_session("u2netp")
res = requests.get("https://picsum.photos/600")
res.raise_for_status()
with Image.open(BytesIO(res.content)) as img:
out = process(session, img, size=(256, 256), bgcolor='#F0E68C')
out.save("output.png")
For example, an input and output might be:
If you wanted to work with lots of files, your pathlib objects can be passed directly to Pillow:
from pathlib import Path
for path_in in Path(r'C:\test\images').glob('*.jpg'):
path_out = path_in.parent / f"{path_in.stem}-out.png"
# no point processing images that have already been done!
if path_out.exists():
continue
with Image.open(path_in) as img:
out = process(session, img, size=(256, 256), bgcolor='#F0E68C')
out.save(path_out)
Update: it's often worth adding a check into these loops so they can be rerun and not have to process everything again. If you really do want images to be re-processed then just delete *-out.png

TypeError: NoneType, when trying to loop crop images

from os import listdir
import cv2
files=listdir('/home/raymond/Desktop/Test/Test') #Importing the dir for cropping
for file in files:
img = cv2.imread('/home/raymond/Desktop/Test/Test'+file) # reading a single image from the dir
crop_img = img[0:1600, 0:1600]
cv2.imwrite('/home/raymond/Desktop/Test/cropped'+file,crop_img) # write new data to img
Im trying to loop crop images, while getting an error of
Traceback (most recent call last):
File "Files.py", line 8, in <module>
crop_img = img[0:1600, 0:1600]
TypeError: 'NoneType' object is not subscriptable
(fixi) ➜ exercises
You are probably missing a slash at the end of the path here:
img = cv2.imread('/home/raymond/Desktop/Test/Test'+file) # reading a single image from the dir
Should be:
img = cv2.imread('/home/raymond/Desktop/Test/Test/'+file) # reading a single image from the dir
or even better:
import os
img = cv2.imread(os.path.join('/home/raymond/Desktop/Test/Test/',file)) # reading a single image from the dir
img = cv2.imread('/home/raymond/Desktop/Test/Test'+file)
Hello Dan Raymond,
This cannot work because Python does not add a slash (/) before listed filenames.
Which means that if you have a filename "hello", then what is appended to '/home/raymond/Desktop/Test/Test' is "hello" which results in '/home/raymond/Desktop/Test/Testhello' which does not exist.
Replace your line with this:
img = cv2.imread('/home/raymond/Desktop/Test/Test/'+file)

image to text conversion using Tesseract

I am trying to load all images in a folder and extract text from images. I keep getting error message for the second for loop. For example,
AttributeError: 'numpy.ndarray' object has no attribute 'read'
It seems I cannot access list Img. Any idea?
# import OpenCV, Numpy, Python image library, Tesseract OCR
import os
import cv2
import numpy
from PIL import Image
import pytesseract
import glob
#set tesseract path
pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files (x86)/Tesseract-OCR/tesseract.exe'
#read all image with .jpg format in a specifying folder
img = []
for i in glob.glob("C:\\Users\\daizhang\\Desktop\\Deloitte Development\\Python\\Reports\\Image\\*.jpg"):
n= cv2.imread(i,0) #convert image to grayscale
print(i)
img.append(n)
for j in img:
im = Image.open(j)
text = pytesseract.image_to_string (j, lang='eng')
with open("C:\\Users\\daizhang\\Desktop\\Deloitte Development\\Python\Reports\\Image\\test.txt", "w") as f:
f.write(text.encode('utf8'))
I have Mac OSX but you can adjust this code to file Window's path directory.
import os
from os import path
from glob import glob
from pytesseract import image_to_string
from PIL import Image, ImageEnhance, ImageFilter
def enhance_img(filename):
# Enhance image and save as under new name
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
im.save('newfilename')
def convert_img(filename):
image = Image.open(filename)
# Convert image to text
file = open ('parsing.txt', 'a')
file.write(image_to_string(image))
file.close
def find_ext(dir, ext):
return glob(path.join(dir, "*.{}".format(ext)))
# use the following for change directory
# os.chdir(path)
filename = find_ext("","png")
for file in filename:
# convert image to text
convert_img(file)
If you want to enhance the image then include the following block and adjust the code above to loop through the new filenames.
def enhance_img(filename):
# Enhance image and save as under new name
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
im.save('newfilename')
For file in filename:
# to enhance image if needed
newfilename = filename[-3] + '_1.png'
enhance_img(file)

Python concatinating a string and an intiger counter to name content inside a folder

I am using widows 10 pro, python 3.6.2rc1. I am training a convolutional neural network made by tensorflow. As a preprocessing phase, I hae written the following code to resize each image. It works perfectly well, but since I have more than 100 training images (I made it quite low just to see how it works at the moment) with very different names, and at the end I'd like all of them follow the same naming convention as in "image001", "image002" and so on, I added a counter and use it to change the name of the image before saving it to the same folder by using cv2.imwrite(). But I am getting this error:
Traceback (most recent call last):
File "E:/Python/TrainingData/TrainingPrep.py", line 11, in <module>
cv2.imwrite(imageName,re)
cv2.error: D:\Build\OpenCV\opencv-3.2.0\modules\imgcodecs\src\loadsave.cpp:531: error: (-2) could not find a writer for the specified extension in function cv::imwrite_
import cv2
import glob
i=0
images = glob.glob("*.jpg")
for image in images:
img = cv2.imread(image,1)
counter=str(i)
re = cv2.resize(img,(128,128))
imageName = "image"+counter
cv2.imwrite(imageName,re)
i=i+1
print(counter)
I need my images have the names image001, image00x. I appreciate if you help me solve this problem.
Thank you very much.
The imwrite method expects the extension to determine the file format.
Simply change your line to (for PNG, or whatever file format you want) and it should work:
imageName = "image"+counter+".png"
You can rename the files later if you so wish, using glob.glob. A working example should be something like this:
import cv2
import glob
import os
i=0
images = glob.glob("*.jpg")
for image in images:
img = cv2.imread(image,1)
counter=str(i)
re = cv2.resize(img,(128,128))
imageName = "image"+counter+".jpg"
cv2.imwrite(imageName,re)
i=i+1
print(counter)
rename = glob.glob("images*.jpg")
for src in rename:
dst = os.path.splitext(item)[0]
os.rename(src, dst)
This method will give you the leading zeros you want in the file name:
import cv2
import glob
i=0
images = glob.glob("*.jpg")
for image in images:
img = cv2.imread(image,1)
re = cv2.resize(img,(128,128))
imageName = "image{:03d}.png".format(i) # format i as 3 characters with leading zeros
cv2.imwrite(imageName,re)
i=i+1
print(counter)

IOError: cannot identify image file when loading images from pdf files

I am trying to read scanned images from a pdf using wand and display it using PIL. But I get some error. First page of the pdf file works perfectly but the second page shows this error.
Code
from wand.image import Image
from wand.display import display
from PIL import Image as PI
import pyocr
import pyocr.builders
import io
import numpy as np
import cStringIO
tool = pyocr.get_available_tools()[0]
lang = tool.get_available_languages()[1]
req_image = []
final_text = []
image_pdf = Image(filename="DEEP_PLAST_20.700.pdf", resolution=200)
image_jpeg = image_pdf.convert('jpeg')
img_page = Image(image=image_jpeg.sequence[1])
img_buffer = np.asarray(bytearray(img_page.make_blob()), dtype=np.uint8)
print(img_buffer)
# im = PI.fromarray(img_buffer)
im = PI.open(cStringIO.StringIO(img_buffer))
I get this error.
Traceback (most recent call last):
File "ocr.py", line 43, in <module>
im = PI.open(cStringIO.StringIO(img_buffer))
File "/home/sahil/anaconda2/lib/python2.7/site-packages/PIL/Image.py", line 2452, in open
% (filename if filename else fp))
IOError: cannot identify image file <cStringIO.StringI object at 0x7fc4a8f168b0>
I don't why the code fails on the second page of the pdf whereas it works for the first one.
Any help would be appreciated!

Categories