1

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?

kmario23
  • 57,311
  • 13
  • 161
  • 150
daniel_hck
  • 1,100
  • 3
  • 19
  • 38
  • Does my answer solve your problem? – kmario23 Mar 27 '17 at 04:37
  • Where you actually check and change the subpixel value shouldn't that be `r` instead of `v`? – Paul Panzer Mar 27 '17 at 06:11
  • Kmario: yes, thankk you. Please see my comment after your answer Paul Panzer: You are right. I copied the code manually and changed the name of variables to make it easier to follow. Corrected. – daniel_hck Mar 27 '17 at 15:28

2 Answers2

2

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
kmario23
  • 57,311
  • 13
  • 161
  • 150
  • 1
    Yes, that is beutiful. I was just waiting for more answers. Can you explainme a little bit your answer. I got the img[:,:,0]<255. You slice all y,x for color r to change the value. But I do not understand why is embebed into another array? – daniel_hck Mar 27 '17 at 15:26
  • Updated my answer with more explanation – kmario23 Mar 27 '17 at 18:07
  • 1
    Not only is more elegant but much more efficient. The time to show the results has incredibly decreased – daniel_hck Mar 28 '17 at 03:57
0

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

np.maximum(img[..., 2], 255, out=img[..., 2])
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99