Measure circularity or ellipticality - matlab

I have some binary images that want to classify them base on shape of them in MATLAB. If they have circular or elliptical shape they belong to class one,if they have elliptical shape with dent in their boundary they belong to class two. I dont know how can I use this feature. Can any body help me with this?

You can use the eccentricity property in regionprops. From MATLAB documentation of eccentricity:
The eccentricity is the ratio of the distance between the foci of the ellipse and its major axis length. The value is between 0 and 1. (0 and 1 are degenerate cases. An ellipse whose eccentricity is 0 is actually a circle, while an ellipse whose eccentricity is 1 is a line segment.)
So as the value of eccentricity increases , the ellipse starts becoming flatter. Hence, at its maximum value = 1, it is a line segment.
To check if there is a dent in the ellipse, you can use check for convexity. Whenever there is a dent in an ellipse, it will be non-convex. In other words, if you try to fit a convex polygon, it won't be able to approximate the shape well enough. You can use convexArea property to check the same. From MATLAB documentation of convexArea:
Returns a p-by-2 matrix that specifies the smallest convex polygon that can contain the region. Each row of the matrix contains the x- and y-coordinates of one vertex of the polygon. Only supported for 2-D label matrices.
So you use bwlabel to create a 2-D label matrix from your binary image and then check the difference between the area of your binary image and the area of the fitted convex polygon. Measuring area could be as simple as counting pixels. You already know that the number pixels of your fitted convex polygon = p. Just take the absolute difference between p and the number of pixels in your original binary image. You should be able to easily set a threshold to classify into one of the two classes.
I think you can write the code for this. Hope this helps.

Related

how to determine if an image is symmetrical?-MATLAB

I have a 3D color image. I wish to plot its principal axis and its centroid. To do that, I have extracted each of the color channels, found the centroid and then proceeded to find the covariance matrix and eigenvalue. I am unsure as to whether this will help me plot the principal axis.
My primary goal is to plot the principal axis so that I can find whether the image is symmetrical about that axis.
This is the algorithm I would like to implement.
Plot the principal axis of the image. The image is then rotated
(clockwise) to align its coordinate (𝑥 and 𝑦) axes with principal
inertia axis of the image. The image is then hypothetically folded
around the 𝑥-axis and the the sum of the absolute grey-level
difference between the corresponding pixels(𝐴 𝑥) between the
overlapping folds was taken as the amount of asymmetry on the 𝑥-axis.
The same procedure was performed for the 𝑦-axis. Two asymmetry
measures were calculated from 𝐴 𝑥 and 𝐴 𝑦 as follows:
A1 = min (𝐴
𝑥
, 𝐴
𝑦
)
𝐴
× 100%
A2 =
(𝐴
𝑥
+ 𝐴
𝑦
)
𝐴
× 100%.
The two asymmetry measures noted above (𝐴 1 and 𝐴 2) are computed
for each image channel, in the RGB colour space, resulting in the
total of six-coefficient (6D) colour asymmetry feature.
How do I plot the principal axis? I tried using regionprops function in MATLAB to plot the major axis, minor axis, centroid and orientation but I am unsure if this is the right approach. Should I use PCA?
Can I overlap the image using the fliplr function?
What do they mean same procedure for y-axis? If an image is asymmetrical over one axis then doesn't it mean its asymmetrical over the y-axis too?
I am unable to implement this algorithm. Please guide on how to code this in MATLAB.
https://in.mathworks.com/matlabcentral/answers/266988-how-to-flip-a-segmented-image-along-the-major-axis#answer_208875
This is a partial answer to my query but I am stuck at the initial part. How do I find the major axis and align in with the axes using imtranslate()?

Summing squared area changes from Voronoi cells given area of triangles in 3D?

