How cv2.imshow() function works in BGR model? - python

In RGB color model, cv2.imshow() works by bgr order,when use cv2.imshow() to load a image,and show it in matplotlib.plot.show() function,it goes wrong cause plot.show() use rgb order,it can be solved by reverse the channels of b,g,r in image,but when I make RGB color model transformation into other color model,like HSV,YUV,YCbCr,when use plot.show() it still be different to cv2.show().So when RGB->HSV,YUV,YCbCr color model,does cv2.show() still works like v,s,h maps to b,g,r?And plt.show() use the order h,s,v maps to r,g,b?No matter what color model use cv2.show() and plot.show(),it just use b,g,r and r,g,b orders maps to changed channels?Like v,s,h and h,s,v in HSV,v,u,y and y,u,v in YUV?
img_HSV = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2HSV)
plt.show(img_HSV )
cv2.show(img_HSV )
plt.show(img_HSV [:,:,::-1])
the result in line 1 code is different with line2,but line 3 is same as line2.
So plt.show works by h,s,v maps to r,g,b and cv2.show works by v,s,h maps to b,g,r?

plt.show(img_HSV ) assumes the input is RGB
cv2.show(img_HSV ) assumes the input is BGR
So if you give input in a different format they take the channel as they assume anyway. For example, cv2.imshow(img_HSV ) method will take the Hue value as Blue so there will be a different image representation.
So just convert them back to RGB or BGR for imshow() functions after your processes done with the other color spaces.

I assume you mean cv2.imshow (and plt.imshow) as in your title, right? Most of the time (and in all your examples) you pass an image with three channels to the functions plt.imshow and cv2.imshow.
Those are numpy arrays and the data type (uint8, float32, ect) is the only information you implicitly pass along. So those functions simply don't know which color encoding you are currently using. They simply interpret it as RGB (matplotlib) respectively BGR (OpenCV). So the second channel will always be interpreted as green and the other ones as red and blue respectively. That's all they do.
PS: If you pass a single-channel array you'll get a gray image.
PPS: Consider the range of the values in your numpy array. For example if you are passing float the values should be in the interval [0-1], whereas with uint8 it's [0-255] for matplotlib.

Related

Create a grayscale image from a color coded source image in Python

I want to convert a color-coded image to grayscale. The colors in that image correspond to given values (e.g. black is 0 and red is 25) like on this color scale.
Is there a way to convert this image to grayscale and keep that color gradient, so that 0 on the scale remains black and 25 is shown as white?
I tried to convert it with matplotlib and also cv2 but ended up with grayscale images, that did not respect my given color gradient. I would appreciate an answer very much. Thank you!
Depending on the tools you use you can
read/convert the color-coded image as RGB,
convert RGB to grayscale
or
convert the colors in the gradient to grayscale,
read/convert the color-coded image using that grayscale palette.
The second approach is more efficient.
Update:
Upon reading your last comment (which should be in the original question), the options become
read/convert the color-coded image as RGB,
convert RGB to grayscale,
rescale by multiplying the pixel values by 10
or
convert the colors in the gradient to grayscale, rescaled to 0-255,
read/convert the color-coded image using that grayscale palette.

How RBG triplet value is converted into single value? single value comes between 0 to 255. how single value is mapped into color image?

Using OpenCV, input image(Blue background image Christmas tree inside) was read.
Below image is input image.
the output of read image is changed from a blue background into the red.
when I viewed the value of the variable of 'image' in spyder. Here 3 is RGB channel
When double-clicked the value it shows with Axis =0. what I understood is BGR value
Axis =1 here to0 BGR
Axis =2. I am stuck here. I would not understand how triplet value of(pixel) RBG value is converted into a single value of each pixel and how this pixel(0,0)=254 represents red color here.
I understood for black and white values varies from 0 to 255. But here how axis =2 (pixel(0,0)=254) represents Red color(guessing from output of the read image).
You are reading image using OpenCV where it takes BGR color channel matrix. However you are displaying it using some other library which take color channel matrix as RGB. Convert your image to RGB using cv2.cvtColor(image, cv2.BGR2RGB) and it will then display it.

