How to get pixel location of object in image [closed] - matlab

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Suppose I have a binary image shown in below. I want to get the location(pixel value in X,Y coordinates) of all rectangular shapes and also circular shapes. How to detect how many rectangular and circular shapes are present there. I want to get the solution in Matlab. The rectangle and circle may be in different size. The small circles are noise here. Thanks in advance.

You need to:
find connected components (bwconncomp)
find some statistic for each connected component (regionprops)
discard connected components that are too small, defining a threshold on the area
find if the connected component is a rectangle or a circle / ellipse. You can use the circularity, defined as 4*pi*Area / (Perimeter^2). Perfect circles will have value 1, squares 0.785, and so on. So you can define a threshold on circularity to determine if a shape is a circle/ellipse or not.
Here the result, with smaller blobs removed, and circles/ellipses and rectangles in different colors:
Code:
% Read image
img = imread('path_to_image');
% Convert to grayscale
img = rgb2gray(img);
% Remove JPEG artifacts
bw = img > 20;
% Prepare output image
output = zeros(size(bw));
% Compute connected components, and their statistics
cc = bwconncomp(bw);
props = regionprops(cc, 'Area', 'Perimeter');
% Will contain x,y coordinates for rectanles and circles
coord_rect = {};
coord_circ = {};
% Define thresholds on size and circularity
th_size = 200;
th_circ = 0.8;
% For each connected component
for i = 1 : cc.NumObjects
% Is big enough?
if(props(i).Area < th_size)
continue;
end
% Rectangle or Circle?
circularity = 4 * pi * props(i).Area / (props(i).Perimeter ^ 2);
[y,x] = ind2sub(cc.ImageSize, cc.PixelIdxList{i});
if(circularity > th_circ)
% Circle
output(cc.PixelIdxList{i}) = 1;
coord_circ{end+1} = [x, y];
else
% Rectangle
output(cc.PixelIdxList{i}) = 2;
coord_rect{end+1} = [x, y];
end
end
% Show results
imshow(bw);
figure();
imagesc(output);

Related

