measure valley width 2d, matlab - matlab

I have a 2d image, I have locations where local minimas occurs.
I want to measure the width of the valleys "leading" to those minimas.
I need either the radii of the circles or ellipses fitted to these valley.
An example attached here, dark red lines on the peaks contours is what I wish to find.
Thanks.

I am partially extending the answer of #Lucas.
Given a threshold t I would consider the points P_m that are below t and closer to a certain point m of minimum of your f (given a characteristic scale length r).
(You said your data are noisy; to distinguish minima and talk about wells, you need to estimate such r. In your example it can be for instance r=4, i.e. half the distance between the minima).
Then you have to consider a metric for each well region P_m, say for example
metric(P_m) = .5 * mean{ maximum vertical diameter of P_m ,
maximum horizontal diameter of P_m}.
In your picture metric(P_m) = 2 for both wells.
On the whole, in terms of pseudo-code you may consider
M := set of local minima of f
for_each(minimum m in M){
P_m += {p : d(p,m) < r and f(r)<t} % say that += is the push operation in a Stack
}
radius_of_region_around(m) = metric(P_m); %

I would suggest making a list of points that describe the values at the edge of your ellipse, perhaps by finding all the points where it crosses a threshold.
above = data > threshold
apply a simple edge detector
edges = EdgeDetector(above)
find coordinates of edges
[row,col] = find(edges)
Then apply this ellipse fitter http://www.mathworks.com/matlabcentral/fileexchange/3215-fitellipse

I'm assuming here you have access to the x, y and z data and are not processing a given JPG (or so) image. Then, you can use the function contourc to your advantage:
% plot some example function
figure(1), clf, hold on
[x,y,z] = peaks;
surf(x,y,z+10,'edgecolor', 'none')
grid on, view(44,24)
% generate contour matrix. The last entry is a 2-element vector, the last
% element of which is to ensure the right algorithm gets called (so leave
% it untouched), and the first element is your threshold.
C = contourc(x(1,:), y(:,1), z, [-4 max(z(:))+1]);
% plot the selected points
plot(C(1,2:end), C(2,2:end), 'r.')
Then use this superfast ellipse fitting tool to fit an ellipse through those points and find all the parameters of the ellipse you desire.
I suggest you read help contourc and doc contourc to find out why the above works, and what else you can use it for.

Related

How to Plot lines on image by 45 degrees from centroid. I have fitted a bounding box on image and found centroid