Converting image to grayscale

I want to convert any image to grayscale, but I don't understand the difference between these implementations.
image = cv2.imread('lenna.jpg')
gray = cv2.cvtColor(image, cv2.IMREAD_GRAYSCALE)
gray1 = rgb2gray(image)
gray2 = cv2.imread('lenna.jpg', cv2.IMREAD_GRAYSCALE)
image1 = Image.open('lenna.jpg', 'r')
gray3 = image1.convert('L')
When I plot them, I get them in blue scale, green scale, green scale and gray respectively. When I should use each one?
You've encountered a spot where Python's type system isn't protecting you in the way that C++ would.
cv2.IMREAD_GRAYSCALE and cv2.COLOR_BGR2GRAY are values from different enumerations. The former, whose numerical value is 0, applies to cv2.imread(). The latter, whose numerical value is 6, applies to cv2.cvtColor(). C++ would have told you that cv2.IMREAD_GRAYSCALE can't be passed to cv2.cvtColor(). Python quietly accepts the corresponding int value.
Thus, you think you're asking cv2 to convert a color image to gray, but by passing cv2.IMREAD_GRAYSCALE, cv2.cvtColor() sees the value 0, and thinks you're passing cv2.COLOR_BGR2BGRA. Instead of a grayscale image, you get the original image with an alpha channel added.
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
is what you need instead.
The other issue you're seeing, assuming you're using a Jupyter notebook, is that cv2 layers color planes in BGR order instead of RGB. To display them properly, first do
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
and then display the result.
The images that are not gray are the still 3d arrays, that is to say they still somehow retain color information, the reason you are seeing blue and green is because in those 3d arrays the red and green channels in the first case and the blue & red channels in the second have been reduced to 0 leaving only the blue and green that you see.
In order to read the image as grayscale you would use
img_gray=cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
This will yield a 2d array with values between 0 and 255 corresponding to how bright the pixel should be instead of how bright each of the 3 color channels of the pixel should be.

What is a "twice HSV transformation"?

