Fitting of a sphere using SVD/LMS - image

I would like to fit a MR binary data of 281*398*104 matrix which is not a perfect sphere, and find out the center and radius of sphere and error also. I know LMS or SVD is a good choice to fit for sphere.
I have tried sphereFit from matlab file exchange but got an error,
>> sphereFit(data)
Warning: Matrix is singular to working precision.
> In sphereFit at 33
ans =
NaN NaN NaN
Would you let me know where is the problem, or any others solution?

If you want to use sphere fitting algorithm you should first extract the boundary points of the object you assume to be a sphere. The result should be represented by a N-by-3 array containing coordinates of the points. Then you can apply sphereFit function.
In order to obtain boundary point of a binary object, there are several methods. One method is to apply morphological erosion (you need the "imerode" function from the image processing toolbox) with small structuring element, then compute set difference between the two images, and finally use the "find" function to transform binary image into a coordinate array.
the idea is as follow:
dataIn = imerode(data, ones([3 3 3]));
bnd = data & ~data2;
inds = find(bnd);
[y, x, z] = ind2sub(size(data), inds); % be careful about x y order
points = [x y z];
sphere = sphereFitting(points);
By the way, the link you gave refers to circle fitting, I suppose you wanted to point to a sphere fitting submission?
regards,

Related

Calculate 3D distance based on change in intensity

I have three sections (top, mid, bot) of grayscale images (3D). In each section, I have a point with coordinates (x,y) and intensity values [0-255]. The distance between each section is 20 pixels.
I created an illustration to show how those images were generated using a microscope:
Illustration
Illustration (side view): red line is the object of interest. Blue stars represents the dots which are visible in top, mid, bot section. The (x,y) coordinates of these dots are known. The length of the object remains the same but it can rotate in space - 'out of focus' (illustration shows a rotating line at time point 5). At time point 1, the red line is resting (in 2D image: 2 dots with a distance equal to the length of the object).
I want to estimate the x,y,z-coordinate of the end points (represents as stars) by using the changes in intensity, the knowledge about the length of the object and the information in the sections I have. Any help would be appreciated.
Here is an example of images:
Bot section
Mid section
Top section
My 3D PSF data:
https://drive.google.com/file/d/1qoyhWtLDD2fUy2zThYUgkYM3vMXxNh64/view?usp=sharing
Attempt so far:
enter image description here
I guess the correct approach would be to record three images with slightly different z-coordinates for your bot and your top frame, then do a 3D-deconvolution (using Richardson-Lucy or whatever algorithm).
However, a more simple approach would be as I have outlined in my comment. If you use the data for a publication, I strongly recommend to emphasize that this is just an estimation and to include the steps how you have done it.
I'd suggest the following procedure:
Since I do not have your PSF-data, I fake some by estimating the PSF as a 3D-Gaussiamn. Of course, this is a strong simplification, but you should be able to get the idea behind it.
First, fit a Gaussian to the PSF along z:
[xg, yg, zg] = meshgrid(-32:32, -32:32, -32:32);
rg = sqrt(xg.^2+yg.^2);
psf = exp(-(rg/8).^2) .* exp(-(zg/16).^2);
% add some noise to make it a bit more realistic
psf = psf + randn(size(psf)) * 0.05;
% view psf:
%
subplot(1,3,1);
s = slice(xg,yg,zg, psf, 0,0,[]);
title('faked PSF');
for i=1:2
s(i).EdgeColor = 'none';
end
% data along z through PSF's center
z = reshape(psf(33,33,:),[65,1]);
subplot(1,3,2);
plot(-32:32, z);
title('PSF along z');
% Fit the data
% Generate a function for a gaussian distibution plus some background
gauss_d = #(x0, sigma, bg, x)exp(-1*((x-x0)/(sigma)).^2)+bg;
ft = fit ((-32:32)', z, gauss_d, ...
'Start', [0 16 0] ... % You may find proper start points by looking at your data
);
subplot(1,3,3);
plot(-32:32, z, '.');
hold on;
plot(-32:.1:32, feval(ft, -32:.1:32), 'r-');
title('fit to z-profile');
The function that relates the intensity I to the z-coordinate is
gauss_d = #(x0, sigma, bg, x)exp(-1*((x-x0)/(sigma)).^2)+bg;
You can re-arrange this formula for x. Due to the square root, there are two possibilities:
% now make a function that returns the z-coordinate from the intensity
% value:
zfromI = #(I)ft.sigma * sqrt(-1*log(I-ft.bg))+ft.x0;
zfromI2= #(I)ft.sigma * -sqrt(-1*log(I-ft.bg))+ft.x0;
Note that the PSF I have faked is normalized to have one as its maximum value. If your PSF data is not normalized, you can divide the data by its maximum.
Now, you can use zfromI or zfromI2 to get the z-coordinate for your intensity. Again, I should be normalized, that is the fraction of the intensity to the intensity of your reference spot:
zfromI(.7)
ans =
9.5469
>> zfromI2(.7)
ans =
-9.4644
Note that due to the random noise I have added, your results might look slightly different.

