Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to calculate radial average of the image with python?

I have a square image, for example this one:

Scipy coin demo image

and I would like to calculate the 1D average of the image for each radius from the position (0,0). I have written some code to do so, but first of all it very slow even for small images, secondly I see that there are also some problems with the idea behind it. Code is here:

import matplotlib.pyplot as plt
import numpy as np
import collections
from skimage import data

image = data.coins()
image = image[:,0:303]
print(image.shape)

projection = {}
total_count = {}

for x_i,x in enumerate(image):
    for y_i,y in enumerate(x):
        if round(np.sqrt(x_i**2+y_i**2),1) not in projection:
            projection[round(np.sqrt(x_i**2+y_i**2),1)] = y
            total_count[round(np.sqrt(x_i**2+y_i**2),1)] = 1
        elif np.sqrt(round(np.sqrt(x_i**2+y_i**2),1)) in projection:
            projection[round(np.sqrt(x_i**2+y_i**2),1)] += y
            total_count[round(np.sqrt(x_i ** 2 + y_i ** 2), 1)] += 1

od = collections.OrderedDict(sorted(projection.items()))
x, y = [],[]

for k, v in od.items():
    x.append(k)
    y.append(v/total_count[k])

plt.plot(x,y)
plt.xlabel('Radius from (0,0)')
plt.ylabel('Averaged pixel value')
plt.show()

The result of the code looks like this:

Result of radius average of picture

Has anyone have some clue how to improve my the script? I also don't know why in some cases there are some spikes which have very small average value. I would really appreciate some hints. Thanks!

like image 351
Dawid Avatar asked Nov 14 '25 10:11

Dawid


2 Answers

You may filter the image by the radius by creating a matrix of radii R and calculating

image[(R >= r-.5) & (R < r+.5)].mean()

where r is the radius you are interested in.

enter image description here

import numpy as np
import matplotlib.pyplot as plt
from skimage import data

# get some image
image = data.coins()
image = image[:,0:303]

# create array of radii
x,y = np.meshgrid(np.arange(image.shape[1]),np.arange(image.shape[0]))
R = np.sqrt(x**2+y**2)

# calculate the mean
f = lambda r : image[(R >= r-.5) & (R < r+.5)].mean()
r  = np.linspace(1,302,num=302)
mean = np.vectorize(f)(r)

# plot it
fig,ax=plt.subplots()
ax.plot(r,mean)
plt.show()

enter image description here

like image 124
ImportanceOfBeingErnest Avatar answered Nov 17 '25 09:11

ImportanceOfBeingErnest


I have found also another, very elegant way of doing radial average posted by @Bi Rico here:

def radial_profile(data, center):
    y, x = np.indices((data.shape))
    r = np.sqrt((x - center[0])**2 + (y - center[1])**2)
    r = r.astype(np.int)

    tbin = np.bincount(r.ravel(), data.ravel())
    nr = np.bincount(r.ravel())
    radialprofile = tbin / nr
    return radialprofile

It works quite well and what is most important is much more efficient than previously posted suggestions.

like image 24
Dawid Avatar answered Nov 17 '25 08:11

Dawid



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!