matplotlib RGB image different cmap? - python

Is there a way to change the colormap of an RGB image in matplotlib from hsv to say twilight?
If I have an array that is x,y,3 from 0 to 255, it gives a normal RGB image. Is this somehow changable to say colorscheme from the twilight cmap? As a way to make the picture work for colorblind people.

Related

Percentage of clouds in an image [duplicate]

Regarding the following cv2.inRange(...) invocation:
mask = cv2.inRange(quantized_img, color, color)
Must the 'quantized_img' and 'color' arguments be strictly in HSV or it's OK to have RGB image and RGB 'color'? It seems that RGB works for me, but all examples I could find are HSV-based. So I'm concerned about the correct usage.
Thanks!
In general, use whatever color space you like. RGB/BGR is fine, HSV is fine, something completely made up (with cv.transform) is fine too.
inRange spans a "cube".
Think about it. Imagine a 3D plot with R,G,B axes, or with H,S,V axes. In RGB space, the faces of the cube are aligned with those RGB axes. in HSV space the faces of the cube are aligned with those axes instead.
Now, a cube spanned in RGB space, when transformed into HSV space, is not aligned with the axes in HSV space. In fact it's not even a cube anymore, but likely some kind of torus or section of a cone or something. Same goes the other way around.
If the area of values you're interested in, in whatever space you choose, is flat or even stick-shaped (instead of a mostly spherical cloud), the cube you have to span might align very badly with the area of values you are interested in, and would have to include a lot of values you aren't interested in.
So you move into another color space where your values of interest are somewhat better aligned with the axes in that space. Then the cube spanned by inRange fits your purpose better.
Imagine a "stick" in RGB space going from the black corner to the white corner. It represents "colors" with no saturation to them (because colors are in the other six corners of the cube). Try spanning a cube over that area. Doesn't fit well.
In HSV space however, it's trivial. Usually it's visualized as a cylinder/inverted cone though... span a thin cylinder in the center: any Hue (angle), any Value (height), with very low Saturation (close to the center axis). If you took HSV as a cube, you'd span a thin wall instead. And it all would fit very well.
The explanation given by #Christoph Rackwitz is completely correct. I'll just like to add a few tips observed by me.
HSV and Lab color spaces are the best ones for color segmentation.
Keep BGR color space as probably the last option.
Do not just blindly start finding the range in HSV or Lab color segmentation for your color. Look for other methods too.
Other methods include:
Visualize each color channel of HSV and Lab separately as a grayscale image. You might see some pattern there only.
One thing that helped in my case was I did Otsu's thresholding on "Hue" and "Saturation" channels of my image and then performed a bitwise OR operation on their output. The final image had everything I need without any errors. Do a hit-and-try on your input images to observe such patterns. This helps a lot.

Use different colormap with one channel image - cv2.imshow()

When I use this method with an 1 channel image, it's shown in grayscale. Is there a way to use other color maps (not grayscale) when showing an 1 channel image? If there is, it means grayscale is the default for imshow when working with an image with only 1 channel? Thanks in advance
As far as I know, you cannot apply a color map in Python/OpenCV cv2.imshow like you can with Mathplotlib pyplot. But you can create a color map and apply it to your grayscale image using cv2.LUT to change your grayscale image into a colored image that you can display with cv2.imshow.
Please see the documentation for cv2.imshow at https://docs.opencv.org/4.1.1/d7/dfc/group__highgui.html#ga453d42fe4cb60e5723281a89973ee563

How to convert a grayscale image to heatmap image with Python OpenCV

