Python Image Library - Create and paste image - python

How do I create a new image with a black background and paste another image on top of it?
What I am looking to do is turn some 128x128 transparent icons into 75x75 black background icons.
Doesnt work ...
import Image
theFile = "/home/xxxxxx/Pictures/xxxxxx_128.png"
img = Image.open(theFile)
newImage = Image.new(img.mode, img.size, "black")
newImage.paste(img)
newImage.resize((75,75))
newImage.save("out.png")
print "Done"
Thanks!

The resize method returns a new image object, rather than changing the existing one. Also, you should resize the image before pasting it. The following works for me:
import Image
theFile = "foo.png"
img = Image.open(theFile)
resized = img.resize((75,75))
r, g, b, alpha = resized.split()
newImage = Image.new(resized.mode, resized.size, "black")
newImage.paste(resized, mask=alpha)
newImage.save("out.png")
print "Done"
I found an example of this split + mask technique from this blog post.
Example input:
Output:

Related

how to put transparent image to another image using PIL without .paste() class

I'm newbie in PIL so for me it's hard to understand how I can do it, somebody helps me with it. In code, I only take two pictures and resized a transparent one. Now I don't know what to do next to paste it without .paste() class
def get_web_image (url):
img_data = requests.get(url).content
with open('picture1(bg)_1200x800.png', 'wb') as handler:
handler.write(img_data)
return img_data
def paste_image (source, destination, x, y, omit_color="None"):
im = Image.open(source)
pixels_newpaste = []
newsize = (200, 200)
im = im.resize(newsize)
im.save('picture2(done).png')
im.show()
paste_image ('picture2(transparent)_840x841.png', main_image, 1, 1)
main_pic()
#my_img_object = get_web_image ('https://avante.biz/wp-content/uploads/Baseball-Wallpapers/Baseball-Wallpapers-015.jpg')
I tried to make it using .getpixel(), but as I understand it requires only to draw in one color. So please help me to make this function
Here is a simplified version using these two images which are suitably resized and also partially transparent:
#!/usr/bin/env python3
from PIL import Image
# Open pitcher and pitch images
bg = Image.open('pitch.jpg')
fg = Image.open('pitcher.png').convert('RGBA')
w, h = fg.width, fg.height
# Iterate over rows and columns
for y in range(h):
for x in range(w):
# Get components of foreground pixel
r, g, b, a = fg.getpixel((x,y))
# If foreground is opaque, overwrite background with foreground
if a>128:
bg.putpixel((x,y), (r,g,b))
# Save result
bg.save('result.png')

How to add image on gif using Pillow?

Actually I am doing some experiments with python but I came to the point where I want to add an image on a transparent GIF with dimensions of the image.
I am getting an error of bad transparency mask.
Code -
from PIL import Image, ImageSequence
background = Image.open(...)
animated_gif = Image.open(...)
frames = []
for frame in ImageSequence.Iterator(animated_gif):
frame = frame.copy()
frame.paste(background, mask=bg)
frames.append(frame)
frames[0].save('output.gif', save_all=True, append_images=frames[1:])
Here is the answer of my question...
from PIL import Image, ImageSequence
background = Image.open("img.jpg")
animated_gif = Image.open("GIFF.gif")
frames = []
for frame in ImageSequence.Iterator(animated_gif):
output = background.copy()
frame_px = frame.load()
output_px = output.load()
transparent_foreground = frame.convert('RGBA')
transparent_foreground_px = transparent_foreground.load()
for x in range(frame.width):
for y in range(frame.height):
if frame_px[x, y] in (frame.info["background"], frame.info["transparency"]):
continue
output_px[x, y] = transparent_foreground_px[x, y]
frames.append(output)
frames[0].save('output.gif', save_all=True, append_images=frames[1:-1])
import Image
background = Image.open("test1.png")
foreground = Image.open("test2.png")
background.paste(foreground, (0, 0), foreground)
background.show()
I will explain the parameters for .paste() function.
first - the image to paste
second - coordinates
third - This indicates a mask that will be used to paste the image. If you pass a image with transparency, then the alpha channel is used as mask.
If this is not what you want to do, please add a comment for your need.

Put image on another image using python

Hello i'm using python to track objects in a video and i want to show an image on top of the object instead of a text.
The current line that im using to show text on top of the target box :
cv2.putText(img_current_frame ,"object name",(int(bbox[0]), int(bbox[1]-45)),0, 0.75, (0,0,0),2)
There's already an answer for this: overlay a smaller image on a larger image python OpenCv
In your case, you could wrap this functionality with the following:
def overlay_image(im1, im2, x_offset, y_offset):
'''Mutates im1, placing im2 over it at a given offset.'''
im1[y_offset:y_offset+im2.shape[0], x_offset:x_offset+im2.shape[1]] = im2
then call it:
im_over = cv2.imread("my_overlay_image.png")
overlay_image(img_current_frame, im_over, 10, 10)
(as per the referenced solution)
You might prefer to composite text with the PIL .text() method:
from PIL import Image, ImageDraw
img = Image.open("blank.png").convert("RGBA")
d = ImageDraw.Draw(img)
d.text((10, 10), "Hello world!")
img.show()
Or if you have pixels, then use alpha_composite().
If you stick with cv2,
then addWeighted() will help you blend in a logo image with alpha set to taste.
Or you can just use the matrix addition operator:
output = img_current_frame + logo

Python add noise to image breaks PNG