I have a list of triangles in 3D that form a surface (ie a triangulation). The structure is a deformed triangular lattice. I want to know the change in area of the deformed hexagons of the voronoi tessalation of the lattice with respect to the rest area of the undeformed lattice cells (ie with respect to a regular hexagon). In fact, I really want the sum of the squared change in area of the hexagonal unit cells associated with those triangles.
Background/Math details:
I'm approximating a curved elastic sheet by a triangular lattice. One way to tune the poisson ratio (elastic constant) of the sheet is by adding a 'volumetric' strain energy term to the energy. I'm trying to compute a 'volumetric' strain energy of a deformed, elastic, triangular lattice, defined as: U_volumetric = 1/2 T (e_v)^2, where e_v=deltaV/V is determined by the change in area of a voronoi cell with respect to its reference area, which is a known constant.
Reference: https://www.researchgate.net/publication/265853755_Finite_element_implementation_of_a_non-local_particle_method_for_elasticity_and_fracture_analysis
Want:
Sum[ (DeltaA/ A).^2 ] over all hexagonal cells.
My data is stored in the variables:
xyz = [ x1,y1,z1; x2,y2,z2; etc] %the vertices/particles in 3D
TRI = [ vertex0, vertex1, vertex2; etc] %
where vertex0 is the row of xyz for the particle sitting at vertex 0 of the first triangle.
NeighborList = [ p1n1, p1n2, p1n3, p1n4, p1n5,p1n6 ; p2n1...]
% where p1n1 is particle 1's first nearest neighbor as a row index for xyz. For example, xyz(NL(1,1),:) returns the xyz location of particle 1's first neighbor.
AreaTRI = [ areaTRI1; areaTRI2; etc]
I am writing this in MATLAB.
As of now, I am approximating the amount of area attributed to each vertex as 1/3 of the triangle's area, then summing over the 6 nearest neighbor triangles. But a voronoi cell area will NOT be exactly equal to Sum_(i=0,1,...5) 1/3* areaTRI_i, so this is a bad approximation. See the image in the link above, which I think makes this clearer.
You can do this using the DUALMESH-submission on the file exchange:
DUALMESH is a toolbox of mesh processing routines that allow the construction of "dual" meshes based on underlying simplicial triangulations. Support is provided for various planar and surface triangulation types, including non-Delaunay and non-manifold types.
Simply use the following commands to generate a vector areas of all the dual elements' areas. The ordering will correspond to the nodes xyz.
[cp,ce,pv,ev] = makedual2(xyz, TRI);
[~,areas(cp(:,1))] = geomdual2(cp,ce,pv,ev);
You might want to have a look at the boundary areas using:
trisurf(TRI, xyz(:,1), xyz(:,2), areas);
The dual cells of boundary nodes theoretically are unbounded and thus should have infinite area. This submission handles it differently however: Instead of an unbounded cell it will return the intersection of the unbounded cell with the original mesh.
Also mind that your question is not well defined if the mesh you are working with is not planar, as the dual mesh cells will be planar and won't scale the same way as the triangles. So this solution will probably only work correctly if your mesh is really 2D. (From what I can tell, the paper you mention is also only for the 2D-case.)

relabeling pixels based on distance between object's centerline and boundary

I've a binary image containing an object as illustrated in the figure below. The centerline of the object is depicted in red. For each pixel belonging to the object, I would like to relabel it with a color. For instance, pixels whose orthogonal distance to the centerline are half of the distance to the object boundary from the centerline, should be labeled blue, otherwise green. An illustration is given below. Any ideas?
Also, how could I fit a 1D gaussian centered in the object centerline and orthogonal to it?
The image in full resolution can be found under: http://imgur.com/AUK9Hs9
Here is what comes to mind (providing you have the Image Processing Toolbox):
Create two binary images, one BWin with 1 (true) pixels at the location of your red line, and one BWout that is the opposite of your white region (1 outisde the region and 0 (false) inside).
Like this:
BWin:
BWout:
Then apply the euclidean transform to both using bwdist:
Din = bwdist(BWin);
Dout = bwdist(BWout);
You now have two images with pixel intensities that represent the euclidean distance to the closest non-0 pixel.
Now subtract both, the values of the difference will be positive on one side of the equidistance and negative on the other side:
blueMask=Din-Dout>0;
greenMask=~BWout & blueMask;
You can then populate the RGB layer using the masks:
Result=zeros(size(II));
Result(:,:,1)=BWin;
Result(:,:,2)=greenMask;
Result(:,:,3)=~blueMask & ~BWin;
imshow(Result);