Matlab: Extract Image in polar representation from Cartesian

I m trying to compute an efficient way to transform an image in cartesian coordinates into a polar representation. I know some functions such as ImToPolar are doing it and it works perfectly but takes a considerable much time for big images, especially when they require to be processed back and forth.
Here´s my input image:
and then I generate a polar mesh using a cartesian mesh centered at 0 and the function cart2pol(). Finally, I plot my image using mesh(theta, r, Input).
And here´s what I obtain:
Its exactly the image I need and it´s the same as ImToPolar or maybe better.
Since MATLAB knows how to compute it, does anybody know how to extract a matrix in polar representation from this output? Or maybe a fast (like in fast fourier transform) way to compute a Polar transform (and inverse) on MATLAB?
pol2cart and meshgrid and interp2 are sufficient to create the result:
I=imread('http://i.stack.imgur.com/HYSyb.png');
[r, c,~] = size(I);
%rgb image can be converted to indexed image to prevent excessive copmutation for each color
[idx, mp] = rgb2ind(I,32);
% add offset to image coordinates
x = (1:c)-(c/2);
y = (1:r)-(r/2);
% create distination coordinates in polar form so value of image can be interpolated in those coordinates
% angle ranges from 0 to 2 * pi and radius assumed that ranges from 0 to 400
% linspace(0,2*pi, 200) leads to a stretched image try it!
[xp yp] = meshgrid(linspace(0,2*pi), linspace(0,400));
%translate coordinate from polar to image coordinates
[xx , yy] = pol2cart(xp,yp);
% interpolate pixel values for unknwon coordinates
out = interp2(x, y, idx, xx, yy);
% save the result to a file
imwrite(out, mp, 'result.png')

Vector decomposition in matlab

this is my situation: I have a 30x30 image and I want to calculate the radial and tangent component of the gradient of each point (pixel) along the straight line passing through the centre of the image (15,15) and the same (i,j) point.
[dx, dy] = gradient(img);
for i=1:30
for j=1:30
pt = [dx(i, j), dy(i,j)];
line = [i-15, j-15];
costh = dot(line, pt)/(norm(line)*norm(pt));
par(i,j) = norm(costh*line);
tang(i,j) = norm(sin(acos(costh))*line);
end
end
is this code correct?
I think there is a conceptual error in your code, I tried to get your results with a different approach, see how it compares to yours.
[dy, dx] = gradient(img);
I inverted x and y because the usual convention in matlab is to have the first dimension along the rows of a matrix while gradient does the opposite.
I created an array of the same size as img but with each pixel containing the angle of the vector from the center of the image to this point:
[I,J] = ind2sub(size(img), 1:numel(img));
theta=reshape(atan2d(I-ceil(size(img,1)/2), J-ceil(size(img,2)/2)), size(img))+180;
The function atan2d ensures that the 4 quadrants give distinct angle values.
Now the projection of the x and y components can be obtained with trigonometry:
par=dx.*sind(theta)+dy.*cosd(theta);
tang=dx.*cosd(theta)+dy.*sind(theta);
Note the use of the .* to achieve point-by-point multiplication, this is a big advantage of Matlab's matrix computations which saves you a loop.
Here's an example with a well-defined input image (no gradient along the rows and a constant gradient along the columns):
img=repmat(1:30, [30 1]);
The results:
subplot(1,2,1)
imagesc(par)
subplot(1,2,2)
imagesc(tang)
colorbar

Finding the area of a 2-D data set

