How to check the channel order of an image? - python

Question
With an image loaded into Python as shown below, how do I know which order the channels are in? (e.g. BGR or RGB)
Code
from PIL import Image
import numpy as np
image_pil = Image.open("Stonehenge.jpg")
image_np = np.array(image_pil)
image_np[0][0]
Result
array([ 52, 123, 155], dtype=uint8)
Specific question
How do I know whether the 52 corresponds to the red channel, the blue channel, or a different channel? Or does this question not make sense on a conceptual level?
Notes
In a similar question for Java instead of Python, one person claims:
If you are reading in the image file, or you have access to the code
that reads in the file, know it is:
BGR order if you used cv2.imread(),
RGB order if you used mpimg.imread(), (assuming import matplotlib.image as mpimg)
If you don't know how the file was opened, the accepted answer
BufferedImage is great for Java.

Since you use PIL and you don't specify any other mode to load the Image with, you get R G B.
You could verify that by checking the "mode" attribute on the Image instance:
image_pil.mode # should return the string 'RGB'
Pillow supports the array interface, via image_pil.__array_interface__ magic method, so when when you create the ndarray numpy just uses that. i.e., it doesn't know anything about the colour channel order. If you have an image file stored as BGR, and you load it like this, you will get blue data in the red channel and vice-versa, and it would look wrong when you display it.

Related

How to use imageio imread to get a multi channel array (RGB) from a single channel image (grayscale)?

So I want to use imageio to read a black-and-white image as a 3d image.
If I had used opencv I would use the following command since opencv's default is IMREAD_COLOR:
im3d = cv2.imread(im_path)
This results in shape (186, 148, 3)
However, since it is a black-and-white image, imageio contrary to opencv defaults to reading two dimensions. Thus
im3d = imageio.imread(im_path)
results in shape (186, 148).
According to the imageio docs, I need to add "format", a string with "The format to use to read the file." to make imageio behave the way I want to. See this link:
https://imageio.readthedocs.io/en/stable/userapi.html#imageio.imread
But this is so badly explained! I am often amazed by how bad documentation is.
I have no way to know what to enter as "format" in order to get imageio to behave as I want.
So any help on this would be very appreciated!
Following the documentation link you provided, you can see a navigation item Docs for the formats quite prominent on the left side. For example, let's check the PNG format entry, since PNG supports single channel images. There's a section Parameters for reading: You need to provide a proper Pillow format string, for RGB images, it's 'RGB'. The parameter to be used is called pilmode. Let's check that:
import imageio
im = imageio.imread('path/to/some/singlechannelimage.png')
print(im.shape)
im3d = imageio.imread('path/to/some/singlechannelimage.png', pilmode='RGB')
print(im3d.shape)
If I run that for some single channel PNG, I get:
(639, 379)
(639, 379, 3)
That's what you want, I suppose.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.8.5
imageio: 2.9.0
----------------------------------------

RGB Values Being Returned by PIL don't match RGB color

I'm attempting to make a reasonably simple code that will be able to read the size of an image and return all the RGB values. I'm using PIL on Python 2.7, and my code goes like this:
import os, sys
from PIL import Image
img = Image.open('C:/image.png')
pixels = img.load()
print(pixels[0, 1])
now this code was actually gotten off of this site as a way to read a gif file. I'm trying to get the code to print out an RGB tuple (in this case (55, 55, 55)) but all it gives me is a small sequence of unrelated numbers, usually containing 34.
I have tried many other examples of code, whether from here or not, but it doesn't seem to work. Is it something wrong with the .png format? Do I need to further code in the rgb part? I'm happy for any help.
My guess is that your image file is using pre-multiplied alpha values. The 8 values you see are pretty close to 55*34/255 (where 34 is the alpha channel value).
PIL uses the mode "RGBa" (with a little a) to indicate when it's using premultiplied alpha. You may be able to tell PIL to covert the to normal "RGBA", where the pixels will have roughly the values you expect:
img = Image.open('C:/image.png').convert("RGBA")
Note that if your image isn't supposed to be partly transparent at all, you may have larger issues going on. We can't help you with that without knowing more about your image.

Viewing dicom image with Bokeh

