Ask Your Question

Replace a range of colors with a specific color in python

asked 2016-06-28 00:16:47 -0500

helxsz gravatar image

updated 2016-06-28 08:41:03 -0500

I have a image with white background, grey and black part, I want to segment three parts into different color.

so far I could segment the black and grey part with inRange, but I wonder Is there a python API that substitute one color with another color, for example to substitute the black part with red color.

original image
original image

   frame = cv2.imread("/home/ad/Desktop/1.png")

image after inrange image after inrange

lower_black = np.array([0,0,0], dtype = "uint16")
upper_black = np.array([70,70,70], dtype = "uint16")
black_mask = cv2.inRange(frame, lower_black, upper_black)

image description substitute the black color to white color

black_mask[np.where((black_mask == [0] ).all(axis = 1))] = [255]

However, in the last image when trying to substitute the black color into the white color, only a traction of black color has been transformed, there are some parts of the black part remains to be black

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2016-06-28 02:20:10 -0500

Missing gravatar image

updated 2016-06-28 10:30:46 -0500

You can simply use numpy to do this.

image = np.zeros((400,400,3), dtype="uint8")
image[np.where((image==[0,0,0]).all(axis=2))] = [255,255,255]

This will change all pixels in image that have a value of [0,0,0] to [255,255,255].

After your inRange() operation you get an image in black and white, so you have just one color channel. In that case you have to use:

image[np.where((image==[0]).all(axis=1))] = [255]

This will change all rows in your image that are completely black to white. To change not only the rows that are completely black omit the call to numpy.all(). Use:

image[np.where(image == [0])] = [255]

Best regards

edit flag offensive delete link more


@Missing, I tried " image[np.where((image==[0,0,0]).all(axis=2))] = [255,255,255] ", but returns " AttributeError: 'bool' object has no attribute 'all' ", so I guess it another way, image[np.where((image==[0,0,0])).all(axis=2)] = [255,255,255], but still telling me a error "AttributeError: 'tuple' object has no attribute 'all' "

helxsz gravatar imagehelxsz ( 2016-06-28 04:47:06 -0500 )edit

Your first attemp should work correctly. Did you import numpy correctly as np? Do you use your image or the image i created with np.zeros?

import cv2
import numpy as np

    image = np.zeros((400,400,3), dtype="uint8")
    raw = image.copy()
    image[np.where((image==[0,0,0]).all(axis=2))] = [255,255,255]
    cv2.imshow('Test', image)
    cv2.imshow('Test2', raw)
    if cv2.waitKey() == ord('q'):

This is the complete code for the example and it turns a black image into a white one.

Missing gravatar imageMissing ( 2016-06-28 05:04:32 -0500 )edit

Hi, @Missing, actually it works for the original image but it is strange that the resulted mask from inRange() can't be performed on same operation`enter code here.

frame = cv2.imread("/home/ad/Desktop/1.png")
lower_black = np.array([0,0,0], dtype = "uint16")
upper_black = np.array([70,70,70], dtype = "uint16")
black_mask = cv2.inRange(frame, lower_black, upper_black)
frame[np.where((frame == [0,0,0]).all(axis = 2))] = [0,255,255]     # it works
black_mask[np.where((black_mask == [0,0,0]).all(axis = 2))] = [0,255,255]   # it doesn't work
helxsz gravatar imagehelxsz ( 2016-06-28 05:58:25 -0500 )edit

Hey, yes because your original image is in RGB color format. The masked image is just black and white, so you just have one color channel. Change your code to:

black_mask[np.where((black_mask == [0]).all(axis = 1))] = [255]
Missing gravatar imageMissing ( 2016-06-28 06:19:49 -0500 )edit

@Missing, thanks for reminding me this. I tried the approach, it works but only partially, there is some parts not being transformed. Any ideas? I have updated in the main content.

helxsz gravatar imagehelxsz ( 2016-06-28 08:42:24 -0500 )edit

Okay my fault. The problem here is that the call to numpy.all() tests whether the condition is true for the whole array, meaning it checks if every pixel in an image row is black and that is obviously not true in your case. So try it without the numpy.all() function. Just use

black_mask[np.where(black_mask == [0])] = [255]
Missing gravatar imageMissing ( 2016-06-28 09:03:49 -0500 )edit

Thanks a lot, @Missing, it works perfectly and I learned a lot! if you can add it to the answer, I can score it. :)

helxsz gravatar imagehelxsz ( 2016-06-28 09:35:49 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower


Asked: 2016-06-28 00:16:47 -0500

Seen: 39,744 times

Last updated: Jun 28 '16