If two rectangles intersection is zero in matlab [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Knowing center of the two rectangles and their angle by x axis (horizontal axis), how can one recognize if their intersection is zero or not in Matlab? Any answers containing this information is highly appreciated. Width and length of rectangles are also known
This is a programming problem if you want to solve it numerically. For exact solutions, you could use geometrical equations.
The first problem: defining a rectangle's corners from its width, height and centre:
C1 = [0, 0]; % Centre of rectangle 1 (x,y)
C2 = [1, 1]; % Centre of rectangle 2 (x,y)
W1 = 5; W2 = 3; % Widths of rectangles 1 and 2
H1 = 2; H2 = 3; % Heights of rectangles 1 and 2
% Define the corner points of the rectangles using the above
R1 = [C1(1) + [W1; W1; -W1; -W1]/2, C1(2) + [H1; -H1; -H1; H1]/2];
R2 = [C2(1) + [W2; W2; -W2; -W2]/2, C2(2) + [H2; -H2; -H2; H2]/2];
Next problem is to create many points which represent the edges of the rectangles. You could instead generate many points within the rectangles if you wanted to look at intersecting areas.
n = 1000; % Define some number of points to use
% Use interp1 to interpolate around the rectangles
R1points = interp1(1:5, [R1; R1(1,:)], linspace(1,5,n));
R2points = interp1(1:5, [R2; R2(1,:)], linspace(1,5,n));
Then rotate the rectangles:
a1 = deg2rad(0); a2 = deg2rad(30); % angles of rotation for rectangle 1 and 2 respectively
R1rotated(:,1) = (R1points(:,1)-C1(1))*cos(a1) - (R1points(:,2)-C1(2))*sin(a1) + C1(1);
R1rotated(:,2) = (R1points(:,1)-C1(1))*sin(a1) + (R1points(:,2)-C1(2))*cos(a1) + C1(2);
R2rotated(:,1) = (R2points(:,1)-C2(1))*cos(a2) - (R2points(:,2)-C2(2))*sin(a2) + C2(1);
R2rotated(:,2) = (R2points(:,1)-C2(1))*sin(a2) + (R2points(:,2)-C2(2))*cos(a2) + C2(2);
Finally, check intersection with inpolygon:
in1 = inpolygon(R1rotated(:,1), R1rotated(:,2), R2rotated(:,1), R2rotated(:,2));
in2 = inpolygon(R2rotated(:,1), R2rotated(:,2), R1rotated(:,1), R1rotated(:,2));
If nnz(in1)>0 or nnz(in2)>0 then you have an intersection! Visualise it using scatter:
hold on
scatter(R2rotated(:,1), R2rotated(:,2), '.b')
scatter(R2rotated(in2,1), R2rotated(in2,2), 'xc')
scatter(R1rotated(:,1), R1rotated(:,2), '.r')
scatter(R1rotated(in1,1), R1rotated(in1,2), 'xg')
Result:

Remove overlapped Circles in MATLAB [duplicate]

This question already has answers here:
Non overlapping randomly located circles
(4 answers)
Closed 5 years ago.
I have written a MATLAB code to be able to visualize some Circles. Please have a look at my below code and the attached figure as the output.
clc;
clear;
close all;
% X and Y of each Center
Xloc = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5];
Yloc = [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5];
% Radius of each circle
radius = unifrnd(0,1,[1 numel(Xloc)]);
% Random colours
allColours = rand(numel(Xloc),3);
% Transform the data into position = [left bottom width height]
pos = [Xloc(:)-radius(:) Yloc(:)-radius(:) 2*radius(:)*[1 1]];
% Create and format the axes
H = axes;
hold on;
axis equal;
box on;
set(H,'XTickLabel',[],'YTickLabel',[]);
% Create the circles
for idx = 1:numel(Xloc);
rectangle(...
'Position',pos(idx,:),...
'Curvature',[1 1],...
'FaceColor',allColours(idx,:),...
'EdgeColor','none');
end
The output figure is (Circles' radius is generated randomly, so if you execute the code, you will face with a new output):
As you can see in the figure, there is overlap between circles. I was wondering how can I separate centers from each other to do not overlap each others, and at the same time they keep the original distance (or similar distance) from each other in [Xloc Yloc]
You can try to formulate an optimisation problem:
You have to constrain the minimal distance between the centers based on the desired radii.
You have to minimise the deviations from its desired center location.

Detecting almost surrounded background areas [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm doing image processing on tribological samples. I'm segmenting the wear track from the images, but have a recurring problem:
Setting the threshold too low leads to a complete failure. Setting it too high (as in the image) leads to multiple areas that are almost but not quite enveloped by the label. They mess up the distance transform I'm using to estimate track width, and should be detected and merged to the label.
I have used morphological operations to improve the quality of the label, but do not wish to make the structuring elements bigger due to some side effects in the rest of the image. The curvature of the label prevents me from using convex hulls. The bulk of the label prevents me from using the solidity of the label as an indicator. The unwanted interior objects are not enveloped completely by the label, so they can not be detected via the Euler characteristic etc.
Is there any good way to detect background objects that are 'almost completely' surrounded by foreground objects?
I used watershed to divide the background into separate regions and then bwboundaries to detect how much of a region's boundary is shared with the foreground object:
% generate example image
bw = im2double(rgb2gray(imread('example.jpg'))) == 1;
% dilate binary object to overlap watershed boundaries
bwDil = imdilate(bw,ones(5));
% get watershed labels
D = bwdist(bw);
D = -D;
D(bw) = -Inf;
L = watershed(D);
% get binary regions and remove fg object
R = (L > 0);
R(bw) = 0;
% get boundaries of all regions
BR = bwboundaries(R);
% set boundary ratio - if a regio's shares more boundary with fg object
% than this threshold it considered surrounded
boundaryRatio = zeros(numel(BR),1);
ratioThresh = 0.6;
mask = false(size(bw));
% go through region boundaries and add them to mask if above tresh
for ii = 1:numel(BR)
ind = sub2ind(size(bw),BR{ii}(:,1),BR{ii}(:,2));
boundaryRatio(ii) = nnz(bwDil(ind))/numel(ind);
if boundaryRatio(ii) > ratioThresh
mask(ind) = 1;
end
end
% fill mask
mask = imfill(mask,4,'holes');
% plot
subplot(121);
imshow(bw);
title('fg')
rgb = double(cat(3,mask,bw,bw));
subplot(122);
imshow(rgb);
title('fg with surrounded bg')

detecting finger valleys with Matlab [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have a binary image of the hand like that:
I have to write a Matlab function that detects the valley between two fingers.
The parameters are the binary image and the coordinates of the two finger's tips.
I'm new in image processing and I don't know how to start.
I suggest to isolate the black area between the two input points, and then find the highest point in this connected component.
You can try the following approach (you may need to tweak some of the parameters, but it should be a good start).
I = rgb2gray(imread('<your path>'));
%input parameters - points which represents two finger tips.
x1 = 408; y1 = 441;
x2 = 454; y2 = 373;
%binarize image
I = im2bw(I);
%noise reduction - close holes
I2 = imclose(I,strel('disk',10));
%draw a line between p1 and p2
ind = drawline([y1 x1],[y2 x2],size(I));
lineMat = zeros(size(I));
lineMat(ind) = 1;
%adds the line to the image
I2 = I2 | lineMat;
%finds a point in the middle of the line
[lineY, lineX] = ind2sub(size(I),ind);
midX = lineX(ceil(length(ind)/2));
midY = lineY(ceil(length(ind)/2));
%finds a point which resides in the connected component which is between
%the line and the two finger.
xSeed = midX;
ySeed = midY -5;
%perform imfill operation, starting from (xSeed,ySeed),
%in order to find the conected component in which the point (xSeed,ySeed)
%resides.
diffMat = imfill(I2,[ySeed xSeed])~=I2;
%finding the highest point in this connected component
[Y, X] = ind2sub(size(diffMat),find(diffMat));
minInd = find(Y==min(Y),1,'first');
yValley = Y(minInd);
xValley = X(minInd);
%presents result
imshow(I);hold on;
plot(x1,y1,'r.','MarkerSize',20);
plot(x2,y2,'r.','MarkerSize',20);
plot(xValley,yValley,'b.','MarkerSize',20);
*draw line function is taken from drawline webpage.
Final result (input points in red, output point in blue).
It's just the algorithm, but all these function certainly exist in MatLab:
Compute the convex hull
Compute the difference: Convex Hull minus the original shape. Then you have all the valleys you are looking for, plus some small patterns.
Connected components labeling.
Delete the small components. Then you have all the valleys between the fingers.
Then you can select the one you want using the fingertip coordinates.

Count black pixels within a circle [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have one vector of radii and second vector of hundreds of [X,Y] coordinates. For each possible coordinate-radius pair I have count all black pixels within a circle (whose center is placed in the coordinate) on an input binary image.
What is the fastest way to do it? My only idea is to iterate through every pixel of an image, check the circle equation and then the pixel color but it doesn't seem much optimized for several hundred such operations.
Matlab is great for working with images thanks to the matrix syntax. It does also work with indices so most time you can avoid "iterating through pixels" (although sometimes you'll still have to).
Instead of checking all the pixels within each circle, and having to detect how many pixels were counted twice, another approach is to create a mask, the same size of you image. Blank this mask for each of your circles (so overlapping pixels are only 'blanked' once), then apply the mask on your original picture and count the remaining illuminated pixels.
For an example, I have to take some sample data, the image:
load trees
BW = im2bw(X,map,0.4);
imshow(BW)
And 20 random point/circle coordinates (you can change the number of points and the min/max radii easily):
%// still building sample data
s = size(BW) ;
npt = 20 ; Rmin=5 ; Rmax=20 ; %// problem constants
x = randi([1 s(2)] ,npt,1); %// random X coordinates
y = randi([1 s(1)] ,npt,1); %// Y
r = randi([Rmin Rmax],npt,1); %// radius size between 5 to 20 pixels.
Then we build your custom mask :
%// create empty mask with enough overlap for the circles on the border of the image
mask = false( s+2*Rmax ) ;
%// prepare grid for a sub-mask of pixels, as wide as the maximum circle
xmask = -Rmax:Rmax ;
[xg,yg] = ndgrid(xmask,xmask) ;
rg = sqrt( (xg.^2+yg.^2) ) ; %// radius of each pixel in the subgrid
for ip=1:npt
mrow = xmask+Rmax+y(ip) ; %// calc coordinates of subgrid on original mask
mcol = xmask+Rmax+x(ip) ; %// calc coordinates of subgrid on original mask
cmask = rg <= r(ip) ; %// calculate submask for this radius
mask(mrow,mcol) = mask(mrow,mcol) | cmask ; %// apply the sub-mask at the x,y coordinates
end
%// crop back the mask to image original size (=remove border overlap)
mask = mask(Rmax+1:end-Rmax,Rmax+1:end-Rmax) ;
imshow(mask)
Then you just apply the mask and count :
%% // Now apply on original image
BWm = ~BW & mask ; %// note the ~ (not) operator because you want the "black" pixels
nb_black_pixels = sum(sum(BWm)) ;
imshow(BWm)
nb_black_pixels =
5283
Here is one implementation:
Advantages:
No loops, meshgrid/ndgrid. Instead used faster bsxfun and pdist2
Dots are counted only once, even when the circles overlap.
Variable radius used (radius of all circle is not same)
Code:
%// creating a binary image with little black dots
A = randi(600,256);
imbw = A ~= 1;
%// Your binary image with black dots
imshow(imbw);
%// getting the index of black dots
[dotY, dotX] = find(~imbw);
nCoords = 10; %// required number of circles
%// generating its random coordinates as it is unknown here
Coords = randi(size(A,1),nCoords,2);
%// calculating the distance from each coordinate with every black dots
out = pdist2(Coords,[dotX, dotY]).'; %//'
%// Getting only the black dots within the radius
%// using 'any' avoids calculating same dot twice
radius = randi([10,25],1,size(Coords,1));
pixelMask = any(bsxfun(#lt, out, radius),2);
nPixels = sum(pixelMask);
%// visualizing the results by plotting
hold on
scatter(dotX(pixelMask),dotY(pixelMask));
viscircles([Coords(:,1),Coords(:,2)],radius.'); %//'
hold off
Output:
>> nPixels
nPixels =
19