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
Related
I have a lot of URLs of images stored on the web, example of a URL is as follows :
https://m.media-amazon.com/images/M/MV5BOWE4M2UwNWEtODFjOS00M2JiLTlhOGQtNTljZjI5ZTZlM2MzXkEyXkFqcGdeQXVyNjUwNzk3NDc#._V1_QL75_UX190_CR0
I want to load images from a similar URL as mentioned above and then do some operations on that image then return the resulting image.
So here's my code :
def get_image_from_url(url, path):
try:
# downloading image from url
img = requests.get(url)
with open(path, 'wb') as f:
f.write(img.content)
# reading image, str(path) since path is object of Pathlib's path class
img = cv2.imread(str(path), cv2.IMREAD_COLOR)
# some operations
# deleting that downloaded image since it is of no use now
if os.path.exists(path):
os.remove(path)
return resulting_image
except Exception as e:
return np.zeros((224, 224, 3), np.uint8)
But this process is taking too much time so I thought instead of downloading and deleting the image I will directly load that image present on the URL into a variable.
Something like this :
def store_image_from_url(url):
image = get_image_from_url(url) # without downloading it into my computer
# do some operations
return resulting_image
Is there any way to do the same?
Thank you
As How can I read an image from an Internet URL in Python cv2, scikit image and mahotas?, it can be something like this :
import cv2
import urllib
import numpy as np
def get_image_from_url(url):
req = urllib.urlopen(url)
arr = np.asarray(bytearray(req.read()), dtype=np.uint8)
img = cv2.imdecode(arr, -1)
return img
I would like to extract text from scanned PDFs.
My "test" code is as follows:
from pdf2image import convert_from_path
from pytesseract import image_to_string
from PIL import Image
converted_scan = convert_from_path('test.pdf', 500)
for i in converted_scan:
i.save('scan_image.png', 'png')
text = image_to_string(Image.open('scan_image.png'))
with open('scan_text_output.txt', 'w') as outfile:
outfile.write(text.replace('\n\n', '\n'))
I would like to know if there is a way to extract the content of the image directly from the object converted_scan, without saving the scan as a new "physical" image file on the disk?
Basically, I would like to skip this part:
for i in converted_scan:
i.save('scan_image.png', 'png')
I have a few thousands scans to extract text from. Although all the generated new image files are not particularly heavy, it's not negligible and I find it a bit overkill.
EDIT
Here's a slightly different, more compact approach than Colonder's answer, based on this post. For .pdf files with many pages, it might be worth adding a progress bar to each loop using e.g. the tqdm module.
from wand.image import Image as w_img
from PIL import Image as p_img
import pyocr.builders
import regex, pyocr, io
infile = 'my_file.pdf'
tool = pyocr.get_available_tools()[0]
tool = tools[0]
req_image = []
txt = ''
# to convert pdf to img and extract text
with w_img(filename = infile, resolution = 200) as scan:
image_png = scan.convert('png')
for i in image_png.sequence:
img_page = w_img(image = i)
req_image.append(img_page.make_blob('png'))
for i in req_image:
content = tool.image_to_string(
p_img.open(io.BytesIO(i)),
lang = tool.get_available_languages()[0],
builder = pyocr.builders.TextBuilder()
)
txt += content
# to save the output as a .txt file
with open(infile[:-4] + '.txt', 'w') as outfile:
full_txt = regex.sub(r'\n+', '\n', txt)
outfile.write(full_txt)
UPDATE MAY 2021
I realized that although pdf2image is simply calling a subprocess, one doesn't have to save images to subsequently OCR them. What you can do is just simply (you can use pytesseract as OCR library as well)
from pdf2image import convert_from_path
for img in convert_from_path("some_pdf.pdf", 300):
txt = tool.image_to_string(img,
lang=lang,
builder=pyocr.builders.TextBuilder())
EDIT: you can also try and use pdftotext library
pdf2image is a simple wrapper around pdftoppm and pdftocairo. It internally does nothing more but calls subprocess. This script should do what you want, but you need a wand library as well as pyocr (I think this is a matter of preference, so feel free to use any library for text extraction you want).
from PIL import Image as Pimage, ImageDraw
from wand.image import Image as Wimage
import sys
import numpy as np
from io import BytesIO
import pyocr
import pyocr.builders
def _convert_pdf2jpg(in_file_path: str, resolution: int=300) -> Pimage:
"""
Convert PDF file to JPG
:param in_file_path: path of pdf file to convert
:param resolution: resolution with which to read the PDF file
:return: PIL Image
"""
with Wimage(filename=in_file_path, resolution=resolution).convert("jpg") as all_pages:
for page in all_pages.sequence:
with Wimage(page) as single_page_image:
# transform wand image to bytes in order to transform it into PIL image
yield Pimage.open(BytesIO(bytearray(single_page_image.make_blob(format="jpeg"))))
tools = pyocr.get_available_tools()
if len(tools) == 0:
print("No OCR tool found")
sys.exit(1)
# The tools are returned in the recommended order of usage
tool = tools[0]
print("Will use tool '%s'" % (tool.get_name()))
# Ex: Will use tool 'libtesseract'
langs = tool.get_available_languages()
print("Available languages: %s" % ", ".join(langs))
lang = langs[0]
print("Will use lang '%s'" % (lang))
# Ex: Will use lang 'fra'
# Note that languages are NOT sorted in any way. Please refer
# to the system locale settings for the default language
# to use.
for img in _convert_pdf2jpg("some_pdf.pdf"):
txt = tool.image_to_string(img,
lang=lang,
builder=pyocr.builders.TextBuilder())
I'm trying to resize a set of images, approximatively 366, so I created a script that I tested first on 3 and it was successful.
The issue is when I process the whole folder, it returns me this error :
resizeimage.imageexceptions.ImageSizeError: 'Image is too small, Image size : (275, 183), Required size : (399, 399)'
My script is supposed to iterate an entire folder, resize images then store the output files in another folder:
import os
from PIL import Image
from resizeimage import resizeimage
path = "/Users/sigc2sige/PycharmProjects/helloworld/photos"
size = (399, 399)
for file in os.listdir(path):
with open('/Users/sigc2sige/PycharmProjects/helloworld/photos/'+file, 'r+b') as f:
with Image.open(f) as image:
cover = resizeimage.resize_cover(image, size, Image.ANTIALIAS)
cover.save('/Users/sigc2sige/PycharmProjects/helloworld/photos_2/'+file, image.format)
I did use this instruction:
thumb = ImageOps.fit(image, size, Image.ANTIALIAS) but I believe that it crops images instead of resizing them.
If you have any ideas about how to solve this issue, it would be great.
Downsampling an image (making it smaller) is one thing, and upsampling (making it bigger) is another thing. If you want to downsample, ANTIALIAS is a good choice, if you want to upsample, there are other filters you could use.
import os
from PIL import Image
from resizeimage import resizeimage
path = "/Users/sigc2sige/PycharmProjects/helloworld/photos"
size = (399, 399)
for file in os.listdir(path):
with open('/Users/sigc2sige/PycharmProjects/helloworld/photos/'+file, 'r+b') as f:
with Image.open(f) as image:
if (image.size) >= size:
cover = resizeimage.resize_cover(image, size, Image.ANTIALIAS)
cover.save('/Users/sigc2sige/PycharmProjects/helloworld/photos_2/'+file, image.format)
else:
cover = image.resize(size, Image.BICUBIC).save('/Users/sigc2sige/PycharmProjects/helloworld/photos_2/'+file, image.format)
Now, I have a python game that has sprites, and it obtains the images from files in its directory. I want to make it such that I do not even need the files. Somehow, to pre-store the image in a variable so that i can call it from within the program, without the help of the additional .gif files
The actual way i am using the image is
image = PIL.Image.open('image.gif')
So it would be helpful if you could be precise about how to replace this code
Continuing #eatmeimadanish's thoughts, you can do it manually:
import base64
with open('image.gif', 'rb') as imagefile:
base64string = base64.b64encode(imagefile.read()).decode('ascii')
print(base64string) # print base64string to console
# Will look something like:
# iVBORw0KGgoAAAANS ... qQMAAAAASUVORK5CYII=
# or save it to a file
with open('testfile.txt', 'w') as outputfile:
outputfile.write(base64string)
# Then make a simple test program:
from tkinter import *
root = Tk()
# Paste the ascii representation into the program
photo = 'iVBORw0KGgoAAAANS ... qQMAAAAASUVORK5CYII='
img = PhotoImage(data=photo)
label = Label(root, image=img).pack()
This is with tkinter PhotoImage though, but I'm sure you can figure out how to make it work with PIL.
Here is how you can open it using PIL. You need a bytes representation of it, then PIL can open a file like object of it.
import base64
from PIL import Image
import io
with open("picture.png", "rb") as file:
img = base64.b64encode(file.read())
img = Image.open(io.BytesIO(img))
img.show()
So I've been trying to make a meme bot, in python using PILLOW (a PIL fork) basically it takes a random template and a random source image and puts them together.
So far I managed to make a version which puts the source image adequately in the template, but fails to resize it. Here's my code:
P. S. I mainly code in C, so my python ain't that great
from PIL import Image, ImageOps
import os, random
import re
import linecache
import string
temp_dir = "temp dir"
source_dir = "source dir"
memes_dir = "memes dir"
#Random template & source image
rand_temp = random.choice(os.listdir(temp_dir))
rand_source = random.choice(os.listdir(source_dir))
#template
bot = Image.open(temp_dir + rand_temp)
#source image
top = Image.open(source_dir + rand_source)
width, height = bot.size
size = (width, height)
#Puts Source image in template
meme = ImageOps.fit(top, size, Image.ANTIALIAS)
meme.paste(bot, (0,0), bot)
meme.show()
Is there any way to achieve what I want? Or should I maybe move to another language? Thanks!