Draw line and Cut off Circuler area - matlab

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.

Related

Fit an inside circle of an object - Matlab

I wish to fit an inside circle of an outline object, how can I do it? in the example shown I tried to calculate the r by dividing the MajorAxisLength but it does not work.
Code:
clc;
clear;
RGB = imread('pillsetc.png');
I = rgb2gray(RGB);
bw = imbinarize(I);
imshow(bw)
bw = bwareaopen(bw,30);
bw = imfill(bw,'holes');
imshow(bw)
[B,L] = bwboundaries(bw,'noholes');
stats = regionprops(L,'Centroid','MajorAxisLength');
hold on
k=3;
boundary = B{k};
r = stats(k).MajorAxisLength/2;
centroid = stats(k).Centroid;
plot(centroid(1),centroid(2),'+');
theta = linspace(0,2*pi);
x = r*cos(theta) + centroid(1);;
y = r*sin(theta) + centroid(2);;
plot(x,y)
axis equal
Ok, this is an approximated solution, but given the limited parameters you can get from regionprops, this is probably good enough.
My derivations are follows:
the goal to calculate the radius of the inscribed circle of a rectangle is to estimate the length of the short-edge.
If we assume the elliptic fitting to a rectangle yields approximately the same area as the rectangle, and the short/long edge ratio is the same as the minor/major axis ratios, then, we can obtain the following equation:
x=short edge of the rectangle;
y=long edge of the rectangle;
b=minor axis of the fitted ellipse;
a=major axis of the fitted ellipse;
then we have
x/y=b/a
x*y=a*b*pi
from that, we can solve the value of x is sqrt(pi)*b. That makes the radius of the inscribed circle sqrt(pi)/2*b.
changing your below two lines of code
stats = regionprops(L,'Centroid','MinorAxisLength');
...
r = stats(k).MinorAxisLength*(sqrt(pi)/4);
...
I was able to get something pretty close to the inscribed circle. Give it a try.

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;

how to draw oval shape around objects in image

I want to draw oval shape around cells in a binary image. So far I tried the code shown below to draw ellipses around cells in a binary image. In code, IBord is the binary image.Code draws ellipse shape successfully around cells.
s = regionprops(IBord, 'Orientation', 'MajorAxisLength', 'MinorAxisLength', 'Eccentricity', 'Centroid');
figure(2);
imshow(IBord)
phi = linspace(0,2*pi,50);
cosphi = cos(phi);
sinphi = sin(phi);
for k = 1:length(s)
xbar = s(k).Centroid(1);
ybar = s(k).Centroid(2);
a = s(k).MajorAxisLength/2;
b = s(k).MinorAxisLength/2;
theta = pi*s(k).Orientation/180;
R = [ cos(theta) sin(theta)
-sin(theta) cos(theta)];
xy = [a*cosphi;b*sinphi];
xy = R*xy;
X = xy(1,:) + xbar;
Y = xy(2,:) + ybar;
plot(X,Y,'r','LineWidth',2);
end
kindly suggest how can i modify this code to draw oval shape (egg like shape) around cells in a binary image.
One way to achieve this effect is to use smaller exponents on cosphi and sinphi.
gam = .8
xy = [a * sign(cosphi) .* abs(cosphi).^gam; b * sign(sinphi) .* abs(sinphi).^gam];
Play around with gam. This should give more oval-ly shapes.

How to draw a filled circle on a video frame using matlab

I have an "inverted-pendulum" video which I try to find the mid point of moving part. I am using Computer Vision Toolbox
I change the mid point's color using detected coordinates. Assume that X is the frame's row number for the detected mid point and the Y is the col number.
while ~isDone(hVideoFileReader)
frame = step(hVideoFileReader);
...
frame(X-3:X+3, Y-3:Y+3, 1) = 1; % # R=1 make the defined region red
frame(X-3:X+3, Y-3:Y+3, 2) = 0; % # G=0
frame(X-3:X+3, Y-3:Y+3, 3) = 0; % # B=0
step(hVideoPlayer, frame);
end
Then I easily have a red square. But I want to add a red filled circle on the detected point, instead of a square. How can I do that?
You can use the insertShape function. Example:
img = imread('peppers.png');
img = insertShape(img, 'FilledCircle', [150 280 35], ...
'LineWidth',5, 'Color','blue');
imshow(img)
The position parameter is specified as [x y radius]
EDIT:
Here is an alternative where we manually draw the circular shape (with transparency):
% some RGB image
img = imread('peppers.png');
[imgH,imgW,~] = size(img);
% circle parameters
r = 35; % radius
c = [150 280]; % center
t = linspace(0, 2*pi, 50); % approximate circle with 50 points
% create a circular mask
BW = poly2mask(r*cos(t)+c(1), r*sin(t)+c(2), imgH, imgW);
% overlay filled circular shape by using the mask
% to fill the image with the desired color (for all three channels R,G,B)
clr = [0 0 255]; % blue color
a = 0.5; % blending factor
z = false(size(BW));
mask = cat(3,BW,z,z); img(mask) = a*clr(1) + (1-a)*img(mask);
mask = cat(3,z,BW,z); img(mask) = a*clr(2) + (1-a)*img(mask);
mask = cat(3,z,z,BW); img(mask) = a*clr(3) + (1-a)*img(mask);
% show result
imshow(img)
I'm using the poly2mask function from Image Processing Toolbox to create the circle mask (idea from this post). If you don't have access to this function, here is an alternative:
[X,Y] = ndgrid((1:imgH)-c(2), (1:imgW)-c(1));
BW = (X.^2 + Y.^2) < r^2;
That way you get a solution using core MATLAB functions only (no toolboxes!)
If you have an older version of MATLAB with the Computer Vision System Toolbox installed, you can use vision.ShapeInserter system object.
Thanks #Dima, I have created a shapeInserter object.
greenColor = uint8([0 255 0]);
hFilledCircle = vision.ShapeInserter('Shape','Circles',...
'BorderColor','Custom',...
'CustomBorderColor', greenColor ,...
'Fill', true, ...
'FillColor', 'Custom',...
'CustomFillColor', greenColor );
...
fc = int32([Y X 7;]);
frame = step(hFilledCircle, frame, fc);
I then applied it to detected point.

Selecting an ellipse as a region of interest (ROI)

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));