I have this image and I read as a PIL file. Then, I save it back using save method in PIL and imwrite method in cv2. Saving the image with imwrite downgrades the image quality (it becomes black and white and text can't be read).
image = Image.open("image.png")
cv2_image = numpy.asarray(image)
image.save("pil.png")
cv2.imwrite("opencv.png", cv2_image)
Here are the output files:
pil.png
opencv.png
The input image is a palette image - see here. So, you need to convert it to RGB otherwise you just pass OpenCV the palette indices but without the palette.
So, you need:
image = Image.open(...).convert('RGB')
Now make it into a Numpy array:
cv2image = np.array(image)
But that will be in RGB order, so you need to reverse the channel order:
cv2image = cv2image[..., ::-1]
Related
I want to change the img_path to the frames generated from opencv:
img = image.load_img(img_path, target_size=(224, 224))
How can I rewrite it?
I am assuming that the image.load_img() function that you are using is the one from keras_utils package.
As it is noted in the documentation, load_img() accepts path to the image as the first parameter and returns:
Returns:
A PIL Image instance.
It is not mentioned in the question, but if you read the frames from the camera using opencv they should already be numpy arrays which you could to pass to your model. Of course you should resize them to (224,224) before (how to resize the image using opencv).
However, if you want to have the PIL images (to have the same type as the one returned by load_img()), you need to convert your opencv frames (numpy array) to PIL image. Follow this question and answer by #ZdaR to do this conversion:
import cv2
import numpy as np
from PIL import Image
img = cv2.imread("path/to/img.png")
# You may need to convert the color.
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
im_pil = Image.fromarray(img)
# For reversing the operation:
im_np = np.asarray(im_pil)
I have images like this, which I believe have 4 data channels (RGB + an alpha channel).
When I try to open this image like so, I can't access the transparency layer.
from PIL import Image
fn = 'FUgqUA5.png'
im = Image.open(fn)
im.mode # returns RGB instead of desired .png
im.getData()[0] # returns (0,0,0) instead of desired (0,0,0,255)
How do I open this image as an actual .png? Is it possible the image is saved as a 3-channel png instead and that this image simply doesn't have a 4th channel?
I saved the image and saw the properties via image editor and it did not mention that there is a 4th channel.
PS: (image editor is ImageMagick)
I want to convert an image loaded
TestPicture = cv2.imread("flowers.jpg")
I would like to run a PIL filter like on the example with the variable
TestPicture
but I'm unable to convert it back and forth between these types.
Is there a way to do these conversions?
Can OpenCV do all of the image filters that are in the PIL package?
Example:
Result:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
threshold_img = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
im_pil = cv2_to_pil(threshold_img)
pytesseract.image_to_string(im_pil)
Out[5]: 'TUM'
Yes OpenCV is more robust and flexible and can perform most of the image processing routines which are available out there, So probably this filter can be done with OpenCV> However, there may not be a straightforward API for that.
Anyways, as far as the conversion of image format from OpenCV to PIL is concerned you may use Image.fromarray as:
import cv2
import numpy as np
from PIL import Image
img = cv2.imread("path/to/img.png")
# You may need to convert the color.
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
im_pil = Image.fromarray(img)
# For reversing the operation:
im_np = np.asarray(im_pil)
But you must keep in mind that, OpenCV follows BGR convention and PIL follows RGB color convention, so to keep the things consistent you may need to do use cv2.cvtColor() before conversion.
Pillow and OpenCV use different formats of images. So you can't just read an image in Pillow and manipulate it into an OpenCV image.
Pillow uses the RGB format as #ZdaR highlighted, and OpenCV uses the BGR format. So, you need a converter to convert from one format to another.
To convert from PIL image to OpenCV use:
import cv2
import numpy as np
from PIL import Image
pil_image=Image.open("demo2.jpg") # open image using PIL
# use numpy to convert the pil_image into a numpy array
numpy_image=numpy.array(pil_img)
# convert to a openCV2 image, notice the COLOR_RGB2BGR which means that
# the color is converted from RGB to BGR format
opencv_image=cv2.cvtColor(numpy_image, cv2.COLOR_RGB2BGR)
To convert from OpenCV image to PIL image use:
import cv2
import numpy as np
from PIL import Image
opencv_image=cv2.imread("demo2.jpg") # open image using openCV2
# convert from openCV2 to PIL. Notice the COLOR_BGR2RGB which means that
# the color is converted from BGR to RGB
color_converted = cv2.cvtColor(opencv_image, cv2.COLOR_BGR2RGB)
pil_image=Image.fromarray(color_converted)
Here are two functions to convert image between PIL and OpenCV:
def toImgOpenCV(imgPIL): # Conver imgPIL to imgOpenCV
i = np.array(imgPIL) # After mapping from PIL to numpy : [R,G,B,A]
# numpy Image Channel system: [B,G,R,A]
red = i[:,:,0].copy(); i[:,:,0] = i[:,:,2].copy(); i[:,:,2] = red;
return i;
def toImgPIL(imgOpenCV): return Image.fromarray(cv2.cvtColor(imgOpenCV, cv2.COLOR_BGR2RGB));
Convert from OpenCV img to PIL img will lost transparent channel. While convert PIL img to OpenCV img will able to keep transparent channel, although cv2.imshow not display it but save as png will gave result normally.
I am trying to convert the image that I read using cv2.imread which is store in numpy array to PIL Image object , the color of Image will be changed Here is the code
I=cv2.imread("Image.jpg")
PILImage=Image.fromarray(I,mode='RGB')
How can get back my original Image?
OpenCV likes to treat images as having BGR layers instead of RGB layers. Adding
I = cv2.cvtColor(I, cv2.COLOR_BGR2RGB)
will swap layers to what you expect.
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.