Python: Apply sRGB colour profile and alpha channel to image - python

I have been having trouble trying to save a png image with sRGB and an alpha channel. I first crop an image and then save it like this:
from PIL import Image
import cv2
inputPath = 'picture.png'
img = cv2.imread(inputPath)
crop_img = img[bounds[3]:bounds[2], bounds[1]:bounds[0]]
pth = name + ".png"
crop_img.save(pth)
This however creates a file like this:
I want the file to be like this though:
How can I get this result in python?
P.S. The original image does have an alpha channel and sRGB colour profile.
Any help is greatly appreciated!

You can read your image as follows. It will load your image as such including the alpha channel.
img = cv2.imread(inputPath,-1)
UPDATE
Following code is equivalent to the above given answer since cv2.IMREAD_UNCHANGED=-1 in documentation. Though above snippet solve the issue, it is not a good programming practice to use it since it doesn't give the idea about what is really -1 does. But following code snippet gives an explicit idea about the behavior of the code.
img = cv2.imread(input,cv2.IMREAD_UNCHANGED)

Related

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.

Can someone explain me different type of modes of image?

enter image description here
I am new to the this image processing stuff. Why I am asking this question is because I have a code which works for RGB mode but doesnt for P mode ?
So I came to conclusion that it is something related to modes. I did some basic research on modes.but did not find any simple explanation. Will be helpful if someone can help me understand this.
CODE:
image=Image.open('image.png')
image.load()
image_data = np.asarray(image)
image_data_bw = image_data.max(axis=2)
non_empty_columns = np.where(image_data_bw.max(axis=0)>0)[0]
non_empty_rows = np.where(image_data_bw.max(axis=1)>0)[0]
cropBox = (min(non_empty_rows), max(non_empty_rows), min(non_empty_columns), max(non_empty_columns))
image_data_new = image_data[cropBox[0]:cropBox[1]+1, cropBox[2]:cropBox[3]+1 , :]
new_image = Image.fromarray(image_data_new)
new_image.save('cropped_image.png')
Codesource
Input to the code following Image:
Output should be like the following image(It is cropped to the edges of the picture. Please click on the image for understanding):
This Image is in RGBA mode.so the code is working fine for such images. But not with the image in P mode.
ERROR:
Error I get with P mode:
axis 2 is out of bounds for array of dimension 2
The answer you found greatly overcomplicates the process, by using numpy. The PIL library supports this usecase natively, with the image.getbbox() and image.crop() methods:
cropbox = image.getbbox()
new_image = image.crop(cropbox)
This works for all the different modes, regardless. The cropbox produced by image.getbbox() is exactly the same size as the one produced by the numpy route.
from PIL import Image
img = Image.open('Image.png')
print(x,y)
img.show()
cropbox_1 = img.getbbox()
new_image_1 = img.crop(cropbox_1)
new_image_1.save('Cropped_image,png')
new_image_1.show()
This code completely crops the image to the edges. Only if the images are having alpha channel, you might have to remove that channel by converting it.
ex. If it is a RGBA mode make it RGB and then use getbbox().
img = image.convert('RGB')
cropbox = img.getbbox()
image_1 = img.crop(cropbox)
addition of this should do the task.

How do I convert an RGB picture into graysacle using simplecv?

So working with windows, python 2.7 and simplecv I am making a live video with my webcam and want simplecv to give me a grayscale version of the video. Is there any simple way to achieve that?
I found the command
grayscale()
on the opencv page, which should do exactly that but when I run it I get the error:
NameError: name "grayscale" is not defined
I am currently using this prewritten code for object tracking but I don't know whether I should use the command I found, and where in the code I should put it, does anybody have an idea? :
print __doc__
import SimpleCV
display = SimpleCV.Display()
cam = SimpleCV.Camera()
normaldisplay = True
while display.isNotDone():
if display.mouseRight:
normaldisplay = not(normaldisplay)
print "Display Mode:", "Normal" if normaldisplay else "Segmented"
img = cam.getImage().flipHorizontal()
dist = img.colorDistance(SimpleCV.Color.BLACK).dilate(2)
segmented = dist.stretch(200,255)
blobs = segmented.findBlobs()
if blobs:
circles = blobs.filter([b.isCircle(0.2) for b in blobs])
if circles:
img.drawCircle((circles[-1].x, circles[-1].y), circles[-1].radius(),SimpleCV.Color.BLUE,3)
if normaldisplay:
img.show()
else:
segmented.show()
There are multiple ways to do this in SimpleCV.
One way has been already described, it's the toGray() method.
There's also a way you can do this with gaussian blur, which also helps to remove image noise:
from SimpleCV import *
img = Image("simplecv")
img.applyGaussianFilter(grayscale=True)
After the third line, img object contains the image with a lot less high-frequency noise, and converted to grayscale.
You may check out pyimagesearch.com who works with OpenCV, but he explains why applying Gaussian Blur is a good idea.
In simple cv theres a function called toGray() for example:
import SimpleCV as sv
img = img.jpg
sv.img.jpg.toGray()
return gimg.jpg

