PIL Image mode "P" -> "RGBA" - python

This is my issue:
import Image
im = Image.open("1.png")
im.show()
print im.mode
im.convert("RGBA").save("2.png")
Well, with my image you can see the difference.
My question is: how do I convert it properly?
Image:
Result:
NOTE: The original image has a semi-transparent glow, the result has a solid green "glow"

This issue was reported here:
https://bitbucket.org/effbot/pil-2009-raclette/issue/8/corrupting-images-in-palette-mode
In March 2012, a comment says it's now fixed in development version of PIL. The most recent released version is 1.1.7, so the fix won't be available until 1.2 comes out. PIL updates very slowly, so don't expect this to come out soon.

Unfortunately your PNG image is a type that PIL doesn't handle very well - a paletted image with an alpha channel. When you open the image, the alpha is thrown away and there's no way to get it back.
This is different from the usual palette transparency where one index of the palette is used to denote fully transparent pixels.

You could use scipy.misc.imread:
img = scipy.misc.imread(filename, mode='RGBA')
img = Image.fromarray(img)

Your problem is that you do not provide info about what PIL should use as source of ALPHA channel.
PIL will not on its own add transparency to your image.
What part of your image you want to be transparent?

Related

How do I fix my image not being pasted correctly?

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.

Add an alpha channel and color profile to image

I am trying to get an image with an alpha channel and a color profile of sRGB IEC61966-2.1.
The image I am starting with does not have an alpha channel but it does have the color profile I want. see starting image
If I run the following,
from PIL import Image
img = Image.open('84.png')
print(img.mode)
img.convert('RGBA').save('84a.png')
I get an alpha channel, but the color profile seems to be gone. see ending image. Note that img.mode is 'P'. I saw this solution, but I would like to do it without cv2 if possible. Also I think that solution is starting with an image that already has an alpha channel. Maybe it applies and I am missing something.
Thank you
This solution helped to figure it out. All I did was find my desired *.icc file at /System/Library/ColorSync/Profiles/. I copied it to my run directory and called it sRGB.icc. Then I ran
from PIL import Image, ImageCms
img = Image.open('84.png').convert('RGBA')
img = ImageCms.profileToProfile(img, 'sRGB.icc', 'sRGB.icc', renderingIntent=0, outputMode='RGBA')
img.save('84a.png')
This gave me the alpha channel and color profile I wanted. However, it is a little 'hacky' since profileToProfile() should convert from one profile to another. Python returns None when I run Image.open('84.png').info.get('icc_profile') so there seems to be no initial color profile recognized.

Error when overlaying two images in OpenCV and or PIL

I've tried overlaying two images in openCV both in openCV and in PIL, but to no avail. I'm using a 1000x1000x3 array of np.zeros for the background (aka, a black background) and this random image of my monitor, but I really can't get it to work for some reason unbeknownst to me.
Trying with OpenCV only: (result(if you pay attention, you can see a couple of weird lines and dots in the middle))
base_temp = np.zeros((1000,1000,3))
foreground_temp = cv2.imread('exampleImageThatILinkedAbove.png')
base_temp[offset_y:offset_y+foreground_temp.shape[0], offset_x:offset_x+foreground_temp.shape[1]] = foreground_temp
Trying with PIL: (The result is literally the same as the OpenCV version)
base_temp = cv2.convertScaleAbs(self.base) #Convert to uint8 for cvtColor
base_temp = cv2.cvtColor(base_temp, cv2.COLOR_BGR2RGB) #PIL uses RGB and OpenCV uses BGR
base_temp = Image.fromarray(base_temp) #Convert to PIL Image
foreground_temp = cv2.cvtColor(cv2.convertScaleAbs(self.last_img), cv2.COLOR_BGR2RGB)
foreground_temp = Image.fromarray(foreground_temp)
base_temp.paste(foreground_temp, offset)
I'm using python3.5 and and OpenCV3.4 on Windows 10, if that's any help.
I'd like to avoid any solutions that require saving the cv2 images and then reloading them in another module to convert them but if it's unavoidable that's okay too. Any help would be appreciated!
If you check the type of base_temp, you will see it is float64 and that is going to cause you problems when you try to save it as a JPEG which expects unsigned 8-bit values.
So the solution is to create your base_temp image with the correct type:
base_temp = np.zeros((1000,1000,3), dtype=np.uint8)
The complete code and result look like this:
import cv2
import numpy as np
from PIL import Image
# Make black background - not square, so it shows up problems with swapped dimensions
base_temp=np.zeros((768,1024,3),dtype=np.uint8)
foreground_temp=cv2.imread('monitor.png')
# Paste with different x and y offsets so it is clear when indices are swapped
offset_y=80
offset_x=40
base_temp[offset_y:offset_y+foreground_temp.shape[0], offset_x:offset_x+foreground_temp.shape[1]] = foreground_temp
Image.fromarray(base_temp).save('result.png')

