Home > Mobile >  Is there a way to use numpy array functions to get this same effect?
Is there a way to use numpy array functions to get this same effect?

Time:02-04

I am trying to filter out all non-gray values within a given tolerance with the following code. It gives the expected results but runs too slowly to use in practice. Is there a way to do the following using numpy operations?

for i in range(height):
        for j in range(width):
            r, g, b = im_arr[i][j]

            r = (r   150) / 2
            g = (g   150) / 2
            b = (b   150) / 2

            mean = (r   g   b) / 3
            diffr = abs(mean - r)
            diffg = abs(mean - g)
            diffb = abs(mean - b)

            maxdev = 2

            if (diffr   diffg   diffb) > maxdev:
                im_arr[i][j][0] = 0
                im_arr[i][j][1] = 0
                im_arr[i][j][2] = 0

CodePudding user response:

This can be done without any loop. I'll try to break out every step into a dedicated line

import numpy as np
im_arr = np.random.rand(300,400,3) # Assuming this how you image looks like
img_shifted = (im_arr   15) / 2 # This can be done in one go
mean_v = np.mean(img_shifted, axis=2) # Compute the mean along the channel axis
diff_img = np.abs(mean_v[:,:,None] - img_shifted) # Broadcasting to subtract n x m from n x m x k
maxdev = 2
selection = np.sum(diff_img, axis=2) > maxdev
im_arr[selection] = 0 # Using fancy indexing with booleans 

CodePudding user response:

Looping in plain Python is slow: one of the advantages of numpy is that transversing the arrays is highly optimized. Without commenting on the algorithm, you can get the same results using only numpy, which will be much faster

Since im_arr is an image, it is very likely that the dtype is np.uint8. That is only 8 bits, so you have to be careful of overflows. In you code, when you add 150 to a number, the result will be of type np.int64. But if you add 150 to an 8-bit np.ndarray, the result will still be of type np.uint8 and it can overflow. You can either change the array type (using astype) or add a float, which will automatically promote the array to float

mod_img = (im_arr   150.)/2  # the point of "150." is important
signed_dif = mod_img - np.mean(mod_img, axis=2, keepdims=True)
collapsed_dif = np.sum(np.abs(signed_dif), axis=2)
maxdev = 2
im_arr[collapsed_dif > maxdev] = 0
  •  Tags:  
  • Related