I have a (540, 960, 1) shaped image with values ranging from [0..255] which is black and white. I need to convert it to a "heatmap" representation. As an example, pixels with 255 should be of most heat and pixels with 0 should be with least heat. Others in-between. I also need to return the heat maps as Numpy arrays so I can later merge them to a video. Is there a way to achieve this?
Here are two methods, one using Matplotlib and one using only OpenCV
Method #1: OpenCV + matplotlib.pyplot.get_cmap
To implement a grayscale (1-channel) -> heatmap (3-channel) conversion, we first load in the image as grayscale. By default, OpenCV reads in an image as 3-channel, 8-bit BGR.
We can directly load in an image as grayscale using cv2.imread() with the cv2.IMREAD_GRAYSCALE parameter or use cv2.cvtColor() to convert a BGR image to grayscale with the cv2.COLOR_BGR2GRAY parameter. Once we load in the image, we throw this grayscale image into Matplotlib to obtain our heatmap image. Matplotlib returns a RGB format so we must convert back to Numpy format and switch to BGR colorspace for use with OpenCV. Here's a example using a scientific infrared camera image as input with the inferno colormap. See choosing color maps in Matplotlib for available built-in colormaps depending on your desired use case.
Input image:
Output heatmap image:
Code
import matplotlib.pyplot as plt
import numpy as np
import cv2
image = cv2.imread('frame.png', 0)
colormap = plt.get_cmap('inferno')
heatmap = (colormap(image) * 2**16).astype(np.uint16)[:,:,:3]
heatmap = cv2.cvtColor(heatmap, cv2.COLOR_RGB2BGR)
cv2.imshow('image', image)
cv2.imshow('heatmap', heatmap)
cv2.waitKey()
Method #2: cv2.applyColorMap()
We can use OpenCV's built in heatmap function. Here's the result using the cv2.COLORMAP_HOT heatmap
Code
import cv2
image = cv2.imread('frame.png', 0)
heatmap = cv2.applyColorMap(image, cv2.COLORMAP_HOT)
cv2.imshow('heatmap', heatmap)
cv2.waitKey()
Note: Although OpenCV's built-in implementation is short and quick, I recommend using Method #1 since there is a larger colormap selection. Matplotlib has hundreds of various colormaps and allows you to create your own custom color maps while OpenCV only has 12 to choose from. Here's the built in OpenCV colormap selection:
You need to convert the image to a proper grayscale representation. This can be done a few ways, particularly with imread(filename, cv2.IMREAD_GRAYSCALE). This reduces the shape of the image to (54,960) (hint, no third dimension).

how to extract the relative colour intensity in a black and white image in python?

Suppose I have got a black an white image, how do I convert the colour intensity at each point into a numerical value that represents its relativity intensity?
I checked somewhere on the web and found the following:
Intensity = np.asarray(PIL.Image.open('test.jpg'))
What's the difference between asarray and array?
Besides, the shape of the array Intensity is '181L, 187L, 3L'. The size of the image test.jpg is 181x187, so what does the extra '3' represent?
And are there any other better ways of extracting the colour intensity of an image?
thank you.
The image is being opened as a color image, not as a black and white one. The shape is 181x187x3 because of that: the 3 is there because each pixel is an RGB value. Quite often images in black and white are actually stored in an RGB format. For an image image, if np.all(image[:,:,0]==image[:,:,1]) and so on, then you can just choose to use any of them (eg, image[:,:,0]). Alternatively, you could take the mean with np.mean(image,axis=2).
Note too that the range of values will depend on the format, and so depending upon what you mean by color intensity, you may need to normalize them. In the case of a jpeg, they are probably uint8s, so you may want image[:,:,0].astype('float')/255 or something similar.

What does matplotlib `imshow(interpolation='nearest')` do?

I use imshow function with interpolation='nearest' on a grayscale image and get a nice color picture as a result, looks like it does some sort of color segmentation for me, what exactly is going on there?
I would also like to get something like this for image processing, is there some function on numpy arrays like interpolate('nearest') out there?
EDIT: Please correct me if I'm wrong, it looks like it does simple pixel clustering (clusters are colors of the corresponding colormap) and the word 'nearest' says that it takes the nearest colormap color (probably in the RGB space) to decide to which cluster the pixel belongs.
interpolation='nearest' simply displays an image without trying to interpolate between pixels if the display resolution is not the same as the image resolution (which is most often the case). It will result an image in which pixels are displayed as a square of multiple pixels.
There is no relation between interpolation='nearest' and the grayscale image being displayed in color. By default imshow uses the jet colormap to display an image. If you want it to be displayed in greyscale, call the gray() method to select the gray colormap.

Categories