I need to optimize this part of an image processing application.
It is basically the sum of the pixels binned by their distance from the central spot.
d
Taken from a numpy Enhancement Proposal I am working on:
pp.plot(*group_by(np.round(R, 5).flatten()).mean(data.flatten()))
The call to mean returns the unique values in R, and the mean of corresponding values in data over identical values in R.
So not quite the same as a histogram based solution; you don't have to remap to a new grid, which is nice if you want to fit a radial profile, without loss of information. Performance should be slightly better than your original solution. Also, standard deviations can be computed with the same efficiency.
Here is my latest draft numpy group_by EP; not a very concise answer as such, but a very general one. I hope we can all agree numpy needs something like np.group_by(keys).reduce(values); if you have any feedback, it would be welcome.
There is a function in PyDIP that does just this: dip.RadialMean. You can use it in a similar way to OP's radial_profile
function:
import PyDIP as dip
img = dip.ImageReadTIFF('crop.tif')
# center, radi = find_centroid(img)
center, radi = (509, 546), 55
rad = dip.RadialMean(img, binSize=1, center=center)
rad[radi:].Show()
Disclaimer: I'm an author of PyDIP and the DIPlib library.
You can use numpy.histogram to add up all the pixels that appear in a given "ring" (range of values of r from the origin). Each ring is one of the histogram bins. You choose the number of bins depending on how wide you want the rings to be. (Here I found 3 pixel wide rings work well to make the plot not too noisy.)
def radial_profile(data, center):
y,x = np.indices((data.shape)) # first determine radii of all pixels
r = np.sqrt((x-center[0])**2+(y-center[1])**2)
# radius of the image.
r_max = np.max(r)
ring_brightness, radius = np.histogram(r, weights=data, bins=r_max/3)
plt.plot(radius[1:], ring_brightness)
plt.show()
(By the way, if this really needs to be efficient, and there are a lot of images the same size, then everything before the call to np.histogram can be precomputed.)
It looks like you could use numpy.bincount here:
import numpy as np
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