2

On a previous question I asked how to change colors on an image uploaded on a numpy.array using opencv (BGR format). The goal was to convert any red channel value < 255 to 255.

How to optimize changing the value of 3d numpy.array if meet a condition

The best answer was:

img[img[:, :, 2] < 255] = 255

The point is that I am not understanding what is going on (This is a different question since the previous one was perfectly answered). I understand this part:

img[:, :, 2] < 255

Is slicing y, x pixels on the red channel and being compared to 255 value.

However, I do not understand why this is embedded in another array:

img[...] = 255 

This has to be read something like: if (img[:, :, 2] < 255) then make this pixel-red channel=255 but I don't know how to read the code line to make it sound like that.

Can anyone explain me this code line very clear so I can modify for other purposes? How should I read it while writing it?

Community
  • 1
  • 1
daniel_hck
  • 1,100
  • 3
  • 19
  • 38

2 Answers2

5

This is called logical indexing.


Let's break this into two parts:

c=img[:, :, 2] < 255 # construct a boolean array

All the indices where c is equal to 1 are used to index elements of img.

img[c, 2] = 255 # set img to 255 at indices in c equal to 1


As an example, assume you have this array A=[10, 20, 34, 90, 100] and you want to change all the elements in A that greater than 11 to 2.

To do this with logical indexing, you would first construct a boolean array like this:

b=A>11 # [0, 1, 1, 1, 1]

Then, use b to index elements of A

A[b]=2

The resulting array would look like this:

[10, 2, 2, 2, 2]
Norbu Tsering
  • 609
  • 5
  • 14
4

First of all, I don't think the expression does what you want: convert any red channel value < 255 to 255., it will instead convert the pixel of all three channels to 255 if the corresponding red channel has value less than 255, what you need if you only want to change the red channel only is:

img[img[:, :, 2] < 255, 2] = 255

Example:

img = np.arange(12).reshape(2,2,3)
img
# array([[[ 0,  1,  2],
#         [ 3,  4,  5]],

#        [[ 6,  7,  8],
#         [ 9, 10, 11]]])

img[img[:,:,2] < 5,2] = 5

img
#array([[[ 0,  1,  5],      # the red channel of this pixel is modified to 5
#        [ 3,  4,  5]],
#
#       [[ 6,  7,  8],
#        [ 9, 10, 11]]])

This uses numpy boolean indexing. Simply speaking, the assignment does what your if statement is trying to do, replace values where the boolean mask(generated by img[:, :, 2] < 255) is true, and keep values where the mask is false.

Psidom
  • 209,562
  • 33
  • 339
  • 356
  • When editing the index `2` of an ndarray representing an image, doesn't it refer to blue instead of red (as mentioned in the comment) ? – Arthur Attout Nov 02 '19 at 19:39