Reputation: 113
I have a PNG image with the dimensions 1024x1024
that contains RGB encoded elevation data.
I read in the image using asarray
from numpy
:
rgb_data = np.asarray(image)
Which results in an 3D array with dimensions (1024, 1024, 4)
. (I'm using RGBA)
I need to run some filters (gaussian, median) over that data, but I need to run it on the decoded elevation data.
The elevation data can be decoded with the following function:
def decodeRGB(pixel):
return (pixel[0] * 256 + pixel[1] + pixel[2] / 256) - 32768
After decoding I will have a 2D array with dimensions (1024, 1024)
that contains the decoded elevation data. (The actual height above sea level)
What I have so far is this:
rgb_data = np.asarray(image)
decoded_data = np.zeros(tile.size)
for rownum in range(width):
for colnum in range(height):
decoded_data[rownum][colnum] = decodeRGB(rgb_data[rownum][colnum])
Unfortunately this solution is quite slow. It takes approx. 10 seconds for a 1024 by 1024 image.
Is there a more performant way to implement this?
My main issue is that the dimensions of the array changes.
I'm going from a (1024, 1024, 4)
array to a (1024, 1024)
array.
I'm basically looking for a fast/efficient way to apply a function to every RGB pixel in an image which allows reduction of the array size.
Thanks a lot for your help!
Upvotes: 1
Views: 1583
Reputation: 53029
Take advantage of vectorisation:
r = rgb_data[..., 0]
g = rgb_data[..., 1]
b = rgb_data[..., 2]
decoded_data = (256*r + g + b/256) - 32768
For example rgb_data[..., 0]
selects all 1024x1024
red values at once, 256*r
multiplies all of them with 256 in one go, and so forth. Since the interpreted for loops in your code come with a significant overhead avoiding them should drastically speed up the conversion.
Or you could use a one-liner:
decoded_data = (rgb_data[..., :3] * (256, 1, 1/256)).sum(axis=-1) - 32768
There are yet more ways similar in spirit. Look at the comments on this post for a nice collection of one-liners.
Upvotes: 4
Reputation: 14399
You can vectorize the process using the very powerful np.einsum
. Just make a transform vector out of your coefficients.
def decodeRGBArray(rgb_data):
transf = np.array([256., 1., 1./256., 0.])
return np.einsum('ijk,k->ij', rgb_data, transf) - 32768
Upvotes: 3