I'm trying to create a image system in Python 3 to be used in a web app. The idea is to load an image from disk and add some random noise to it. When I try this, I get what looks like a totally random image, not resembling the original:
import cv2
import numpy as np
from skimage.util import random_noise
from random import randint
from pathlib import Path
from PIL import Image
import io
image_files = [
{
'name': 'test1',
'file': 'test1.png'
},
{
'name': 'test2',
'file': 'test2.png'
}
]
def gen_image():
rand_image = randint(0, len(image_files)-1)
image_file = image_files[rand_image]['file']
image_name = image_files[rand_image]['name']
image_path = str(Path().absolute())+'/img/'+image_file
img = cv2.imread(image_path)
noise_img = random_noise(img, mode='s&p', amount=0.1)
img = Image.fromarray(noise_img, 'RGB')
fp = io.BytesIO()
img.save(fp, format="PNG")
content = fp.getvalue()
return content
gen_image()
I have also tried using pypng:
import png
# Added the following to gen_image()
content = png.from_array(noise_img, mode='L;1')
content.save('image.png')
How can I load a png (With alpha transparency) from disk, add some noise to it, and return it so that it can be displayed by web server code (flask, aiohttp, etc).
As indicated in the answer by makayla, this makes it better: noise_img = (noise_img*255).astype(np.uint8) but the colors are still wrong and there's no transparency.
Here's the updated function for that:
def gen_image():
rand_image = randint(0, len(image_files)-1)
image_file = image_files[rand_image]['file']
image_name = image_files[rand_image]['name']
image_path = str(Path().absolute())+'/img/'+image_file
img = cv2.imread(image_path)
cv2.imshow('dst_rt', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# Problem exists somewhere below this line.
img = random_noise(img, mode='s&p', amount=0.1)
img = (img*255).astype(np.uint8)
img = Image.fromarray(img, 'RGB')
fp = io.BytesIO()
img.save(fp, format="png")
content = fp.getvalue()
return content
This will popup a pre-noise image and return the noised image. RGB (And alpha) problem exists in returned image.
I think the problem is it needs to be RGBA but when I change to that, I get ValueError: buffer is not large enough
Given all the new information I am updating my answer with a few more tips for debugging the issue.
I found a site here which creates sample transparent images. I created a 64x64 cyan (R=0, G=255, B=255) image with a transparency layer of 0.5. I used this to test your code.
I read in the image two ways to compare: im1 = cv2.imread(fileName) and im2 = cv2.imread(fileName,cv2.IMREAD_UNCHANGED). np.shape(im1) returned (64,64,3) and np.shape(im2) returned (64,64,4). This is why that flag is required--the default imread settings in opencv will read in a transparent image as a normal RGB image.
However opencv reads in as BGR instead of RGB, and since you cannot save out with opencv, you'll need to convert it to the correct order otherwise the image will have reversed color. For example, my cyan image, when viewed with the reversed color appears like this:
You can change this using openCV's color conversion function like this im = cv2.cvtColor(im, cv2.COLOR_BGRA2RGBA) (Here is a list of all the color conversion codes). Again, double check the size of your image if you need to, it should still have four channels since you converted it to RGBA.
You can now add your noise to your image. Just so you know, this is also going to add noise to your alpha channel as well, randomly making some pixels more transparent and others less transparent. The random_noise function from skimage converts your image to float and returns it as float. This means the image values, normally integers ranging from 0 to 255, are converted to decimal values from 0 to 1. Your line img = Image.fromarray(noise_img, 'RGB') does not know what to do with the floating point noise_img. That's why the image is all messed up when you save it, as well as when I tried to show it.
So I took my cyan image, added noise, and then converted the floats back to 8 bits.
noise_img = random_noise(im, mode='s&p', amount=0.1)
noise_img = (noise_img*255).astype(np.uint8)
img = Image.fromarray(noise_img, 'RGBA')
It now looks like this (screenshot) using img.show():
I used the PIL library to save out my image instead of openCV so it's as close to your code as possible.
fp = 'saved_im.png'
img.save(fp, format="png")
I loaded the image into powerpoint to double-check that it preserved the transparency when I saved it using this method. Here is a screenshot of the saved image overlaid on a red circle in powerpoint:

Resizing JPG using PIL.resize gives a completely black image

I'm using PIL to resize a JPG. I'm expecting the same image, resized as output, but instead I get a correctly sized black box. The new image file is completely devoid of any information, just an empty file. Here is an excerpt for my script:
basewidth = 300
img = Image.open(path_to_image)
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize))
img.save(dir + "/the_image.jpg")
I've tried resizing with Image.LANCZOS as the second argument, (defaults to Image.NEAREST with 1 argument), but it didn't make a difference. I'm running Python3 on Ubunutu 16.04. Any ideas on why the image file is empty?
I also encountered the same issue when trying to resize an image with transparent background. The "resize" works after I add a white background to the image.
Code to add a white background then resize the image:
from PIL import Image
im = Image.open("path/to/img")
if im.mode == 'RGBA':
alpha = im.split()[3]
bgmask = alpha.point(lambda x: 255-x)
im = im.convert('RGB')
im.paste((255,255,255), None, bgmask)
im = im.resize((new_width, new_height), Image.ANTIALIAS)
ref:
Other's code for making thumbnail
Python: Image resizing: keep proportion - add white background
The simplest way to get to the bottom of this is to post your image! Failing that, we can check the various aspects of your image.
So, import Numpy and PIL, open your image and convert it to a Numpy ndarray, you can then inspect its characteristics:
import numpy as np
from PIL import Image
# Open image
img = Image.open('unhappy.jpg')
# Convert to Numpy Array
n = np.array(img)
Now you can print and inspect the following things:
n.shape # we are expecting something like (1580, 1725, 3)
n.dtype # we expect dtype('uint8')
n.max() # if there's white in the image, we expect 255
n.min() # if there's black in the image, we expect 0
n.mean() # we expect some value between 50-200 for most images

Categories