I have a .txt file with about 100,000 points in the 2-D plane. When I plot the points, there is a clearly defined 2-D region (think of a 2-D disc that has been morphed a bit).
What is the easiest way to compute the area of this region? Any way of doing easily in Matlab?
I made a polygonal approximation by finding a bunch (like 40) points on the boundary of the region and computing the area of the polygonal region in Matlab, but I was wondering if there is another, less tedious method than finding 40 points on the boundary.
Consider this example:
%# random points
x = randn(300,1);
y = randn(300,1);
%# convex hull
dt = DelaunayTri(x,y);
k = convexHull(dt);
%# area of convex hull
ar = polyarea(dt.X(k,1),dt.X(k,2))
%# plot
plot(dt.X(:,1), dt.X(:,2), '.'), hold on
fill(dt.X(k,1),dt.X(k,2), 'r', 'facealpha', 0.2);
hold off
title( sprintf('area = %g',ar) )
There is a short screencast By Doug Hull which solves this exact problem.
EDIT:
I am posting a second answer inspired by the solution proposed by #Jean-FrançoisCorbett.
First I create random data, and using the interactive brush tool, I remove some points to make it look like the desired "kidney" shape...
To have a baseline to compare against, we can manually trace the enclosing region using the IMFREEHAND function (I'm doing this using my laptop's touchpad, so not the most accurate drawing!). Then we find the area of this polygon using POLYAREA. Just like my previous answer, I compute the convex hull as well:
Now, and based on a previous SO question I had answered (2D histogram), the idea is to lay a grid over the data. The choice of the grid resolution is very important, mine was numBins = [20 30]; for the data used.
Next we count the number of squares containing enough points (I used at least 1 point as threshold, but you could try a higher value). Finally we multiply this count by the area of one grid square to obtain the approximated total area.
%### DATA ###
%# some random data
X = randn(100000,1)*1;
Y = randn(100000,1)*2;
%# HACK: remove some point to make data look like a kidney
idx = (X<-1 & -4<Y & Y<4 ); X(idx) = []; Y(idx) = [];
%# or use the brush tool
%#brush on
%### imfreehand ###
figure
line('XData',X, 'YData',Y, 'LineStyle','none', ...
'Color','b', 'Marker','.', 'MarkerSize',1);
daspect([1 1 1])
hROI = imfreehand('Closed',true);
pos = getPosition(hROI); %# pos = wait(hROI);
delete(hROI)
%# total area
ar1 = polyarea(pos(:,1), pos(:,2));
%# plot
hold on, plot(pos(:,1), pos(:,2), 'Color','m', 'LineWidth',2)
title('Freehand')
%### 2D histogram ###
%# center of bins
numBins = [20 30];
xbins = linspace(min(X), max(X), numBins(1));
ybins = linspace(min(Y), max(Y), numBins(2));
%# map X/Y values to bin-indices
Xi = round( interp1(xbins, 1:numBins(1), X, 'linear', 'extrap') );
Yi = round( interp1(ybins, 1:numBins(2), Y, 'linear', 'extrap') );
%# limit indices to the range [1,numBins]
Xi = max( min(Xi,numBins(1)), 1);
Yi = max( min(Yi,numBins(2)), 1);
%# count number of elements in each bin
H = accumarray([Yi(:), Xi(:)], 1, [numBins(2) numBins(1)]);
%# total area
THRESH = 0;
sqNum = sum(H(:)>THRESH);
sqArea = (xbins(2)-xbins(1)) * (ybins(2)-ybins(1));
ar2 = sqNum*sqArea;
%# plot 2D histogram/thresholded_histogram
figure, imagesc(xbins, ybins, H)
axis on, axis image, colormap hot; colorbar; %#caxis([0 500])
title( sprintf('2D Histogram, bins=[%d %d]',numBins) )
figure, imagesc(xbins, ybins, H>THRESH)
axis on, axis image, colormap gray
title( sprintf('H > %d',THRESH) )
%### convex hull ###
dt = DelaunayTri(X,Y);
k = convexHull(dt);
%# total area
ar3 = polyarea(dt.X(k,1), dt.X(k,2));
%# plot
figure, plot(X, Y, 'b.', 'MarkerSize',1), daspect([1 1 1])
hold on, fill(dt.X(k,1),dt.X(k,2), 'r', 'facealpha',0.2); hold off
title('Convex Hull')
%### plot ###
figure, hold on
%# plot histogram
imagesc(xbins, ybins, H>=1)
axis on, axis image, colormap gray
%# plot grid lines
xoff = diff(xbins(1:2))/2; yoff = diff(ybins(1:2))/2;
xv1 = repmat(xbins+xoff,[2 1]); xv1(end+1,:) = NaN;
yv1 = repmat([ybins(1)-yoff;ybins(end)+yoff;NaN],[1 size(xv1,2)]);
yv2 = repmat(ybins+yoff,[2 1]); yv2(end+1,:) = NaN;
xv2 = repmat([xbins(1)-xoff;xbins(end)+xoff;NaN],[1 size(yv2,2)]);
xgrid = [xv1(:);NaN;xv2(:)]; ygrid = [yv1(:);NaN;yv2(:)];
line(xgrid, ygrid, 'Color',[0.8 0.8 0.8], 'HandleVisibility','off')
%# plot points
h(1) = line('XData',X, 'YData',Y, 'LineStyle','none', ...
'Color','b', 'Marker','.', 'MarkerSize',1);
%# plot convex hull
h(2) = patch('XData',dt.X(k,1), 'YData',dt.X(k,2), ...
'LineWidth',2, 'LineStyle','-', ...
'EdgeColor','r', 'FaceColor','r', 'FaceAlpha',0.5);
%# plot freehand polygon
h(3) = plot(pos(:,1), pos(:,2), 'g-', 'LineWidth',2);
%# compare results
title(sprintf('area_{freehand} = %g, area_{grid} = %g, area_{convex} = %g', ...
ar1,ar2,ar3))
legend(h, {'Points' 'Convex Jull','FreeHand'})
hold off
Here is the final result of all three methods overlayed, with the area approximations displayed:
My answer is the simplest and perhaps the least elegant and precise. But first, a comment on previous answers:
Since your shape is usually kidney-shaped (not convex), calculating the area of its convex hull won't do, and an alternative is to determine its concave hull (see e.g. http://www.concavehull.com/home.php?main_menu=1) and calculate the area of that. But determining a concave hull is far more difficult than a convex hull. Plus, straggler points will cause trouble in both he convex and concave hull.
Delaunay triangulation followed by pruning, as suggested in #Ed Staub's answer, may a bit be more straightforward.
My own suggestion is this: How precise does your surface area calculation have to be? My guess is, not very. With either concave hull or pruned Delaunay triangulation, you'll have to make an arbitrary choice anyway as to where the "boundary" of your shape is (the edge isn't knife-sharp, and I see there are some straggler points sprinkled around it).
Therefore a simpler algorithm may be just as good for your application.
Divide your image in an orthogonal grid. Loop through all grid "pixels" or squares; if a given square contains at least one point (or perhaps two points?), mark the square as full, else empty. Finally, add the area of all full squares. Bingo.
The only parameter is the resolution length (size of the squares). Its value should be set to something similar to the pruning length in the case of Delaunay triangulation, i.e. "points within my shape are closer to each other than this length, and points further apart than this length should be ignored".
Perhaps an additional parameter is the number of points threshold for a square to be considered full. Maybe 2 would be good to ignore straggler points, but that may define the main shape a bit too tightly for your taste... Try both 1 and 2, and perhaps take an average of both. Or, use 1 and prune away the squares that have no neighbours (game-of-life-style). Simlarly, empty squares whose 8 neighbours are full should be considered full, to avoid holes in the middle of the shape.
There is no end to how much this algorithm can be refined, but due to the arbitrariness intrinsic to the problem definition in your particular application, any refinement is probably the algorithm equivalent of "polishing a turd".
I know next to nothing, so don't put much stock in this... consider doing a Delaunay triangulation. Then remove any hull (outer) edges longer than some maximum. Repeat until nothing to remove. Fill the remaining triangles.
This will orphan some outlier points.
I suggest using a space-filling-curve, for example a z-curve or better a moore curve. A sfc fills the full space and is good to index each points. For example for all f(x)=y you can sort the points of the curve in ascendending order and from that result you take as many points until you get a full roundtrip. These points you can then use to compute the area. Because you have many points maybe you want to use less points and use a cluster which make the result less accurate.
I think you can get the border points using convex hull algorithm with restriction to the edge length (you should sort points by vertical axis). Thus it will follow nonconvexity of your region. I propose length round 0.02. In any case you can experiment a bit with different lengths drawing the result and examining it visually.