OpenCV imread transparency gone

I have an image (a captcha) that I download from the web.
When I loaded to opencv it seems to loose its properties or simply mixes the transparent background with the dark/black colors:
Currently the code does nothing but loading a writing again:
captchaImg = cv2.imread('captcha1.png')
cv2.imwrite("captcha2.png", captchaImg)
I have tried loading also with options 0, 1, 2, 3 but the result is the same.
Using the provided constants might help. I do the equivalent of
captchaImg = cv2.imread('captcha1.png', cv2.IMREAD_UNCHANGED)
which reads the alpha channel (if there is one). The REPL says that cv2.IMREAD_UNCHANGED is -1
Well this is a problem with opencv and it has a solution with opencv but it is kind of complex so I went on and use another libary (PIL) that I was going to use any way.
Basically what you do is put a white image behind the transparent one an with that you solve the problem.
The code is the following:
image = Image.open("captcha1.png")
image.convert("RGBA")
canvas = Image.new('RGBA', image.size, (255,255,255,255)) # Empty canvas colour (r,g,b,a)
canvas.paste(image, mask=image) # Paste the image onto the canvas, using it's alpha channel as mask
canvas.save("captcha1.png", format="PNG")
I hope it helps someone with the same problem.

PyGame image save colors distorted

So I have implemented the following screenshot functionality into my game just to log progress and stuff like that. This is my code:
pygame.image.save(screen, save_file)
Pretty basic. I recently upgraded to python 3.3 and have since been having the issue of distorted colors using this function. Here is what I mean:
Distorted Color:
So it looks quite nice, but it isn't how it supposed to be. This is the actual image:
Is this a known issue or is it just me? Are there any fixes to it or is it just a broken function at the moment. I am using pygame 1.9.2pre and I am assuming it is just a bug with the pre release but I was having issues using any other versions of pygame with python 3.3.
Some users have reported difficulty with saving images as pngs:
I only get .tga files even when I specify .png. Very frustrating.
If you use .PNG (uppercase), it will result in an invalid file (at least on my win32). Use .png (lowercase) instead.
PNG does not seem to work, I am able to get a preview of it in Thunar, but everywhere else It says that it is not a valid PNG.
Saving in a different format may be helpful. For example, BMP is a simple format, so it's unlikely that Pygame's implementation will be buggy.
If you really want to save as PNG, you can reverse the distortion by swapping the red channel with the green one. This is fairly easy. For example, using PIL:
from PIL import Image
im = Image.open("screenshot.png")
width, height = im.size
pix = im.load()
for i in range(width):
for j in range(height):
r,g,b = pix[i,j]
pix[i,j] = (g,r,b)
im.save("output.png")
Or you can save as BMP and convert to PNG after the fact:
from PIL import Image
im = Image.open("screenshot.bmp")
im.save("screenshot.png")
for future reference, this trick worked for me:
from PIL import Image
imgdata = pygame.surfarray.array3d(screen).transpose([1,0,2])[:,:,::-1]
Image.fromarray(imgdata).save('output.png')

Categories