Reputation: 21
I am reading an image captured through opencv and want to map a function to every pixel value in the image. The output is an m x n x 3 numpy array, where m and n are the coordinates of length and width of the image and the three values are the corresponding blue, green, and red values for each pixel.
I first thought to run a nested for loop to each value in the image. However, it takes a long time to run, so I am looking for a more efficient way to loop over the image quickly.
Here is the nested for loop:
a = list()
for row in img:
for col in row:
a.append(np.sqrt(np.prod(col[1:])))
adjusted = np.asarray(a).reshape((img.shape[0], img.shape[1]))
This code works, but I would like to make it run faster. I know vectorization could be an option, but I do not know how to apply it onto only part of an array and not a whole array. To do this, I think I could reshape it to img.reshape((np.prod(img.shape[:2]),3))
and then loop over each set of three values, but I do not know the correct function/iterator to use.
Also, if opencv/numpy/scipy has another function that does just this, it would be a great help. I'm also open to other options, but I wanted to give some ideas that I had.
In the end, I want to take the input and calculate the geometric mean of the red and green values and create an n x m array of the geometric means. Any help would be appreciated!
Upvotes: 2
Views: 724
Reputation: 442
This can be vectorized using the axis
parameter in np.prod()
. Setting axis=-1
will cause the product to only be taken on the last axis.
To perform this product on only the last two channels, index the array to extract only those channels using img[..., 1:]
You can replace your code with the following line:
adjusted = np.sqrt(np.prod(img[..., 1:], axis=-1))
For fun, let's profile these two functions using some simulated data:
import numpy as np
img = np.random.random((100,100,3))
def original_function(img):
a = []
for row in img:
for col in row:
a.append(np.sqrt(np.prod(col[1:])))
adjusted = np.asarray(a).reshape((img.shape[0], img.shape[1]))
return adjusted
def improved_function(img):
return np.sqrt(np.prod(img[:,:,1:], axis=-1))
>>> %timeit -n 100 original_function(img)
100 loops, best of 3: 55.5 ms per loop
>>> %timeit -n 100 improved_function(img)
100 loops, best of 3: 115 µs per loop
500x improvement in speed! The beauty of numpy vectorization :)
Upvotes: 2