Calculate the perimeter of a shape specified with a cloud of points

I have a shape which you can imagine as a lake in a field observed from the top (2D). I determined the border pixels of the shape after an image processing, so that I have the coordinates of each border point.
Now I want to calculate the perimeter of this shape. My problem is that I have the points not in following order that would give a closed loop, but unordered.
How can a problem like this be solved in Matlab? (including Curve-Fitting-Toolbox etc.)
Thank you for any suggestions!
You can use the function regionprops for this.
Turn your image into a binary image with 1 inside your 'lake' and 0 outside (which you should be easily able to do, as you mention you extracted the boundaries).
Then use:
props=regionprops(YourBinaryImage, 'Perimeter');
You can then access the perimeter as follows: props.Perimeter
If you have set of 3D points with (x,y,z) coordinates, you may set z to zero and use the 2D (x,y) points to find the convex hull using convhull regardless of their order .

MATLAB: Return array of values between two co-ordinates in a large matrix (diagonally)

If I explain why, this might make more sense
I have a logical matrix (103x3488) output of a photo of a measuring staff having been run through edge detect (1=edge, 0=noedge). Aim- to calculate the distance in pixels between the graduations on the staff. Problem, staff sags in the middle.
Idea: User inputs co-ordinates (using ginput or something) of each end of staff and the midpoint of the sag, then if the edges between these points can be extracted into arrays I can easily find the locations of the edges.
Any way of extracting an array from a matrix in this manner?
Also open to other ideas, only been using matlab for a month, so most functions are unknown to me.
edit:
Link to image
It shows a small area of the matrix, so in this example 1 and 2 are the points I want to sample between, and I'd want to return the points that occur along the red line.
Cheers
Try this
dat=imread('83zlP.png');
figure(1)
pcolor(double(dat))
shading flat
axis equal
% get the line ends
gi=floor(ginput(2))
x=gi(:,1);
y=gi(:,2);
xl=min(x):max(x); % line pixel x coords
yl=floor(interp1(x,y,xl)); % line pixel y coords
pdat=nan(length(xl),1);
for i=1:length(xl)
pdat(i)=dat(yl(i),xl(i));
end
figure(2)
plot(1:length(xl),pdat)
peaks=find(pdat>40); % threshhold for peak detection
bigpeak=peaks(diff(peaks)>10); % threshold for selecting only edge of peak
hold all
plot(xl(bigpeak),pdat(bigpeak),'x')
meanspacex=mean(diff(xl(bigpeak)));
meanspacey=mean(diff(yl(bigpeak)));
meanspace=sqrt(meanspacex^2+meanspacey^2);
The matrix pdat gives the pixels along the line you have selected. The meanspace is edge spacing in pixel units. The thresholds might need fiddling with, depending on the image.
After seeing the image, I'm not sure where the "sagging" you're referring to is taking place. The image is rotated, but you can fix that using imrotate. The degree to which it needs to be rotated should be easy enough; just input the coordinates A and B and use the inverse tangent to find the angle offset from 0 degrees.
Regarding the points, once it's aligned straight, all you need to do is specify a row in the image matrix (it would be a 1 x 3448 vector) and use find to get non-zero vector indexes. As the rotate function may have interpolated the pixels somewhat, you may get more than one index per "line", but they'll be identifiable as being consecutive numbers, and you can just average them to get an approximate value.