Using python to save a JPG image that was edited in the script

Referring to the answer to this question, I tried to save my own JPG image files, after some basic image processing. I've only applied a rotation and a shear. This is my code:
import numpy as np
import sys
from skimage import data, io, filter, color, exposure
import skimage.transform as tf
from skimage.transform import rotate, setup, AffineTransform
from PIL import Image
mypath = PATH_TO_FILENAME
readfile = FILENAME
img = color.rgb2gray(io.imread(mypath + readfile))
myimg = rotate(img, angle=10, order=2)
afine_tf = tf.AffineTransform(shear=0.1)
editedimg = tf.warp(myimg, afine_tf)
# IF I UNCOMMENT THE TWO LINES BELOW, I CAN SEE THE EDITED IMAGE AS EXPECTED
#io.imshow(editedimg)
#io.show()
saveimg= np.array(editedimg)
result = Image.fromarray((saveimg).astype(np.uint8))
newfile = "edited_" + readfile
result.save(path+newfile)
I know that the image processing was fine because if I display it before saving, it's just the original image with a bit of rotation and shearing, as expected. But I'm doing something wrong while saving it. I tried without the astype(np.uint8)) part but got an error. Then I removed some of the code from the link mentioned above because I guessed it was particularly for Fourier Transforms, since when I included some of their code, then I got an image that was all gray but with white lines in the direction of the shear I'd applied. But now the image that gets saved is just 2KB of nothing but blackness.
And when I tried something as simple as:
result = Image.fromarray(editedimg)
result.save(path+newfile)
then I got this error:
raise IOError("cannot write mode %s as JPEG" % im.mode)
IOError: cannot write mode F as JPEG
I don't really need to use PIL, if there's another way to simply save my image, I'm fine with that.
Look into the PIL fork, Pillow, is is not as outdated and what you should probably be using for this.
Also depending on your operating system you may need a few other libraries to compile PIL with JPEG support properly, see here
This may also help Says you need to convert your image to RGB mode before saving.
Image.open('old.jpeg').convert('RGB').save('new.jpeg')

PIL to OpenCV MAT causes color shift

When loading a png image with PIL and OpenCV, there is a color shift. Black and white remain the same, but brown gets changed to blue.
I can't post the image because this site does not allow newbies to post images.
The code is written as below rather than use cv.LoadImageM, because in the real case the raw image is received over tcp.
Here is the code:
#! /usr/bin/env python
import sys
import cv
import cv2
import numpy as np
import Image
from cStringIO import StringIO
if __name__ == "__main__":
# load raw image from file
f = open('frame_in.png', "rb")
rawImage = f.read()
f.close()
#convert to mat
pilImage = Image.open(StringIO(rawImage));
npImage = np.array(pilImage)
cvImage = cv.fromarray(npImage)
#show it
cv.NamedWindow('display')
cv.MoveWindow('display', 10, 10)
cv.ShowImage('display', cvImage)
cv. WaitKey(0)
cv.SaveImage('frame_out.png', cvImage)
How can the color shift be fixed?
OpenCV's images have color channels arranged in the order BGR whereas PIL's is RGB. You will need to switch the channels like so:
import PIL.Image
import cv2
...
image = np.array(pilImage) # Convert PIL Image to numpy/OpenCV image representation
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # You can use cv2.COLOR_RGBA2BGRA if you are sure you have an alpha channel. You will only have alpha channel if your image format supports transparency.
...
#Krish: Thanks for pointing out the bug. I didn't have time to test the code the last time.
Hope this helps.
Change
pilImage = Image.open(StringIO(rawImage))
to
pilImage = Image.open(StringIO(rawImage)).convert("RGB")
Light alchemist's answer did not work, but it did explain the issue. Wouldn't the reverse be screwed up by the Apha channel, i.e. it changes BRGA to AGRB. I would think Froyo's answer would solve it, but it did not change the displayed image at all. What did work was reversing the colors in OpenCV. I'm too much of a newbie to know why. They seem equivalent to me. Reversing the colors in numpy would be preferred as additional processing is planned in numpy. But thanks for the help, the answers steered me in the right direction.
pilImage = Image.open(StringIO(rawImage));
bgrImage = np.array(pilImage)
cvBgrImage = cv.fromarray(bgrImage)
# Reverse BGR
cvRgbImage = cv.CreateImage(cv.GetSize(cvBgrImage),8,3)
cv.CvtColor(cvBgrImage, cvRgbImage, cv.CV_BGR2RGB)
#show it
cv.ShowImage('display', cvRgbImage)
cv. WaitKey(30) # ms to allow display

Categories