I learned this method from a SPIE Proceeding article, they used the twice HSV transformation for shadow detection. In their paper, the method was stated as following:
Firstly, the color model of the image is transformed from RGB to HSV,
and the three components of the HSV model are normalized to 0 to 255,
then the image is transformed from RGB to HSV once again. Thirdly, the
image is turned into a gray image from a color image, only the gray
value of the red component is used. Fourthly, the OTSU thresholding
method is used to produce a threshold by which the image is converted
to a binary image. Since the gray value of the shadow area is usually
smaller than those areas which are not covered by shadow, the
objective is pixels whose gray value is below the threshold, and
background is pixels whose gray value is beyond the threshold.
Do the second and third steps make sense?
The second and third statements absolutely don't make any sense whatsoever. Even the pipeline is rather suspicious. However, after re-reading that statement probably a dozen times, here is what I came up with. Apologies for any errors in understanding.
Let's start with the second point:
Firstly, the color model of the image is transformed from RGB to HSV, and the three components of the HSV model are normalized to 0 to 255, then the image is transformed from RGB to HSV once again
You're well aware that transforming an image from RGB to HSV results in another three channel output. Depending on which platform you're using, you'll either get 0-360 or 0-1 for the first channel or Hue, 0-100 or 0-255 for the second channel or Saturation, and 0-100 or 0-255 for the third channel or Value. Each channel may be unequal in magnitude when comparing with the other channels, and so these channels are normalized to the 0-255 range independently. Specifically, this means that the Hue, Saturation and Value components all get normalized so that they all span from 0-255.
Once we do this, we now have a HSV image where each channel ranges from 0-255. My guess is they call this new image a RGB image because the channels all span from 0-255, just like any 8-bit RGB image would. This also makes sense because when you're transforming an image from RGB to HSV, the dynamic range of the channels all span from 0-255, so my guess is that they normalize all of the channels in the first HSV result to make it suitable for the next step.
Once they normalize the channels after doing HSV conversion as per above, they do another HSV conversion on this new result. The reasons why they would do this a second time are beyond me and don't make any sense, but that's what I gathered from the above description, and that's what they probably mean by "twice HSV transformation" - To transform the original RGB image to HSV once, normalize that result so all channels span from 0-255, then re-apply the HSV conversion again to this intermediate result.
Let's go to the third point:
Thirdly, the image is turned into a gray image from a color image, only the gray value of the red component is used.
The output after you transform the HSV image a second time, the final result is simply taking the first channel which is inherently a grayscale image and is the "red" channel. Coincidentally, this also corresponds to the Hue after you do a HSV conversion. I'm not quite sure what properties the Hue channel holds after converting the image using HSV twice, but maybe it worked for this particular method.
I decided to give this a whirl and see if this really works. Here's an example image of a shadow I found online:
Source: http://petapixel.com/
The basic pipeline is to take an image, convert it into HSV, renormalize the image so that the values are 0-255 again, do another HSV conversion, then do an adaptive threshold via Otsu. We threshold below the optimal value to segment out the shadows.
I'm going to use OpenCV Python, as I don't have the C++ libraries set up on my computer here. In OpenCV, when converting an image to HSV, if the image is unsigned 8-bit RGB, the Saturation and Value components are automatically scaled to [0-255], but the Hue component is scaled to [0-179] in order to fit the Hue (which is originally [0-360)) into the data type. As such, I scaled each value by (255/179) so that the Hue gets normalized to [0-255]. Here's the code I wrote:
import numpy as np # Import relevant libraries
import cv2
# Read in image
img = cv2.imread('shadow.jpg')
# Convert to HSV
hsv1 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Renormalize Hue channel to 0-255
hsv1[:,:,0] = ((255.0/179.0)*hsv1[:,:,0]).astype('uint8')
# Convert to HSV again
# Remember, channels are now RGB
hsv2 = cv2.cvtColor(hsv1, cv2.COLOR_RGB2HSV)
# Extract out the "red" channel
red = hsv2[:,:,0]
# Perform Otsu thresholding and INVERT the image
# Anything smaller than threshold is white, anything greater is black
_,out = cv2.threshold(red, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Show the image - shadow mask
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
This is the output I get:
Hmm.... well there are obviously some noisy pixels, but I guess it does work.... kinda!

PIL Converting an image's hue, then saving out in Python

I'm loading and saving out images with PIL just fine but I can't seem to change the "overall" hue of a given image ~ google and here revealed an answer, sort of, with the numpy module, but thats not an option for me
It should be quite simple, given a gray image with alpha, I'd like to make it's hue red
I think you want a mono-hue image. Is this true?
It's not clear what you want done with the existing bands (alpha and greyscale/level). Do you want alpha to remain alpha and the greyscale to become red saturation? Do you want the alpha to become your red saturation? Do you want greyscale to be the image lightness and the alpha to become the saturation?
Edit:
I've changed the output based on your comment. You wanted the darkest shade of the greyscale band to represent fully saturated red and the lightest grey to represent white (in other words full-saturated with all colors). You also indicated that you wanted alpha to be preserved as alpha in the output. I've made that change too.
This is possible with some band swapping:
import Image
# get an image that is greyscale with alpha
i = Image.open('hsvwheel.png').convert('LA')
# get the two bands
L,A = i.split()
# a fully saturated band
S, = Image.new('L', i.size, 255).split()
# re-combine the bands
# this keeps tha alpha channel in the new image
i2 = Image.merge('RGBA', (S,L,L,A))
# save
i2.save('test.png')

Categories