I'm trying to set the graph background to a dicom image. I followed this example, but the image data given from dicom.pixel_array isn't RGBA. I'm not sure how to convert it, either. I'm also not sure what exactly bokeh is expecting. I've tried finding specifics in the documentation, but not such luck.
from bokeh.plotting import figure, show, output_file
import dicom
import numpy as np
path = "/pathToDicomImage.dcm"
data = dicom.read_file(path)
img = data.pixel_array
p = figure(x_range=(0,10), y_range=(0,10))
# must give a vector of images
p.image_rgba(image=[img], x=0, y=0, dw=10, dh=10)
output_file("image_rgba.html", title="image_rgba.py example")
show(p)
This code doesnt give me any errors, but it doesn't display anything. Maybe the pixel array doesn't have alpha data, so alpha defaults to 0? I'm not sure. Also, I can't quite figure out how to test it.
SOLVED
As was pointed out, I just needed to map the pixel data to rgba space. for this instance, it means duplicating the data to each channel, and setting alpha all the way.
def dicom_image_to_RGBA(image_data):
rows = len(image_data)
cols = rows
img = np.empty((rows,cols), dtype=np.uint32)
view = img.view(dtype=np.uint8).reshape((rows, cols, 4))
for i in range(0,rows):
for j in range(0,cols):
view[i][j][0] = image_data[i][j]
view[i][j][1] = image_data[i][j]
view[i][j][2] = image_data[i][j]
view[i][j][3] = 255
return img
Not being an expert in python, I have had a glance at pydicom's capabilities in handling pixel data. I figured out that pixel_array is the value of the pixel-data attribute of the DICOM dataset as is and pydicom does not offer any functionality to convert it into some standard format which can be handled uniformly. This means you will have to convert it to RGB in most cases which is a quite compilcated and error-prone task.
Things to consider in this:
The encoding (Big/Little Endian, various compression methods like JPEG, JPEG-LS, RLE, ZIP) - DICOM attribute (0002,0010) TransferSyntaxUID
The type of pixeldata (Grayscale, RGB, ...) - DICOM attribute (0028,0004) PhotometricInterpretation, (0028,0103) PixelRepresentation
In case of color images: are the values encoded colur by plane (RRRRR,.....GGGGG,.....BBBBB) or colour by pixel as you expect it to be (RGB RGB...)
The bit depth and which bits are used for actual pixel data values (0028,0100) BitsAllocated, (0028,0101) BitsStored, (0028,0102) Highbit.
are the pixel data values really the values to be displayed or are they indices to a colour/grayscale lookup table (0028,3000) ModalityLUTSequence, (0028,3002) LUTDescriptor, (0028,3003) LUTExplanation, (0028,3004) ModalityLUTType, (0028,3006) LUTData.
Scary, isn't it? For some modern image classes like Enhanced MR, there is even more than that.
However, if you constrain to a particular type of image (e.g. Computed Radiography). limitations to the above mentioned apply that make your life a bit easier.
If you would post a DICOM dump of the image header I could give you some hints how to display that particular image.
HTH
kritzel
What you need to do is map the pixel data returned from pixel_array to RGB space. Usually that is done using a look up table (LUT). Take a look at the functions GetImage and GetLUTValue in the dicomparser module in the dicompyler-core library.
In GetLUTValue it maps the data to an 8-bit greyscale image. If you want to use a different LUT, you would need to map the color space accordingly.

Converting PNG file to bitmap array in Python

I would like to convert a PNG image to a 2 dimensional array where each array holds a list of the RGB values of that specific pixel. How could one create a program to read-in a *.png file and convert to this type of data structure?
If you have PIL installed then you can create an image with Image.open and get the colors like so:
data = [image.getpixel((x, y)) for x in range(image.width) for y in range(image.height)]
You can use the existing pygame module. Import a file into a Surface using pygame.image.load. You can then access the bit array from this using pygame.surfarray.array2d. Please see the Pygame docs for more information.
You can use wand for such basic tasks. The syntax is very easy to read unlike other ImageMagik libs. Basically you'd do something like:
from wand.image import Image
from wand.display import display
array = []
with Image(filename='yourfile.png') as img:
array.append(img.channel_images) # this is most likely wrong, but it should be something similar
It will be along those lines. Once I leave the office I will try this out.

Open a multichannel image in Python OpenCV2

I have a 4 band multichannel image (TIF) which is an unsigned 16 bit image. I am using the following:
opencv2
python
I have done the following at the beginning of my code
import cv2
When I use
i = cv2.imread('img.tif')
it is reading all the four bands but as UINT8. When I use
i = cv2.imread('img.tif', cv2.CV_16U)
it reads only one channel of the image. What should be done to read all the four channels in 16bit unsigned?
Try passing the flag cv2.IMREAD_ANYDEPTH. The documentation states this flag will:
If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
i = cv2.imread('img.tif', flags=cv2.IMREAD_ANYDEPTH)
If that doesn't work, try the cv2.IMREAD_UNCHANGED flag instead. It's not documented, but it looks like it may also work.

Categories

Resources