Selecting an ellipse as a region of interest (ROI) - matlab

I used imellipse to select an ellipse as my region of interest (ROI). The issue is that the ellipse I want to select is of around 45 degrees, and, when I use imellipse, it seems it is 90 degrees either horizontally or vertically.
How can I change the orientation of the ellipse?
Thanks.

You need to rotate the coordinates of an ellipse. Like this:
npts = 1e4;
t = linspace(0,2*pi,npts);
theta = pi/4;
aspect = [5 1]; % [x y]
x = aspect(1)*sin(t+theta);
y = aspect(2)*cos(t);
plot(x, y);
If you want to use imellipse to draw the ellipse on an image, you can extract the vertices and transform them:
figure, imshow('pout.tif');
h = imellipse;
exy = h.getVertices
theta = pi/12;
M = [cos(theta), sin(theta); -sin(theta), cos(theta)]
exy_centered = bsxfun(#minus,exy,mean(exy))
exyRot = bsxfun(#plus,exy_centered*M,mean(exy));
hold on
plot(exyRot(:,1),exyRot(:,2),'r') % orig: plot(exy(:,1),exy(:,2),'r')
To fill in the ellipse, creating a mask, use roifill or roipoly:
w=getfield(imfinfo('pout.tif'),'Width');
h=getfield(imfinfo('pout.tif'),'Height');
bw = roipoly(zeros(h,w),exyRot(:,1),exyRot(:,2));

Related

How to get the x,y coordinates to extrude an image

I am trying to detect the edges of an image (2D image) and extrude the edges of an image (3D image). I can simply extrude a random x,y coordinates using
x = randi(100,1,5);
y = randi(100,1,5);
x = x([1:end 1]);
y = y([1:end 1]);
bw = poly2mask(x,y,100,100);
figure;
subplot(121);
plot(x,y)
[xg,yg] = meshgrid(1:100);
zg = bw * 2;
subplot(122);
surfl(xg,yg,zg)
I can also get the x,y values of the coordinates from the pixel image using the following coordinates
A=double(imread('F:\01.jpg'));
imshow(A)
[height, width] = size(A)
[x, y] = meshgrid(1:width, 1:height);
But I am unable to use this x,y values as the input x,y values for extrusion. Please help me. Thanks in advance.

Area between circular curves

I'm trying to calculate the surface between two circular curves (yellow surface in this picture as simplification) but I'm somehow stuck since I don't have datapoints at the same angular values of the two curves. Any ideas?
Thanks for your help!
Picture:
I assume you have the x,y coordinates which you used to the plot. I obtained them here using imfreehand. I used inpolygon to generate a binary mask for each curve and then apply xor on them to get a mask of the desired area:
% x,y were obtained using imfreehand on 100x100 image and getPosition()
x = [21;22;22;22;22;22;22;23;23;23;23;23;23;24;25;25;26;26;27;28;29;30;30;31;32;32;33;34;35;36;37;38;39;40;41;42;43;44;45;46;47;48;49;50;51;52;53;54;55;56;57;58;59;60;61;62;63;64;65;66;67;68;69;70;71;72;73;74;75;76;77;78;79;79;80;80;81;81;81;82;82;82;82;83;83;83;84;84;85;85;86;86;86;86;86;86;85;84;84;83;82;81;80;79;78;77;76;75;74;73;72;71;70;69;68;67;66;65;64;63;62;61;60;59;58;57;56;55;54;53;52;51;50;49;48;47;46;45;44;43;42;41;40;39;38;37;36;35;34;33;32;31;30;29;28;27;26;25;25;24;24;23;22;21;21;21;21;21;21;21;21;21;21;21;21;21];
y = [44;43;42;41;40;39;38;37;36;35;34;33;32;31;30;29;28;27;26;25;24;23;22;21;20;19;18;18;17;17;17;17;17;16;16;16;16;16;16;15;15;14;14;14;14;14;14;15;15;15;16;16;17;17;17;17;18;18;18;19;20;20;21;22;23;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40;41;42;43;44;45;46;47;48;49;50;51;52;53;54;55;56;56;57;57;58;59;59;60;61;61;61;61;61;60;60;60;59;58;57;56;56;55;55;54;54;54;54;54;54;54;54;54;55;55;55;55;56;57;58;59;60;61;61;62;63;63;64;64;65;65;66;66;66;66;66;66;65;64;63;62;61;60;59;58;57;56;55;54;53;52;51;50;49;48;47;46;45;44];
% generate arbitrary xy
x1 = (x - 50)./10; y1 = (y - 50)./10;
x2 = (x - 50)./10; y2 = (y - 40)./10;
% generate binary masks using poly2mask
pixelSize = 0.01; % resolution
xx = min([x1(:);x2(:)]):pixelSize:max([x1(:);x2(:)]);
yy = min([y1(:);y2(:)]):pixelSize:max([y1(:);y2(:)]);
[xg,yg] = meshgrid(xx,yy);
mask1 = inpolygon(xg,yg,x1,y1);
mask2 = inpolygon(xg,yg,x2,y2);
% add both masks (now their common area pixels equal 2)
combinedMask = mask1 + mask2;
% XOR on both of them
xorMask = xor(mask1,mask2);
% compute mask area in units (rather than pixels)
Area = bwarea(xorMask)*pixelSize^2;
% plot
subplot(131);
plot(x1,y1,x2,y2,'LineWidth',2);
title('Curves');
axis square
set(gca,'YDir','reverse');
subplot(132);
imshow(combinedMask,[]);
title('Combined Mask');
subplot(133);
imshow(xorMask,[]);
title(['XNOR Mask, Area = ' num2str(Area)]);
function area = area_between_curves(initial,corrected)
interval = 0.1;
x = -80:interval:80;
y = -80:interval:80;
[X,Y] = meshgrid(x,y);
in_initial = inpolygon(X,Y,initial(:,1),initial(:,2));
in_corrected = inpolygon(X,Y,corrected(:,1),corrected(:,2));
in_area = xor(in_initial,in_corrected);
area = interval^2*nnz(in_area);
% visualization
figure
hold on
plot(X(in_area),Y(in_area),'r.')
plot(X(~in_area),Y(~in_area),'b.')
end
If I use the lines of the question, this is the result:
area = 1.989710000000001e+03

Draw line and Cut off Circuler area

I have got the below Image after running the below code.
file='grayscale.png';
I=imread(file);
bw = im2bw(I);
bw = bwareaopen(bw,870);
imwrite(bw,'noiseReduced.png')
subplot(2,3,1),imshow(bw);
[~, threshold] = edge(bw, 'sobel');
fudgeFactor = .5;
im = edge(bw,'sobel', threshold * fudgeFactor);
subplot(2,3,2), imshow(im), title('binary gradient mask');
se = strel('disk',5);
closedim = imclose(im,se);
subplot(2,3,3), imshow(closedim), title('Connected Cirlces');
cc = bwconncomp(closedim);
S = regionprops(cc,'Centroid'); //returns the centers S(2) for innercircle
numPixels = cellfun(#numel,cc.PixelIdxList);
[biggest,idx] = min(numPixels);
im(cc.PixelIdxList{idx}) = 0;
subplot(2,3,4), imshow(im), title('Inner Cirlces Only');
c = S(2);
My target is now to draw a red cirle around the circular object(see image) and cut the circle region(area) from the original image 'I' and save the cropped area as image or perform other tasks. How can I do it?
Alternatively, you can optimize/fit the circle with least r that contains all the points:
bw = imread('http://i.stack.imgur.com/il0Va.png');
[yy xx]=find(bw);
Now, let p be a three vector parameterizing a circle: p(1), p(2) are the x-y coordinates of the center and p(3) its radii. Then we want to minimize r (i.e., p(3)):
obj = #(p) p(3);
Subject to all points inside the circle
con = #(p) deal((xx-p(1)).^2+(yy-p(2)).^2-p(3).^2, []);
Optimizing with fmincon:
[p, fval] = fmincon(obj, [mean(xx), mean(yy), size(bw,1)/4], [],[],[],[],[],[],con);
Yields
p =
471.6397 484.4164 373.2125
Drawing the result
imshow(bw,'border','tight');
colormap gray;hold on;
t=linspace(-pi,pi,1000);
plot(p(3)*cos(t)+p(1),p(3)*sin(t)+p(2),'r', 'LineWidth',1);
You can generate a binary mask of the same size as bw with true in the circle and false outside
msk = bsxfun(#plus, ((1:size(bw,2))-p(1)).^2, ((1:size(bw,1)).'-p(2)).^2 ) <= p(3).^2;
The mask looks like:
The convexhull of the white pixels will give you a fairly good approximation of the circle. You can find the center as the centroid of the area of the hull and the radius as the average distance from the center to the hull vertices.

Matlab - Subtracting two 3D figures with surf and min function

I'm trying to make a surf plot that looks like:
So far I have:
x = [-1:1/100:1];
y = [-1:1/100:1];
[X,Y] = meshgrid(x,y);
Triangle1 = -abs(X) + 1.5;
Triangle2 = -abs(Y) + 1.5;
Z = min(Triangle1, Triangle2);
surf(X,Y,Z);
shading flat
colormap winter;
hold on;
[X,Y,Z] = sphere();
Sphere = surf(X, Y, Z + 1.5 );% sphere with radius 1 centred at (0,0,1.5)
hold off;
This code produces a graph that looks like :
A pyramid with square base ([-1,1]x[-1,1]) and vertex at height c = 1.5 above the origin (0,0) is erected.
The top of the pyramid is hollowed out by removing the portion of it that falls within a sphere of radius r=1 centered at the vertex.
So I need to keep the part of the surface of the sphere that is inside the pyramid and delete the rest. Note that the y axis in each plot is different, that's why the second plot looks condensed a bit. Yes there is a pyramid going into the sphere which is hard to see from that angle.
I will use viewing angles of 70 (azimuth) and 35 (elevation). And make sure the axes are properly scaled (as shown). I will use the AXIS TIGHT option to get the proper dimensions after the removal of the appropriate surface of the sphere.
Here is my humble suggestion:
N = 400; % resolution
x = linspace(-1,1,N);
y = linspace(-1,1,N);
[X,Y] = meshgrid(x,y);
Triangle1 = -abs(X)+1.5 ;
Triangle2 = -abs(Y)+1.5 ;
Z = min(Triangle1, Triangle2);
Trig = alphaShape(X(:),Y(:),Z(:),2);
[Xs,Ys,Zs] = sphere(N-1);
Sphere = alphaShape(Xs(:),Ys(:),Zs(:)+2,2);
% get all the points from the pyramid that are within the sphere:
inSphere = inShape(Sphere,X(:),Y(:),Z(:));
Zt = Z;
Zt(inSphere) = nan; % remove the points in the sphere
surf(X,Y,Zt)
shading interp
view(70,35)
axis tight
I use alphaShape object to remove all unwanted points from the pyramid and then plot it without them:
I know, it's not perfect, as you don't see the bottom of the circle within the pyramid, but all my tries to achieve this have failed. My basic idea was plotting them together like this:
hold on;
Zc = Zs;
inTrig = inShape(Trig,Xs(:),Ys(:),Zs(:)+1.5);
Zc(~inTrig) = nan;
surf(Xs,Ys,Zc+1.5)
hold off
But the result is not so good, as you can't really see the circle within the pyramid.
Anyway, I post this here as it might give you a direction to work on.
An alternative to EBH's method.
A general algorithm from subtracting two shapes in 3d is difficult in MATLAB. If instead you remember that the equation for a sphere with radius r centered at (x0,y0,z0) is
r^2 = (x-x0)^2 + (y-y0)^2 + (z-z0)^2
Then solving for z gives z = z0 +/- sqrt(r^2-(x-x0)^2-(y-y0)^2) where using + in front of the square root gives the top of the sphere and - gives the bottom. In this case we are only interested in the bottom of the sphere. To get the final surface we simply take the minimum z between the pyramid and the half-sphere.
Note that the domain of the half-sphere is defined by the filled circle r^2-(x-x0)^2-(y-y0)^2 >= 0. We define any terms outside the domain as infinity so that they are ignored when the minimum is taken.
N = 400; % resolution
z0 = 1.5; % sphere z offset
r = 1; % sphere radius
x = linspace(-1,1,N);
y = linspace(-1,1,N);
[X,Y] = meshgrid(x,y);
% pyramid
Triangle1 = -abs(X)+1.5 ;
Triangle2 = -abs(Y)+1.5 ;
Pyramid = min(Triangle1, Triangle2);
% half-sphere (hemisphere)
sqrt_term = r^2 - X.^2 - Y.^2;
HalfSphere = -sqrt(sqrt_term) + z0;
HalfSphere(sqrt_term < 0) = inf;
Z = min(HalfSphere, Pyramid);
surf(X,Y,Z)
shading interp
view(70,35)
axis tight

How to transform different shapes to circles in Matlab

I have this image:
that has different shapes, and I want to transform each shape in a circle. And each circle must have different radius, depending on the size of the shape. How can I do that? With Morphology Operations or there are any function on Matlab that does that?
I used the function Regionprops to detect every individual shape, then I can do operations on each region separately.
I would use bwlabel to first label all of the components. Then I would use regionprops to find the bounding box of each component. You can then use the rectangle with a Curvature value of [1 1] to plot an ellipse at each bounding box.
%// Load the image and convert to 0's and 1's
img = imread('http://i.stack.imgur.com/9wRYK.png');
img = double(img(:,:,1) > 0);
%// Label the image
L = bwlabel(img);
%// Compute region properties
P = regionprops(L);
imshow(img)
for k = 1:numel(P)
%// Get the bounding box
bb = P(k).BoundingBox;
%// Plot an ellipse around each object
hold on
rectangle('Position', bb, ...
'Curvature', [1 1], ...
'EdgeColor', 'r', ...
'LineWidth', 2);
end
If you actually want circles, you will need to decide how exactly you define a circle from a rectangle. For this, I just used the maximum of the width and height for the diameter.
t = linspace(0, 2*pi, 100);
cost = cos(t);
sint = sin(t);
for k = 1:numel(P)
bb = P(k).BoundingBox;
%// Compute the radius and center of the circle
center = [bb(1)+0.5*bb(3), bb(2)+0.5*bb(4)];
radius = max(bb(3:4)) / 2;
%// Plot each circle
plot(center(1) + radius * cost, ...
center(2) + radius * sint, ...
'Color', 'r');
end
Now if you actually want to modify the image data itself rather than simply displaying it, you can use a meshgrid of all of the pixel centers to test whether a given pixel is within a circle or not.
%// Create a new image the size of the old one
newImage = zeros(size(img));
%// Determine the x/y coordinates for each pixel
[xx,yy] = meshgrid(1:size(newImage, 2), 1:size(newImage, 1));
xy = [xx(:), yy(:)];
for k = 1:numel(P)
bb = P(k).BoundingBox;
%// Compute the circle that fits each bounding box
center = [bb(1)+0.5*bb(3), bb(2)+0.5*bb(4)];
radius = max(bb(3:4)) / 2;
%// Now check if each pixel is within this circle
incircle = sum(bsxfun(#minus, xy, center).^2, 2) <= radius^2;
%// Change the values of newImage
newImage(incircle) = k;
end
%// Create a binary mask of all points that were within any circle
mask = newImage > 0;