MatLab - Best way of finding the closest value

I'm working with Matlab's image toolbox. In particular, after binarizing and labeling an image, I run
props = regionprops(labeledImage, 'Centroid');
to get the centroid of all the connected objects. Now, I would like to find the one closer to a pair of coordinates (namely the center of the image). Of course I know I could use a for loop checking each props[i].Centroid pair of coordinates, but that's slow and there must be a matlaby way of doing it...
which is...?
Thanks in advance
The output from REGIONPROPS will be an N-by-1 structure array with one field 'Centroid' that contains a 1-by-2 array. You can first concatenate all these arrays into an N-by-2 array using the function VERTCAT. Then you can replicate your image center coordinates (assumed to be in a 1-by-2 array) using the function REPMAT so that it becomes an N-by-2 array. Now you can compute the distances using vectorized operations and find the index of the value with the minimum distance using the function MIN:
props = regionprops(labeledImage, 'Centroid');
centers = vertcat(props.Centroid); %# Vertically concatenate the centroids
imageCenter = [x y]; %# Your image center coordinates
origin = repmat(imageCenter,numel(props),1); %# Replicate the coordinates
squaredDistance = sum(abs(centers-origin).^2,2); %# Compute the squared distance
[~,minIndex] = min(squaredDistance); %# Find index of the minimum
Note that since you just want the minimum distance, you can just use the squared distances and avoid a needless call to SQRT. Also note that the function BSXFUN could be used as an alternative to replicating the image center coordinates to subtract them from the object centroids.

Resources