I have fitted a bounding box on image which have concerned area is human silhouette in BW, and found centroid according to concerned human silhouette?
now i have to plot red line by 45 degree angle from centroid.
from centroid to vertical, horizental and diagonal logic? Need code in MATLAB?
I have fitted a bounding box on image and found centroid according to concerned human silhouette?
% bounding box
labeledImage = bwlabel(Ibw);
blobMeasurements = regionprops(labeledImage, 'BoundingBox');
thisBlobsBoundingBox = blobMeasurements.BoundingBox;
subImage = imcrop(Ibw, thisBlobsBoundingBox);
figure, imshow(subImage);
imwrite(subImage,fullfile(cd, strcat('Croped By BoundingBox','.png')));
%centroid
Ibw = imread('Croped By BoundingBox.png');
Ibw = imfill(Ibw,'holes');
Ilabel = bwlabel(Ibw);
stat = regionprops(Ilabel,'centroid');
imshow(Ibw),hold on;
for x = 1: numel(stat)
plot(stat(x).Centroid(1),stat(x).Centroid(2),'ro');
[rows, cols] =ndgrid(1:size(Ibw, 1), 1:size(Ibw, 2));
centroidrowcol = mean([rows(:) .* Ibw(:), cols(:) .* Ibw(:)]);
hold on
end
figure, imshow(Ibw);
imwrite(Ibw,fullfile(cd, strcat('Centroid','.png')));
plot lines from centroid to vercally horizentally and diagonally by 45 degree from centroid.
i have to obtaon these results
enter image description here
I'll start with assuming centroid, a length-2 vector, is the coordinates of a centroid -- since you already have them.
As a reminder, 45 degree lines centered at (0,0) are the images of the functions f(x)=x and f(x)=-x. In order to shift the lines to intercept points of your choice, say (x0, y0), you need f(x-x0)+y0. In other words, f(x)=x-x0+y0 and f(x)=-x+x0+y0 respectively.
Knowing the functions (whose images are) the lines of your desire, there are a number of things you can do in order to complete the task. You can define Matlab functions as such and plot the usual way with plot, or for a quick display, with ezplot:
ezplot(#(x)x-centroid(1)+centroid(2));
line() in Matlab allows you to draw a line segment between two points in 2D, among other things. With line(), you actually don't have to know the equations explicitly. You just need two points. So, one possibility is that you use [centroid(1)+1, centroid(2)+1] as your first point and [centroid(1)-1, centroid(2)-1] as your second point for the shifted f(x)=x line.
Just read the documentation for the correct syntax. In the above example, you would put in
line([centroid(1)+1;centroid(1)-1], [centroid(2)+1;centroid(2)-1]);
This draws a 45 degree line segment alright. You also want the length of the line segment to be visually sensible. You can either autoscale the length, ie. change the 1 into a formula, based on the size of your image. OR, you can make sure your segment is longer than the extent of the image but confine your plot to a certain size by changing xlim and ylim.

MATLAB: Area and centre of mass of a plotted figure

I have made a function that allows a user to draw several points and interpolate those points. I want the function to calculate the centre of mass using this vector :
I think I should therefore first calculate the area of the figure (I drew this example to illustrate the function output). I want to do this using Green's theorem
However since I'm quite a beginner in MATLAB I'm stuck at how to implement this formula in order to find the centre of mass. I'm also not sure how to get the data as my output so far is only the x- and y cordinates of the points.
function draw
fig = figure();
hax = axes('Parent', fig);
axis(hax, 'manual')
[x,y] = getpts();
M = [x y]
T = cumsum(sqrt([0,diff(x')].^2 + [0,diff(y')].^2));
T_i = linspace(T(1),T(end),1000);
X_i = interp1(T,x',T_i,'cubic');
Y_i = interp1(T,y',T_i,'cubic');
plot(x,y,'b.',X_i,Y_i,'r-')
end
The Center Of Mass for a 2D coordinate system should just be the mean of the interpolated x-coordinates and y-coordinates. The Interpolation should give you evenly spaced coordinates which you can use to your advantage. So simply add to your existing function:
CenterOfMass= [mean(X_i),mean(Y_i)]
plot(x,y,'b.',X_i,Y_i,'r-')
hold on
plot(CenterOfMass(1),CenterOfMass(2),'ro')
should give you the center of mass assuming that all points are weighted equally.

Expected number of points in a cubic volume given a GMM

I have a 3D space which I discretized in voxels (cubes of volume). I also have a set of 3D points in such space. I want to know the expected number of points in a given voxel. I chose GMM as a model for this purpose, but I do not know how to calculate what I want starting from mu, sigma and weight of each Gaussian.
So far I managed to fit the GMM (easy):
obj = gmdistribution.fit(points', 20);
and I to plot it via
figure(1);
hold on;
for i = 1:k
plot_gaussian_ellipsoid(obj.mu(i,:), obj.Sigma(:,:,i));
end
axis equal;
which results in what I expect, that is a map where the colors tell me the concentration of points.
The question is, how can I extract the expected number of points in a voxel, given its center (x,y,z) and its side s?
You can use (see example here http://www.mathworks.nl/help/stats/gmdistribution.cluster.html)
idx = cluster(gm,points);

Image processing and moments

In a project I'm currently working on I have to calculate the 5 moments of the contour of an image. Which I can then for example use to get the centroid. To do this I used matlab :
f = imread(Is);
%Edge detection with prewitt
contourImage = edge(f,'prewitt');
% Morphological operation to close the open spaces
se = strel('disk',2);
closecontourImage = imclose(contourImage,se);
imshow(closecontourImage);
%Find the x y positions of all the nonzero elements of the edge
[row,col] = find(closecontourImage);
% 3 moments
m10= 0;
m00= 0;
m01= 0;
mu00 =0;
% Calculate the 3 moments based on the given paper
for r=1:length(row)
for c=1:length(col)
m10 = m10 + ((row(r)^1)*(col(c)^0));
m00 = m00 + ((row(r)^0)*(col(c)^0));
m01 = m01 + ((row(r)^0)*(col(c)^1));
end
end
% Calculate centroid (zwaartepunt) based on the given formulas
x = m10/m00;
y= m01/m00;
Original image (in png, i use pgm in matlab):
The edge (which I assume is the contour):
The plot with the Image and the centroid
When I compare this to matlabs built in centroid calculation it is pretty close.
Though my problem is concerning the area calculation. I read that the 0th moment = area. though my m00 is not the same as the area. Which is logical because the 0th moment is a summation of all the white pixels ... which only represent the edge of the image, therefore this couldn't result in the area. My question is now , is there a difference in contour moments and moments on the entire image ? And is it possible to get the area based on the contour in this representation ?
In my assignment they explicitly say that the moments of the contour should be calculated and that the 1ste moment is equal to the centroid (which is also not the case in my algorithm). But what I read here is that the 1st order central moment = the centroid. So does this mean that the contour moments are the same as the central moments ? And a more general question, can i use this edge as a contour ?
I find these moments very confusing
There is a difference between moments of filled area or its contour. Think about the following case:
The contour is the exactly the same for both of these objects. Nevertheless, it is obvious that the center of weight in the right square is biased to the right, since it is "more full to the right".

Detecting center point of cross using Matlab

Hello, I have an image as shown above. Is it possible for me to detect the center point of the cross and output the result using Matlab? Thanks.
Here you go. I'm assuming that you have the image toolbox because if you don't then you probably shouldn't be trying to do this sort of thing. However, all of these functions can be implemented with convolutions I believe. I did this process on the image you presented above and obtained the point (139,286) where 138 is the row and 268 is the column.
1.Convert the image to a binary image:
bw = bw2im(img, .25);
where img is the original image. Depending on the image you might have to adjust the second parameters (which ranges from 0 to 1) so that you only get the cross. Don't worry about the cross not being fully connected because we'll remedy that in the next step.
2.Dilate the image to join the parts. I had to do this twice because I had to set the threshold so low on the binary image conversion (some parts of your image were pretty dark). Dilation essentially just adds pixels around existing white pixels (I'll also be inverting the binary image as I send it into bwmorph because the operations are made to act on white pixels which are the ones that have a value of 1).
bw2 = bwmorph(~bw, 'dilate', 2);
The last parameter says how many times to do the dilation operation.
3.Shrink the image to a point.
bw3 = bwmorph(bw2, 'shrink',Inf);
Again, the last parameter says how many times to perform the operation. In this case I put in Inf which shrinks until there is only one pixel that is white (in other words a 1).
4.Find the pixel that is still a 1.
[i,j] = find(bw3);
Here, i is the row and j is the column of the pixel in bw3 such that bw3(i,j) is equal to 1. All the other pixels should be 0 in bw3.
There might be other ways to do this with bwmorph, but I think that this way works pretty well. You might have to adjust it depending on the picture too. I can include images of each step if desired.
I just encountered the same kind of problem, and I found other solutions that I would like to share:
Assume image file name is pict1.jpg.
1.Read input image, crop relevant part and covert to Gray-scale:
origI = imread('pict1.jpg'); %Read input image
I = origI(32:304, 83:532, :); %Crop relevant part
I = im2double(rgb2gray(I)); %Covert to Grayscale and to double (set pixel range [0, 1]).
2.Convert image to binary image in robust approach:
%Subtract from each pixel the median of its 21x21 neighbors
%Emphasize pixels that are deviated from surrounding neighbors
medD = abs(I - medfilt2(I, [21, 21], 'symmetric'));
%Set threshold to 5 sigma of medD
thresh = std2(medD(:))*5;
%Convert image to binary image using above threshold
BW = im2bw(medD, thresh);
BW Image:
3.Now I suggest two approaches for finding the center:
Find find centroid (find center of mass of the white cluster)
Find two lines using Hough transform, and find the intersection point
Both solutions return sub-pixel result.
3.1.Find cross center using regionprops (find centroid):
%Find centroid of the cross (centroid of the cluster)
s = regionprops(BW, 'centroid');
centroids = cat(1, s.Centroid);
figure;imshow(BW);
hold on, plot(centroids(:,1), centroids(:,2), 'b*', 'MarkerSize', 15), hold off
%Display cross center in original image
figure;imshow(origI), hold on, plot(82+centroids(:,1), 31+centroids(:,2), 'b*', 'MarkerSize', 15), hold off
Centroid result (BW image):
Centroid result (original image):
3.2 Find cross center by intersection of two lines (using Hough transform):
%Create the Hough transform using the binary image.
[H,T,R] = hough(BW);
%ind peaks in the Hough transform of the image.
P = houghpeaks(H,2,'threshold',ceil(0.3*max(H(:))));
x = T(P(:,2)); y = R(P(:,1));
%Find lines and plot them.
lines = houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
figure, imshow(BW), hold on
L = cell(1, length(lines));
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green');
% Plot beginnings and ends of lines
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');
%http://robotics.stanford.edu/~birch/projective/node4.html
%Find lines in homogeneous coordinates (using cross product):
L{k} = cross([xy(1,1); xy(1,2); 1], [xy(2,1); xy(2,2); 1]);
end
%https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
%Lines intersection in homogeneous coordinates (using cross product):
p = cross(L{1}, L{2});
%Convert from homogeneous coordinate to euclidean coordinate (divide by last element).
p = p./p(end);
plot(p(1), p(2), 'x', 'LineWidth', 1, 'Color', 'white', 'MarkerSize', 15)
Hough transform result:
I think that there is a far simpler way of solving this. The lines which form the cross-hair are of equal length. Therefore it in will be symmetric in all orientations. So if we do a simple line scan horizontally as well as vertically, to find the extremities of the lines forming the cross-hair. the median of these values will give the x and y co-ordinates of the center. Simple geometry.
I just love these discussions of how to find something without defining first what that something is! But, if I had to guess, I’d suggest the center of mass of the original gray scale image.
What about this;
a) convert to binary just to make the algorithm faster.
b) Perform a find on the resulting array
c) choose the element which has either lowest/highest row/column index (you would have four points to choose from then
d) now keep searching neighbours
have a global criteria for search that if search does not result in more than a few iterations, the point selected is false and choose another extreme point
e) going along the neighbouring points, you will end up at a point where you have three possible neighbours.That is you intersection
I would start by using the grayscale image map. The darkest points are on the cross, so discriminating on the highest values is a starting point. After discrimination, set all the lower points to white and leave the rest as they are. This would maximize the contrast between points on the cross and points in the image. Next up is to come up with a filter for determining the position with the highest average values. I would step through the entire image with a NxM array and take the mean value at the center point. Create a new array of these means and you should have the highest mean at the intersection. I'm curious to see how someone else may try this!