1

I want to average a slice of a numpy array (its an image).

Currently i'm iterating over each pixel as follows but its dreadfully slow. I know there is a better way but I cant work it out. Its probably the numpy fancy indexing but i'm stuck.

I've used openCV to read the image into a numpy array with the shape 640,480,3 and I want to change the each of the last bit i.e [123,121,234] to the average of that slice for each of the 640x480.

You don't have to give me the answer but a shove in the right direction would be helpful.

This is whats slow for me:

 def bw_image_arr(self):

    for x in self.images:
        for y in x:
            for z in y:
                z = z.mean()
5
  • Use axis argument for .mean. Commented Sep 30, 2019 at 19:30
  • Do you want calculate mean value of each RGB channel? Commented Sep 30, 2019 at 19:46
  • I am experimenting and I want to change all 3 values to the mean. I need to leave the 3 channels there. Its actually in this format as its an array of images. 50,640,480,3 Commented Sep 30, 2019 at 19:47
  • What would be the shape of the final output? Commented Sep 30, 2019 at 19:59
  • 50,640,480,3 the same as before but the ,3 which was originally [251,145,125] would become [174,174,174] Commented Sep 30, 2019 at 20:00

2 Answers 2

1

Use axis argument to do mean-reduction along last axis and then broadcast to the original shape with np.broadcast_to -

np.broadcast_to(images.mean(axis=-1,keepdims=True),images.shape)

That np.broadcast_to helps us on achieving memory efficiency by giving us original shaped view into the averaged array. If you need the final output with its own memory space, append with .copy() -

np.broadcast_to(images.mean(axis=-1,keepdims=True),images.shape).copy()

Alternatively, we can use np.repeat -

images.mean(axis=-1,keepdims=True).repeat(images.shape[-1],axis=-1)

The posted solutions work for ndarrays of generic dimensions. Hence, will work on one image or a set of images with the desired result of average along the last axis being broadcasted/replicated/repeated along the same.

Also, note that the final output would be of float dtype. So, we might want to convert or/and round to int for usual image-dtype of unsigned-int dtype output.

Sign up to request clarification or add additional context in comments.

1 Comment

This is exactly the result I wanted. Thank you very much for your answer. I think I need to do some reading up on this.
1

You need to average over the x and y axes. In your case the axes 1 and 2 (you can input it in numpy.mean as a tuple). Then if you have 50 images in the first dimension example you will get (50, 3) shaped array.

1 Comment

Thank you for the direction. I'm struggling to understand but with enough tinkering I will get there. I find working it out my self helps me grasp the concept better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.