I have binary images and they have semi or less circles. My aim is to find these circles, make them whole circles and remove all other objects . I found this but it is for MATLAB R2013a. I am using R2011b and it doesn't have the function centers = imfindcircles(A,radius).
How can I do that in MATLAB version R2011b?
Images:
Edit:
My aim is to get whole circle. I show this below for the last image.
Too bad about imfindcircles! One thing I can suggest is to invoke regionprops and specify the 'Area' and 'BoundingBox' flags. regionprops was available in MATLAB for as long as I can remember, so we can certainly use it here.
What this will do is that whatever distinct objects that are seen in the image that are connected, we will find both their areas and their bounding boxes that bound them. After you do this, threshold on the area so that any objects that have a very large area most likely contain circles of interest. Bear in mind that I'm only assuming that you have circles in your image. Should you have any objects that have a large area, this method will extract those out too.
As such, let's read in your image directly from Stack Overflow. When you uploaded the image, it's a RGB image, so I'll have to convert to binary:
im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im_bw = im2bw(im);
Next, call regionprops:
s = regionprops(im_bw, 'Area', 'BoundingBox');
Now, collect all of the areas, and let's take a look at all of the unique areas of all objects seen in this image:
areas = [s.Area].';
unique(areas)
ans =
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
19
20
23
24
25
28
29
38
43
72
73
85
87
250
465
3127
If you take a look at the very end, you'll see that we have an object that has 3127 pixels in it. This probably contains our circle. As such, let's pick out that single element that contains this object:
s2 = s(areas == 3127);
In general, you'll probably have more than one circle in your image, so you should threshold the area to select those potential circles. Something like:
s2 = s(areas > 2000);
Now, let's create a new blank image that is the same size as the original image, then simply use the BoundingBox property to extract out the area that encompasses the circle in the original image and copy it over to the same location in the output image. The BoundingBox field is structured in the following way:
[x y w h]
x and y are the top-left corner of the bounding box. x would be the column and y would be the row. w and h are the width and height of the bounding box. As such, we can use this directly to access our image and copy those pixels over into the output image.
out = false(size(im_bw));
bb = floor(s2.BoundingBox); %// Could be floating point, so floor it
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
This is what I get:
What you should probably do is loop over the circles in case we have more than one. The above code assumes that you detected just one circle. Therefore, do something like this:
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
A small thing to note is that the bounding box encompasses the entire object, but there could also be some noisy pixels that are disconnected that are within that bounding box. You may have to apply some morphology to get rid of those pixels. A binary opening could suffice.
Here's what I get with your other images. I thresholded the area to search for those that have 2000 pixels or more (I did this above):
Just for self-containment and your copy-and-pasting pleasure, here's the code in one segment:
clear all;
close all;
%im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);
s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
imshow(out);
All three images are there in the code. You just have to uncomment whichever one you want to use, comment out the rest, then run the code. It will display an image with all of your detected circles.
Edit
You would like to draw complete circles, instead of extracting the shape themselves. That isn't a problem to do. All you need to do is determine the best "radii" that can be enclosed inside each of the bounding boxes. This is simply the maximum of the width and height of each bounding box, then divide these quantities by 2.
After, create a 2D grid of co-ordinates through meshgrid that is the same size as the original image itself, then create a binary image such that the Euclidean distance between the centre of this bounding box with any point in this 2D grid less than the radius is set to logical true while the other positions are set to logical false.
In other words, do this:
clear all;
close all;
im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
%im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);
s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
figure;
imshow(out);
%// Image that contains all of our final circles
out2 = false(size(im_bw));
[X,Y] = meshgrid(1:size(im_bw,2), 1:size(im_bw,1)); %// Find a 2D grid of co-ordinates
for idx = 1 : numel(s2) %// For each circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
cenx = bb(1) + (bb(3) / 2.0); %// Get the centre of the bounding box
ceny = bb(2) + (bb(4) / 2.0);
radi = max(bb(3), bb(4)) / 2; %// Find the best radius
tmp = ((X - cenx).^2 + (Y - ceny).^2) <= radi^2; %// Draw our circle and place in a temp. image
out2 = out2 | tmp; %// Add this circle on top of our output image
end
figure;
imshow(out2);
This script now shows you the original extracted shapes, and the best "circles" that describes these shapes in two separate figures. Bear in mind that this is a bit different than what I showed you previously with one circle. What I have to do now is allocate a blank image, then incrementally add each circle to this new image. For each circle, I create a temporary binary image that has just a circle I'm looking for, then I add this on top of the new image. At the end, we will show all of the circles in the image that are fully drawn as you desire.
This is what I get for the best circle for each of your images:
Good luck!
Related
I have a list of coordinates, which are generated from another program, and I have an image.
I'd like to load those coordinates (making circular regions of interest (ROIs) with a diameter of 3 pixels) onto my image, and extract the intensity of those pixels.
I can load/impose the coordinates on to the image by using;
imshow(file);
hold on
scatter(xCoords, yCoords, 'g')
But can not extract the intensity.
Can you guys point me in the right direction?
I am not sure what you mean by a circle with 3 pixels diameter since you are in a square grid (as mentioned by Ander Biguri). But you could use fspecial to create a disk filter and then normalize. Something like this:
r = 1.5; % for diameter = 3
h = fspecial('disk', r);
h = h/h(ceil(r),ceil(r));
You can use it as a mask to get the intensities at the given region of the image.
im = imread(file);
ROI = im(xCoord-1:xCoord+1; yCoord-1:yCoord+1);
I = ROI.*h;
Is it possible to find the area of the black pixelation of an area within a circle? in other words I want to find the number of pixels (the area) of the RGB 0,0,0 (black pixels) within the circle. I do not want the areas of the white pixels (1,1,1) within the circle. I also have a radius of the circle if that helps. Here is the image:
Here is the code:
BW2= H(:,:) <0.45 ;%& V(:,:)<0.1;
aa=strel('disk',5);
closeBW = imclose(BW2,aa);
figure, imshow(closeBW)
imshow(closeBW)
viscircles([MYY1 MYX1], round(MYR2/2))
MYY1,MYX2, and the other values are calculated by my program. How can I find the area of the black pixelation in my circle?
Here is an idea:
1) Calculate the total # of black pixels in your original image (let's call it A).
2) Duplicate that image (let's call it B) and replace all pixels inside the circle with white. To do that, create a binary mask. (see below)
3) Calculate the total # of black pixels in that image (i.e. B).
4) Subtract both values. That should give you the number of black pixels within the circle.
Sample code: I used a dummy image I had on my computer and created a logical mask with the createMask method from imellipse. That seems complicated but in your case since you have the center position and radius of the circle you can create directly your mask like I did or by looking at this question/answer.
Once the mask is created, use find to get the linear indices of the white pixels of the mask (i.e. all of it) to replace the pixels in the circle of your original image with white pixels, which you use to calculate the difference in black pixels.
clc;clear;close all
A = im2bw(imread('TestCircle.png'));
imshow(A)
Center = [160 120];
Radius = 60;
%// In your case:
% Center = [MYY1 MYX1];
% Radius = round(MYR2/2);
%// Get sum in original image
TotalBlack_A = sum(sum(~A))
e = imellipse(gca, [Center(1) Center(2) Radius Radius]);
%// Create the mask
ROI = createMask(e);
%// Find white pixels
white_id = find(ROI);
%// Duplicate original image
B = A;
%// Replace only those pixels in the ROI with white
B(white_id) = 1;
%// Get new sum
NewBlack_B = sum(sum(~B))
%// Result!
BlackInRoi = TotalBlack_A - NewBlack_B
In this case I get this output:
TotalBlack_A =
158852
NewBlack_B =
156799
BlackInRoi =
2053
For this input image:
Just a quick question. I've an image and I've extracted a certain point (feature), I know the coordinates of that point in every frame.
Say x1 and y1.
I need a circular ROI form that point on the image with a radius that I chose.
I tried impoly and roipoly - not sure how to use either of these when I know the point in the image.
Thanks
Since you know the coordinates of the center of the ROI along with the radius, you can modify a bit the code provided by #Jonas here to create a circular mask in a quite efficient way.
Example:
clc;clear
Im = imread('coins.png');
[rNum,cNum,~] = size(Im);
%// Define coordinates and radius
x1 = 60;
y1 = 100;
radius = 40;
%// Generate grid with binary mask representing the circle. Credit to Jonas for original code.
[xx,yy] = ndgrid((1:rNum)-y1,(1:cNum)-x1);
mask = (xx.^2 + yy.^2)<radius^2;
%// Mask the original image
Im(mask) = uint8(0);
imshow(Im)
Output:
EDIT
If you want to see only the outer edge of the ROI to see the center, add a logical condition with some tolerance for the radius of a smaller circle. Something like this:
mask = (xx.^2 + yy.^2)<radius^2 & (xx.^2 + yy.^2)>(radius-tol)^2;
With a tol of 2 it looks like this:
Can you guys suggest possible ways on how to remove the circle outline in this image? Imfindcircles doesnt work for me. Can you suggest other methods? http://i.stack.imgur.com/RuD7v.jpg
Assuming BW to be the binary image that has the outline circled and which is to be removed, you can use an approach based on regionprops -
perimtrs = regionprops(BW, 'Perimeter'); %// perimeters for each connected component
px = regionprops(BW, 'PixelIdxList'); %// pixel list for each connected component
[~,idx] = max(struct2array(perimtrs)); %// get the component with max perimeter
%// that represents the outline circle
BW(px(idx).PixelIdxList) = 0; %// Set all pixels of the outline circle to zero,
%// that is they are removed
If you would like to be on the safest side with the functionality, you can use BoundingBox properties from regionprops instead of 'Perimeter' as shown here -
%// Get the bounding box properties for each connected component
perimtrs = regionprops(BW, 'BoundingBox');
%// Get bounding box area for each component and get the ID for the largest
%// box that corresponds to the outline circle
bound_box = reshape(struct2array(perimtrs),4,[]);
bound_box_area = bound_box(3,:).*bound_box(4,:);
[~,idx] = max(bound_box_area);
%// Set the pixels corresponding to the outline circle to zeros
px = regionprops(BW, 'PixelIdxList');
BW(px(idx).PixelIdxList) = 0;
Alternatively, you can avoid the second use of regionprops to get the pixel list with a call to regionprops and that might be efficient with performance, but I haven't not tested, so can't guarantee that. The new approach would look something like this -
perimtrs = regionprops(BW, 'Perimeter');
[~,idx] = max(struct2array(perimtrs))
[L,num] = bwlabel( BW ); %// Label connected components
BW(L==idx)=0; %// Select all pixels corresponding to label idx and set those to zero
Similarly, you can mix this bwlabel approach with BoundingBox of regionprops.
OK so here goes one hypotheses that does not assume the interface to be a circle, neither to be a single region, or having the largest perimeter.
%Assume A as your original image (left image), and bin_A as your binary image (right image)
thres=graythresh(A)
mask_A=im2bw(A,thres);
mask_A=imerode(mask_A,ones(3));
bin_A=bin_A.*mask_A;
I have an intensity image where i marked with the impoly function a region of interest. I have a code that gives me back the vertices of the smallest rectangle still containing my polygon.
The rectangle is most of the times not aligned with the axes. I would like to receive the data inside the rectangle into a matrix form.I have been trying to find out the angle between the largest side of the rectangle and the x axis and then to rotate the image so the rectangle will be aligned with the axes.I will really appreciate any help or new ideas on how to extract the values inside my rectangle into a matrix.
Here is part of my code:
filename = uigetfile; %get the file name
obj = VideoReader(filename);
nFrames=obj.NumberOfFrames;
thisfig = figure();
for k = 1 : nFrames
this_frame = read(obj, k);
thisax = axes('Parent', thisfig);
image(this_frame, 'Parent', thisax);
if k==nFrames
title(thisax, sprintf('Frame #%d', k));
end
if k==1
result=input('How many polygons would you like to draw? ');
for i=1:result
handle=impoly;
accepted_pos = wait(handle);
BW = createMask(handle);
sparse_image=sparse(BW);
[XX, YY] = find(sparse_image);
[rectx,recty]=minboundrect(XX,YY); %the function that returns the vertices of the rectangle
points=[rectx(1),rectx(2),rectx(3),rectx(4);recty(1),recty(2),recty(3),recty(4)]
distance1=((points(1,2)-points(1,1))^2+(points(2,2)-points(2,1))^2)^0.5;
distance2=((points(1,3)-points(1,2))^2+(points(2,3)-points(2,2))^2)^0.5;
if(distance1>distance2) %which side of the rectangle is the largest
vector=[points(1,2)-points(1,1),points(2,2)-points(2,1)];
else
vector=[points(1,3)-points(1,2),points(2,3)-points(2,2)];
end
angleInDegrees = atan2(vector(2), vector(1)) * 180 / pi; %supposed angle between the largest side and the x axis
end
end
To be clear: I get a video and split it into frames and i need to follow a certain area in all of the frames in the video. I'm dealing with a video but i split it into frames so i'm really dealing with images. The rectangle i get is slanted most of the times,i.e not aligned with the axes of my image.
Confusing question.
The code refers to videos, not images.
Is the question about rotating an image? Is the question about retrieving a sub-matrix from an image?
Is the posted code really relevant to the question?
What have you tried?
From the doc:
this_frame = read(obj, k);
video = read(obj) reads in all video frames from the file associated with obj. The read method returns a H-by-W-by-B-by-F matrix, video, where H is the image frame height, W is the image frame width, B is the number of bands in the image (for example, 3 for RGB), and F is the number of frames read.
It seems that you do have the coordinates:
[rectx,recty]=minboundrect(XX,YY);
So I'd say that the matrix you're looking for is
A = this_frame(rectx(1):rectx(2), recty(1):rectx(y), 1, 1); % Red band
Please edit your question for clarity.