Splitting RGB Channels of an Image Using Numpy

124 Views Asked by At

Post reference: Splitting of an RGB image to R G B using OpenCv Python I'm quite new to using opencv and numpy and simply don't understand how Method #1 works to both copy the image and change channels to black. This is a copy of the code section I don't understand:

r = img.copy()
r[:,:,0] = r[:,:,1] = 0

g = img.copy()
g[:,:,0] = g[:,:,2] = 0

b = img.copy()
b[:,:,1] = b[:,:,2] = 0

Could someone post an explanation that a 75+ years -old can understand? Thank you for any assistance!

The code clearly works...I'm simply trying to understand how the colors are separated / merged within the numpy array

2

There are 2 best solutions below

0
Mark Setchell On

OpenCV stores images as Numpy arrays, like this:

image[row, column, channel]

with the channels in B, G, R order. So channel 0 is blue, channel 1 is green and channel 2 is red.

So this command will set the blue channel to 0 for every row and every column, i.e. it will zero out the blue component:

im[:, :, 0] = 0

This will zero out the green everywhere:

im[:, :, 1] = 0

So, you'll be left with a 3-channel image in which the red component is the only one with anything in it, since both blue and green will be empty.

So, as an example, if you start with this:

enter image description here

and you do this:

import cv2 as cv
im = cv.imread('a.png')
r = im.copy()
r[:,:,0] = 0      # zero out blue channel
r[:,:,1] = 0      # zero out green channel
cv.imwrite('result.png', r)

you'll get:

enter image description here


You could do both in one go, by the way, using "fancy indexing":

im[:, :, [0,1]] = 0
0
bfris On

Your code does a couple of things:

  • make a copy of the original image, preserving all 3 channels
  • zero out the channels you don't want

As you've noticed, the code is a little confusing. It could be rewritten by making it a little more verbose.

# assume img is a BGR image (OpenCV uses BGR order by default)
# image is 3D array of form (x, y, <color channel>)
# color channels   0 --> B   1 --> G   2 --> R

r = img.copy()  # make a copy of entire image
r[:,:,0] = 0    # set blue channel to 0
r[:,:,1] = 0    # set green channel to 0

g = img.copy()
g[:,:,0] = 0    # set blue channel to 0
g[:,:,2] = 0    # set red channel to 0

b = img.copy()
b[:,:,1] = 0    # set green channel to 0
b[:,:,2] = 0    # set red channel to 0

While this code might work, you might consider using OpenCV convenience functions split() and merge(). In the official Python tutorials, they say that using numpy indexing is faster, but I haven't found split and merge to be slow.

b,g,r = cv.split(img)  # split 3D img into 2D b,g,r

# do some processing here
#

img = cv.merge((b,g,r))