I've been trying to get thisimage to automatically crop to the smallest size possible, removing the transparent bits around it. I can't just crop this image myself manually, as more things will be added on the image like this .
I've been using this code:
from PIL import Image, ImageChops
image=Image.open('headbase1.png')
image.load()
imageSize = image.size
imageBox = image.getbbox()
print(image.getbbox())
cropped=image.crop(imageBox)
cropped.save('headbase_end.png')
It does not crop out the transparency around it, and the bounding box is this (0, 0, 45, 45), which I do not think is right.
Thanks, VOT.
Edit, this does work: Automatically cropping an image with python/PIL with that image, however it refuses to work for my image. .
getbbox doesn't work on PNGs with alpha channels: image.mode == 'RGBA'
First remove the alpha channel and then obtain the bounding box. image.convert('RGB').getbbox()
Related
I am trying to crop a image into a circulor form (which works) and then pasting it to a white backround.
from PIL import Image,ImageFont,ImageDraw, ImageOps, ImageFilter
from io import BytesIO
import numpy as np
pfp = Image.open(avatar)
# cropping to circle
img=pfp.convert("RGB")
npImage=np.array(img)
h,w=img.size
alpha = Image.new('L', img.size,0)
draw = ImageDraw.Draw(alpha)
draw.pieslice([0,0,h,w],0,360,fill=255)
npAlpha=np.array(alpha)
npImage=np.dstack((npImage,npAlpha))
Image.fromarray(npImage).save('result.png')
background = Image.open('white2.png')
background.paste(Image.open('result.png'), (200, 200, h, w))
background.save('combined.png')
Heres what the cropped image looks like(It looks like it has a white background but that's it's transparent):
Cropped Image
But then when I paste it to the white background it changes to a square:
Pasted Image
Here is the original image I am working with:
Image
What you're doing is setting the Alpha of any pixel outside that circle to 0, so when you render it, it's gone, but that pixel data is still there. That's not a problem, but it important to know.
Problem
Your "white2.png" image does not have an alpha channel. Even if it's a PNG file, you have to add an alpha channel using your image editing tool. You can print("BGN:", background.getbands()), to see the channels it has. You'll see it says 'R','G','B', but no 'A'.
Solution 1
Replace your paste line with:
background.paste(pfp, (200, 200), alpha)
Here, we use the loaded in avatar as is, and the third argument is a mask which PIL figures out how to use to mask the image before pasting.
Solution 2
Give your white background image an alpha channel.
MS Paint doesn't do this. You have to use something else.
For GIMP, you simply right-click on the layer and click Add Alpha-channel.
Oh, and something worth noting.
Documentation for Paste.
See alpha_composite() if you want to combine images with respect to their alpha channels.
I have an A4 png image with some text in it, it's transparent, my question is, how can I crop the image to only have the text, I am aware of cropping in PIL, but if I set it to fixed values, it will not be able to crop another image that has that text in another place. So, how can I do it so it finds where the text, sticker, or any other thing is placed on that big and empty image, and crop it so the thing fits perfectly?
Thanks in advance!
You can do this by extracting the alpha channel and cropping to that. So, if this is your input image:
Here it is again, smaller and on a chessboard background so you can see its full extent:
The code looks like this:
#!/usr/bin/env python3
from PIL import Image
# Load image
im = Image.open('image.png')
# Extract alpha channel as new Image and get its bounding box
alpha = im.getchannel('A')
bbox = alpha.getbbox()
# Apply bounding box to original image
res = im.crop(bbox)
res.save('result.png')
Here is the result:
And again on a chessboard pattern so you can see its full extent:
Keywords: Image processing, Python, PIL/Pillow, trim to alpha, crop to alpha, trim to transparency, crop to transparency.
from PIL import Image
im = Image.open("image.png")
im.getbbox()
im2 = im.crop(im.getbbox())
im2.save("result.png")
How can I convert a non-transparent PNG file into a transparent GIF file with PIL?
I need it for my turtle-graphics game. I can only seem to transparentize a PNG file, not a GIF file.
It's not obvious, to me at least, how you are supposed to do that! This may be an unnecessary work-around for a problem that doesn't exist because I don't know something about how PIL works internally.
Anyway, I messed around with it long enough using this input image:
#!/usr/bin/env python3
from PIL import Image, ImageDraw, ImageOps
# Open PNG image and ensure no alpha channel
im = Image.open('start.png').convert('RGB')
# Draw alpha layer - black square with white circle
alpha = Image.new('L', (100,100), 0)
ImageDraw.Draw(alpha).ellipse((10,10,90,90), fill=255)
# Add our lovely new alpha layer to image
im.putalpha(alpha)
# Save result as PNG and GIF
im.save('result.png')
im.save('unhappy.gif')
When I get to here, the PNG works and the GIF is "unhappy".
PNG below:
"Unhappy" GIF below:
Here is how I fixed up the GIF:
# Extract the alpha channel
alpha = im.split()[3]
# Palettize original image leaving last colour free for transparency index
im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
# Put 255 everywhere in image where we want transparency
im.paste(255, ImageOps.invert(alpha))
im.save('result.gif', transparency=255)
Keywords: Python, image processing, PIL, Pillow, GIF, transparency, alpha, preserve, transparent index.
I've create a *.png image using PPT.
I want to use cv2-python to read and show it. But the cv2.imshow gave me a total black image with nothing on it. This is my code,I just don't know where was wrong:
img = cv2.imread(r"C:/Users/.../Test_shapes.png")
print img.max(),img.shape
cv2.imshow('color_image',img)
cv2.waitKey()
p.s. the img.shape returns the correct shapes (881, 1803, 3). But img.max() returns 0.
Sorry, I don't have enough reputation to add images here. But with Matlab, my *.png could be successfully read and the max is 108.
This normally happens, when you draw some black lines, on a presumably white canvas. Most applications export PNG with transparent background, even if the visible canvas was white.
The result is that the image consists only of black pixels and transparent pixels. Those that are transparent, usually also have an RGB value of 0.0.0 -- so if we look only at the RGB values, everything is black.
E.g. in inkscape, you can put a white rectangle below your drawing to make the PNG exporter really save some white background.
Both, default cv2.imread("file.png", cv2.IMREAD_COLOR) and cv2.imread("file.png", cv2.IMREAD_GRAYSCALE) ignore transparency, and only see the RGB values. This is bad, as the RGB value of a fully transparent pixel is meaningless.
Only cv2.imread("file.png", cv.IMREAD_UNCHANGED) can access the transparency channel. We extract the alpha, invert it, and add it back to the image. This simulates alpha on a white background:
img = cv2.imread("file.png", cv.IMREAD_UNCHANGED)
if img.shape[2] == 4: # we have an alpha channel
a1 = ~img[:,:,3] # extract and invert that alpha
img = cv2.add(cv2.merge([a1,a1,a1,a1]), img) # add up values (with clipping)
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB) # strip alpha channel
cv2.imshow('aa', img); cv2.waitKey(0); cv2.destroyAllWindows()
It seems cv2 is not friends with transparencies at all. Neither cv.add(), nor cv2.addWeighted() can apply an alpha channel easily.
Sorry, could not resist to dig out this unanswered zombie after 5 years. My solution works nicely, when there is only information in the alpha channel, and when information is in both, the rgb channels, and in the alpha channel.
I'm trying to use this this approach to add a semi-transparent polygon to an image. The problem is the image is a JPEG. I know that JPEGs don't have an alpha channel, so I was hoping there was a way I could have PIL take in a JPEG, convert it to a form which has an alpha channel, add the semi-transparent mask, then merge the mask with the image and convert it back into a JPEG for saving. Can PIL accomplish this? If not, how else might I go about doing this? Thanks!
That's easy. Just paste the jpeg into a new rgba Image():
#!/usr/bin/env python3
from PIL import Image
from PIL import ImageDraw
im = Image.open("existing.jpg")
logo = Image.open("python-32.png")
back = Image.new('RGBA', im.size)
back.paste(im)
poly = Image.new('RGBA', (512,512))
pdraw = ImageDraw.Draw(poly)
pdraw.polygon([(128,128),(384,384),(128,384),(384,128)],
fill=(255,255,255,127),outline=(255,255,255,255))
back.paste(poly, (0,0), mask=poly)
back.paste(logo, (im.size[0]-logo.size[0], im.size[1]-logo.size[1]), mask=logo)
back.show()
This additionally adds a png (with transparency) to the image.