user16755372
user16755372

Reputation:

Change numpy value/color red to black

I want to change the red value > 100 of image[1] to RGB(0,0,0) - image[2] - using Python.

Now: [1]: https://i.sstatic.net/cZhVG.jpg

Target: [2]: https://i.sstatic.net/bcTU0.png

For example, if it's RGB(120,60,90) it should be RGB(0,0,0)

data = np.array(img)

print(data)

Terminal:

[[[10  8  6]
  [10  8  6]
  [10  8  6]
  ...
  [ 8  7  5]
  [ 8  7  5]
  [ 8  7  5]]

 [[10  8  6]
  [10  8  6]
  [10  8  6]
  ...
  [ 8  7  5]
  [ 8  7  5]
  [ 8  7  5]]

 [[10  8  6]
  [10  8  6]
  [10  8  6]
  ...
  [ 8  7  5]
  [ 8  7  5]
  [ 8  7  5]]

...

I know that

data[..., 0]

is for the red channel.

Upvotes: 2

Views: 1837

Answers (3)

ddejohn
ddejohn

Reputation: 8952

Here's a one-liner:

(rgb[..., 0] < 100)[..., np.newaxis] * rgb

This also works (haven't tested which is faster):

rgb[rgb[..., 0] > 100] *= 0

Here's the result on a random (3, 5, 3) array:

>>> import numpy as np
>>> rgb = np.random.randint(0, 255, (3, 5, 3), dtype="uint8")
>>> rgb
array([[[159, 204, 134],
        [208, 224, 176],
        [177,  57,  26],
        [213, 191,  17],
        [ 71, 205, 162]],

       [[124,  94,  64],
        [ 41, 231, 130],
        [ 90, 235, 124],
        [ 18, 237, 101],
        [ 92,  86, 250]],

       [[104, 107, 251],
        [ 27, 247, 214],
        [123, 129,  88],
        [199, 105, 225],
        [ 29, 223, 117]]], dtype=uint8)
>>>
>>> (rgb[..., 0] < 100)[..., np.newaxis] * rgb
array([[[  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        [ 71, 205, 162]],

       [[  0,   0,   0],
        [ 41, 231, 130],
        [ 90, 235, 124],
        [ 18, 237, 101],
        [ 92,  86, 250]],

       [[  0,   0,   0],
        [ 27, 247, 214],
        [  0,   0,   0],
        [  0,   0,   0],
        [ 29, 223, 117]]], dtype=uint8)

EDIT: I did some very simple benchmarking on a 500x500 pixel "image":

In [1]: import numpy as np

In [2]: rgb = np.random.randint(0, 255, (500, 500, 3), dtype="uint8")

In [3]: rgb_copy = rgb.copy()

In [4]: %timeit rgb_copy[rgb[..., 0] > 100] *= 0
6.63 ms ± 15 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [5]: rgb_copy = rgb.copy()

In [6]: %timeit rgb_copy[rgb[..., 0] > 100] = np.array([0, 0, 0])
3.25 ms ± 14.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [7]: rgb_copy = rgb.copy()

In [8]: %timeit new_rgb = rgb * (rgb[..., 0] < 100)[..., np.newaxis]
1.24 ms ± 2.91 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Pretty similar results although my first suggestion seems to perform the best in my testing.

Upvotes: 0

CoffeeSyntax
CoffeeSyntax

Reputation: 79

if you're simply trying to change the values in the NumPy array, then just use NumPy's fancy indexing

data[data[..., 0] > 100] = np.array([0, 0, 0])

Upvotes: 1

Joran Beasley
Joran Beasley

Reputation: 113930

red_channel = data[..., 0]
mask = red_chanel > 100
data[mask] = [0,0,0]

I think ... you might have to get a bit fancier

data[mask][...,0] = 0 
data[mask][...,1] = 0 
data[mask][...,2] = 0 

(there is probably an easier way to set it but that should work)

Upvotes: 0

Related Questions