Why applying the same channel thrice results in a black and white image?

850 Views Asked by At

I was experimenting with color swapping using opencv. In the following snippet, the results are pretty close to what I expect.

import cv2

color = cv2.imread("lohri.jpg")
b,g,r = cv2.split(color)
swap = cv2.imwrite("swap.jpg", cv2.merge((r,g,b)))

As you see above, I have swapped the 2 color channels red and blue. But if I apply only one channel, as follows:

swap = cv2.imwrite("swap.jpg", cv2.merge((b,b,b)))

it results in a black and white image. I could not understand why. Could anyone help me understand this?

Following is the image resulting from applying the same channel thrice.

enter image description here

The original image looked like: enter image description here

This happens irrespective of the channel (r,g,b) choosen

1

There are 1 best solutions below

0
On

There are a couple things to understand here.

First, We should discuss how color coding works. Source article. Highly recommend reading it

A digital photograph consists of pixels, a pixel being a colored dot, the smallest element of the image. Each pixel has one and only one color.

Bold Emphasis mine.

The main takeaway here is this, the final image is a combination of the different channels (so to speak. more on that later) for every single pixel.

Second,

Multiple ways of color coding exist. The most prominent of these is RGB. So there we are: RGB. R means: red. G means: green. B means: blue. The RGB color coding assumes that every color has three components: red, green and blue. Believe it or not, all colors that humans can see can be composed from a combination of red, green and blue.

The important thing to understand here is that R,G,B is just one way to represent this "combination" for each pixel. It is only the combination that gives us the colours we see in an image.

Third, in RGB, the numbers represent the "amount" for that colour/channel component. 0 means: nothing, 255 means: the maximum amount.

Fourth,

First observation: In the RGB way of color coding, the higher the numbers, the lighter the corresponding color.

Second observation: When all three of R, G and B are equal, we get a neutral color: white, grey or black.

This part is really important to understand. Because the R,G and B values only represents the components, they have to be merged based on "how much" of each component is present. If they are present in equal quantities, they all generate something along the shades of black-to-white (commonly called as greyscale). The blackness/whiteness depends on the actual number for every channel, 0 would be black, 255 white, others somewhere in between. It is important to understand that this means that the image still can have the 3 R,G,B components, but they all have been set to the same value for a pixel that is greyscale.

Now, diving into the coding aspect of it, it is important to realise, that the numbers are just that, pure numbers.

import cv2

color = cv2.imread("lohri.jpg")
b,g,r = cv2.split(color)

Here, b,g and r are no longer anything special, they are just matrices storing numbers, one for each pixel. I can very well write different names for them as follows:

import cv2

color = cv2.imread("lohri.jpg")
apple,mango,orange = cv2.split(color) #perfectly valid, although confusing

Clearly, the names are just that, names. It is only the "combinations" in an image that were giving them any significance. So, then, when you do this step

swap = cv2.imwrite("swap.jpg", cv2.merge((b,b,b)))

I can very well write it like this

swap = cv2.imwrite("swap.jpg", cv2.merge((some_random_matrix,some_random_matrix,some_random_matrix)))

Or like this,

swap = cv2.imwrite("swap.jpg", cv2.merge((apple,apple,apple)))

The important point to understand is this: the variable name b had absolutely no signifance on its own, it was just a matrix of numbers. When you use the merge function and set each R,G and B channel with the same matrix, you effectively assign each pixel the same values for each R,G,B value. As we know from before, when each "channel" for a pixel has same values, the "combination" is always black-to-white (or greyscale).

Finally, if you instead wanted it to look blue instead of greyscale, you may now be able to guess the correct way to do that.

The correct way is to keep values in the blue channel, but set the other channels to 0 for each pixel. Setting all channels to same value does not get you "more of that specific colour", because the value alone has no meaning, it is just "the combination" of the values on each channel.

color = cv2.imread('lohri.jpg')

new_image = color.copy()
# set green and red channels to 0
new_image[:, :, 1] = 0
new_image[:, :, 2] = 0
cv2.imwrite("only_blue.jpg", new_image)