PIL image in grayscale to OpenCV format - python

I found the previous answer related to a more general conversion from RGB image here: Convert image from PIL to openCV format
I would like to know the difference when an image has to be read as a grayscale format.
images = [None, None]
images[0] = Image.open('image1')
images[1] = Image.open('image2')
print(type(images[0]))
a = np.array(images[0])
b = np.array(images[1])
print(type(a))
im_template = cv2.imread(a, 0)
im_source = cv2.imread(b, 0)
I get the following output:
<class 'PIL.JpegImagePlugin.JpegImageFile'>
<class 'numpy.ndarray'>
Even though I am able to convert the image to ndarray, cv2 says: "bad argument type for built-in operation". I do not need an RGB to BGR conversion. What else should I consider while passing a cv2 read argument?

You are making life unnecessarily difficult for yourself. If you want to load an image as greyscale, and use it with OpenCV, you should just do:
im = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
and that's all. No need to use PIL (which is slower), no need to use cvtColor() because you have already wasted all the memory reading it in BGR anyway.
If you absolutely want to read it using PIL (for some odd reason), use:
import numpy as np
from PIL import Image
# Read in and make greyscale
PILim = Image.open('image.jpg').convert('L')
# Make Numpy/OpenCV-compatible version
openCVim = np.array(PILim)
By the way, if you want to go back to a PIL image from an OpenCV/Numpy image, use:
PILim = Image.fromarray(openCVim)

Since you already have loaded the image, you should use an image conversion function:
im_template = cv2.cvtColor(a, cv2.COLOR_RGB2GRAY)
im_source = cv2.cvtColor(b, cv2.COLOR_RGB2GRAY)

Related

Problems Converting Images from 8-bit to 10-bit

I am trying to convert 8 bit images to 10 bit. I thought it would be as easy as changing the bin values. I've tried to pillow and cv-python:
from PIL import Image
from numpy import asarray
import cv2
path = 'path/to/image'
img = Image.open(path)
data = asarray(img)
newdata = (data/255)*1023 #2^10 is 1024
img2 = Image.fromarray(newdata) #this fails
cv2.imwrite('path/newimage.png, newdata)
While cv2.imwrite successfully writes the new file, it is still encoded as an 8bit image even though bin goes up to 1023.
$ file newimage.png
newimage.png: PNG Image data, 640 x 480, 8-bit/color RGB, non-interlaced
Is there another way in either python or linux that can convert 8-bit to 10-bit?
Lots of things going wrong here.
You are mixing OpenCV (cv2.imwrite) with PIL (Image.open) for no good reason. Don't do that, you will confuse yourself as they use different RGB/BGR orderings and conventions,
You are trying to store 10-bit numbers in 8-bit vectors,
You are trying to hold 3 16-bit RGB pixels in a PIL Image which will not work as RGB images must be 8-bit in PIL.
I would suggest:
import cv2
import numpy as np
# Load image
im = cv2.imread(IMAGE, cv2.IMREAD_COLOR)
res = im.astype(np.uint16) * 4
cv2.imwrite('result.png', res)
I found a solution using pgmagick wrapper for python
import pgmagick as pgm
imagePath = 'path/to/image.png'
saveDir = '/path/to/save'
img = pgm.Image(imagePath)
img.depth(10) #sets to 10 bit
save_path = os.path.join(saveDir,'.'.join([filename,'dpx']))
img.write(save_path)

convert ndarray object to Image

I have a gray scale image of type uint16, size = (256,256) ndarray object
I want to use PIL to resize it to (75,75) but it requires the input to be of Image type.
How can I convert image of ndarray object into Image type to use image.resize((75,75), Image.ANTIALIAS)
NOTE:
I know I can read image using Image.open if it is saved, but my image is obtained after some image processing steps and is not read from disk
UPDATE:
I am trying to provide image that I have :
import scipy.misc
scipy.misc.imsave('image.png', box_img)
# read this similar format image of type ndarray
image = scipy.ndimage.imread('image.png')
# convert it to Image type
The image attached when read of similar type as I need.
I need to convert this image into Image type
Thanks,
Gopi
from PIL import Image
import numpy as np
# An array of ones for example
img_array = np.ones((256,256), dtype='uint16')
img = Image.fromarray(img_array)
img = img.resize((75,75))

How to open a CR2 file in python OpenCV

I've managed to come very far on a program I'm writing. I don't know how to load CR2 files into an OpenCV Image. I've tried the following:
raw = rawpy.imread(sys.argv[1])
rgb = raw.postprocess()
PILrgb = scipy.misc.toimage(rgb)
image = cv2.imdecode(PILrgb, 1)
It was an attempt at converting the numpyarray returned by Postprocess the currently loaded RAW image and return the new resulting image as numpy array. Then calling spicy.misc.toimage to Takes a numpy array and returns a PIL image..
I get the following msg though TypeError: buf is not a numpy array, neither a scalar
It may be easier if you only rawpy
import rawpy
import cv2
raw = rawpy.imread(sys.argv[1]) # access to the RAW image
rgb = raw.postprocess() # a numpy RGB array
image = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR) # the OpenCV image

Convert opencv image format to PIL image format?

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.

Python: How to write a single channel png file from numpy array?

I want to write a single channel png image from a numpy array in python?
In Matlab that would be
A = randi(100,100,255)
imwrite(uint8(A),'myFilename.png','png');
I saw exampels using from PIL import Image and Image.fromarray() but they are for jpeg and 3-channel pngs only it appears...
I already found the solution using opencv, I will post it here. Hopefully it will shorten someone else's searching...
Here is a solution using opencv / cv2
import cv2
myImg = np.random.randint(255, size=(200, 400)) # create a random image
cv2.imwrite('myImage.png',myImg)
PIL's Image.fromarray() automatically determines the mode to use from the datatype of the passed numpy array, for example for an 8-bit greyscale image you can use:
from PIL import Image
import numpy as np
data = np.random.randint(256, size=(100, 100), dtype=np.uint8)
img = Image.fromarray(data) # uses mode='L'
This however only works if your array uses a compatible datatype, if you simply use data = np.random.randint(256, size=(100, 100)) that can result in a int64 array (typestr <i8), which PIL can't handle.
You can also specify a different mode, e.g. to interpret a 32bit array as an RGB image:
data = np.random.randint(2**32, size=(100, 100), dtype=np.uint32)
img = Image.fromarray(data, mode='RGB')
Internally Image.fromarray() simply tries to guess the correct mode and size and then invokes Image.frombuffer().
The image can then be saved as any format PIL can handle e.g: img.save('filename.png')
You might want not to utilise OpenCV for simple image manipulation. As suggested, use PIL:
im = Image.fromarray(arr)
im.save("output.png", "PNG")
Have you tried this? What has failed here that led you to concluding that this is JPEG-only?

Categories

Resources