Help with getting data from image at equidistant positions from the centre - to include the "off circle corners"
5 views (last 30 days)
Show older comments
Hello, I have an image and I want to get the median of data at each radius value. This is shown by the yellow circles - so each circle (take the median of all pixels on it).

However, in my attemy, I missing all the corners of data that are actually at a larger radius than the image size, but not full circles. Any suggestions how to include this data.
This was my attempt:
% 1st draw circle of radius R on the flog2 plot
theta = linspace(0,360); %use n=121 for every 3 degrees (reduce from every degree for speed
centre = [cx,cy]; %circle centre
% I= Image
[X,Y]=ndgrid(1:size(I,1),1:size(I,2));
X=X-cx;Y=Y-cy;%shift coordinate grid
hold(ax1,"on");
data=[];
for i=1:cy-1
radius=i; %circle radius
data(i,1)=i;
y = radius*sind(theta)+centre(2);
x = radius*cosd(theta)+centre(1);
%Get Data on radius
L=sqrt(X.^2+Y.^2)==radius;
data(i,2) = median(I(L));
if mod(i,5)==0
plot(ax1,x,y,'y'); %draw circle
end
% Now use interp so use all pixels on circle. This is
% actually what I finally use now
[xx,yy]=pol2cart(theta,radius); % this is for the interp2 approach
x=xx+cx; y=yy+cy;
vals=median(interp2(I,x,y));
data(i,3)=vals;
end
% Now plot data
hold(ax2,"on");
plot(ax2,data(:,1),data(:,3),'y-','LineWidth',3);
0 Comments
Accepted Answer
Matt J
on 6 Apr 2025
Edited: Matt J
on 7 Apr 2025
[M,N]=size(yourImage);
c=[M+1,N+1]/2; %image center
rho=hypot((1:M)'-c(1), (1:N)-c(2));
G=discretize(rho,0:2:norm([M,N]/2+2) );
Medians=splitapply(@median, yourImage(:),G(:));
14 Comments
Matt J
on 7 Apr 2025
You can also overlay the annuli boundaries to get more visual information about the pixel memberships
plotG(11,11,1)
plotG(12,12,1)
function plotG(M,N,d)
c=[M+1,N+1]/2; %image center
rho=hypot((1:M)'-c(1), (1:N)-c(2));
R=0:d:norm([M,N])/2+d;
G=discretize(rho, R);
imagesc(G); colormap(1-gray(256)); axis equal; hold on
viscircles(repmat(c,numel(R),1), R(:) ); hold off
end
More Answers (2)
Image Analyst
on 6 Apr 2025
@Jason, ok try this - it may be a little more intuitive:
grayImage = imread('cameraman.tif');
[rows, columns, numColorChannels] = size(grayImage);
figure('Name', 'Demo by Image Analyst', 'NumberTitle', 'off')
subplot(2, 1, 1);
imshow(grayImage);
axis('on', 'image');
X = 1 : columns;
Y = 1 : rows;
centerX = columns / 2;
centerY = rows / 2;
[x, y] = meshgrid(X, Y);
radii = sqrt((x - centerX) .^ 2 + (y - centerY) .^ 2);
fprintf('There are %d unique radii in this image.\n', numel(unique(radii)))
% Find out how many histogram bins we'll need to be about every pixel.
maxDistance = max(radii(:))
% So the min distance is 0 and the max distance is maxDistance.
% Let's divide this up into numRings "zones".
numRings = 10; % Whatever you want for the thickness of the rings/zones.
zoneBoundaries = linspace(0, maxDistance, numRings);
% Show the lines separating each ring (zone);
centers = repmat([centerX, centerY], numRings, 1);
viscircles(centers, zoneBoundaries);
% For each ring, get a mask and get the median of the pixel values in the mask.
for k = 1 : numRings-1
innerRadius = zoneBoundaries(k);
outerRadius = zoneBoundaries(k+1);
mask = (radii >= innerRadius) & (radii < outerRadius);
medianValues(k) = median(grayImage(mask));
fprintf('The median pixel value between distance %.1f and %.1f is %d gray levels.\n',...
innerRadius, outerRadius, medianValues(k))
end
% Plot medians
subplot(2, 1, 2);
plot(zoneBoundaries(1:end-1), medianValues, 'b.-', 'LineWidth', 2, 'MarkerSize', 25);
grid on;
title('Median Value as a Function of Radius.')
ylabel('Median Value')
xlabel('Radius')
3 Comments
Image Analyst
on 8 Apr 2025
- The function viscircles is the one that overlays circles over an image. There are lots of options so check it out.
- To have the boundaries be exactly one pixel apart, you'd set the number of rings to the max distance. Keep in mind though that the distances are floating point, factional distances, except for distance purely vertical or horizontal (or a very few other special cases). Even though the pixel centers lie on integer grid coordinates, their distance is not in general going to be an integer.
- If you're using median, it doesn't really make sense to do an interpolation, does it? Think about it. And if you did, how many points would you interpolate in between? See attached interpolation demos but I don't recommend you interpolate. What is your end goal anyway? Why are you using a non-linear metric like median instead of a linear one like mean? And interpolation would be mixing computations of nonlinear and linear measurements. If you don't have enough pixels in any of the rings, I suggest you just widen the rings. If you wanted, you could smooth the final profile afterwards. I think we need to think about what is the real world physical reason why you want this measurement and if going to subpixel resolution is really needed or would change anything.
- To do a subset of rings, you'd simply use indexing to pick out every , say, tenth one: viscircles(centers(1:10:end, :), zoneBoundaries(1:10:end));
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!