daniel_hck
daniel_hck

Reputation: 1140

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

I am working on python - Open CV on Ubuntu. I am pretty new in python and I am feeling my coding is not optimized.

The final goal is to change the pixel color to an jpeg image. Let's say that if the red channel value is < 255 I set it at 255.

For that, I transformed the jpeg into a numpy.array. Then using 'for/ in:' loops I go pixel by pixel to check if the red channel is <255. If the condition is met, then I change the value to 255.

My code:

import numpy
import cv2

img=cv2.imread('image.jpeg',1)

y=x=-1  # I use y and x as a counters. 
        #They will track the pixel position as (y,x)

for pos_y in img:
    y=y+1; x=-1 #For each new column of the image x is reset to -1
    for pos_x in pos_y:
        x=x+1
        b, g, r = pos_x  # I get the blue, green and red color
                         # please note that opencv is bgr instead of rgb
        if r < 255:
             r = 255
             pos_x = [b,g,r]
             img[y,x] = pos_x

cv2.imshow('Image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

This code works. However, I feel is neither elegant nor efficient.

How could I optimize the code and make it more efficient?

Upvotes: 1

Views: 2748

Answers (2)

kmario23
kmario23

Reputation: 61415

How about this for an RGB image?

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

Using this we create a boolean mask from red channel of the image and check if its value is less than 255. If yes, then we set those values to 255.

OpenCV reads image as BGR, so:

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

would be appropriate.

Alternatively, you could also do:

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

Example:

In [24]: a
Out[24]: 
array([[[168],
        [170],
        [175]],

       [[169],
        [170],
        [172]],

       [[165],
        [170],
        [174]]])

In [25]: a > 170
Out[25]: 
array([[[False],
        [False],
        [ True]],

       [[False],
        [False],
        [ True]],

       [[False],
        [False],
        [ True]]], dtype=bool)

Using the above condition (a > 170), we generate a boolean mask. Now, imagine that you take any one of the channels and lay it on top of this boolean mask. And when we assign new values, wherever the mask has true values, those corresponding elements in the image array will be reset with new value.

# we just filter out the values in array which match our condition
In [36]: a[a > 170]
Out[36]: array([175, 172, 174])

# assign new values. Let's say 180
In [37]: a[a > 170] = 180   

In [38]: a
Out[38]: 
array([[[168],
        [170],
        [180]],    # <== new value

       [[169],
        [170],
        [180]],    # <== new value

       [[165],
        [170],
        [180]]])   # <== new value

Upvotes: 2

Paul Panzer
Paul Panzer

Reputation: 53079

If img is an mxnx3 numpy array the following changes the 3rd component in-place:

np.maximum(img[..., 2], 255, out=img[..., 2])

Upvotes: 0

Related Questions