In the script below I outline an object but in the final plot I have noticed that the left bottom of the plot is not 0,0. How can I fix it in the plot and also the X/Ycoord data?
Code:
clc
clear
close all
Iorig = imread('E:/drop.jpg');
I = rgb2gray(Iorig);
axis on
imshow(I)
T = adaptthresh(I, 0.65);
BW = imbinarize(I,T);
BW2 = imcomplement(BW);
BW2 = imfill(BW2, 'holes');
axis on
hold on;
[B,L] = bwboundaries(BW2,'noholes');
boundary = B{1};
Xcoord = boundary(:,2);
Ycoord = boundary(:,1);
plot(Xcoord, Ycoord, 'g', 'LineWidth', 2)
You can flip they y-axis using
set(gca,'YDir','normal')
Related
In Matlab the image axes are shown as rows and columns (matrix style) which flip/cause the Y axis to start from the upper left corner. In the script below, I divide an outline to equally distance points using interparc (File Exchange link).
I wish to convert/adjust the calculated Y coordinates of the selected points so they will start from the “graph point of origin” (0,0; lower left corner) but without flipping the image. Any idea how to do this coordinates conversion?
Code:
clc;
clear;
close all;
readNumPoints = 8
numPoints = readNumPoints+1
url='https://icons.iconarchive.com/icons/thesquid.ink/free-flat-sample/512/owl-icon.png';
I = imread(url);
I = rgb2gray(I);
imshow(I);
BW = imbinarize(I);
BW = imfill(BW,'holes');
hold on;
[B,L] = bwboundaries(BW,'noholes');
k=1;
stat = regionprops(I,'Centroid');
b = B{k};
c = stat(k).Centroid;
y = b(:,2);
x = b(:,1);
plot(y, x, 'r', 'linewidth', 2);
pt = interparc(numPoints,x,y,'spline');
py = pt(:,2);
px = pt(:,1);
sz = 150;
scatter(py,px,sz,'d')
str =1:(numPoints-1);
plot(py, px, 'g', 'linewidth', 2);
text(py(1:(numPoints-1))+10,px(1:(numPoints-1))+10,string(str), 'Color', 'b');
pointList = table(py,px)
pointList(end,:) = []
You will need to flip the display direction of y-axis (as #If_You_Say_So suggested in the comment).
set(gca,'YDir','normal')
Y-axis is now pointing upward, but the image is displayed upside down. So we flip the y-data of the image as well.
I=flipud(I);
The image is flipped twice and is thus upright.
The data should be flipped before you plot it or do any calculation based on it. The direction of y-axis can be flipped later when you show the image or plot the outline.
url='https://icons.iconarchive.com/icons/thesquid.ink/free-flat-sample/512/owl-icon.png';
I = imread(url);
I = rgb2gray(I);
% Flip the data before `imshow`
I=flipud(I);
imshow(I);
% Flip the y-axis display
set(gca,'YDir','normal')
pointList =
py px
______ ______
1 109
149.02 17.356
362.37 20.77
512 113.26
413.99 270.84
368.89 505.99
141.7 508
98.986 266.62
Given two coordinate points A and B and its gradient 'slopes'. Now, I want to draw a line (with linspace - function) on an image which worked for lines with a gradient ~1. The line stopped at the image boundary (due to xlims and ylims).
imshow(I)
xlims = xlim(gca);
ylims = ylim(gca);
Now the problem: I try to repeat for another line which is nearly vertical and it did not stop at the image boundary (see picture):
Any solutions how I can draw a line using a y=mx+c equation that stops at the image boundary independent from the gradient?
EDIT:
img = uint8(zeros(382, 382));
pointA = [181.4594, 129.7092];
pointB = [185.3411, 251.6005];
imshow(img)
hold on
plot(pointA(1), pointA(2), 'ro')
plot(pointB(1), pointB(2), 'bo')
hold off
% From y = mx + x
slope = 31.4015;
intercept = -5.5684e+03;
xlims = xlim(gca);
ylims = ylim(gca);
y = xlims*slope + intercept;
Xline = linspace(xlims(1), xlims(2), 382);
Xline_pole1 = linspace(xlims(1), pointA(1), 382/2);
Xline_pole2 = linspace(xlims(2), pointB(1), 382/2);
Yline = Xline*slope + intercept;
Yline_pole1 = Xline_pole1*slope + intercept;
Yline_pole2 = Xline_pole2*slope + intercept;
hold on
plot( Xline_pole1, Yline_pole1, 'Color', 'b', 'LineWidth', 3 );
hold off
% Check how many coordinates are within image frame
for zz=1:length(Xline_pole1)
hold on
plot(Xline_pole1(zz),Yline_pole1(zz), 'm+');
end
Easy workaround:
Just reset your limits after you plotted your lines
imshow(I)
xlims = xlim(gca);
ylims = ylim(gca);
% plot your lines
xlim(xlims)
ylim(ylims)
I found this script below in https://blogs.mathworks.com/steve/2010/07/30/visualizing-regionprops-ellipse-measurements/
I wish to plot also the MajorAxisLength and the MinorAxisLength, how can I do it?
Script:
url = 'https://blogs.mathworks.com/images/steve/2010/rice_binary.png';
bw = imread(url);
imshow(bw)
s = regionprops(bw, 'Orientation', 'MajorAxisLength', ...
'MinorAxisLength', 'Eccentricity', 'Centroid');
imshow(bw)
hold on
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
hold off
You have a lot of unnecessary code in what you posted. I don't think you actually attempted to adjust it for what you say you want to plot. Given what you said you are trying to do in the comments, I think this is the code you want in order to plot the Major Axis Length vs. Minor Axis Length
url = 'https://blogs.mathworks.com/images/steve/2010/rice_binary.png';
bw = imread(url);
s = regionprops(bw, 'Orientation', 'MajorAxisLength', ...
'MinorAxisLength', 'Eccentricity', 'Centroid'); %Get region props
Major=zeros(size(s));
Minor=zeros(size(s));
for k = 1:length(s)
Major(k)= s(k).MajorAxisLength; %get your y values
Minor(k)= s(k).MinorAxisLength; %get your x values
end
figure %create a new figure because you don't want to plot on top of the image
plot(Minor, Major, 'o') %plot
xlabel('Minor Axis Length')
ylabel('Major Axis Length')
I want to get the convex hull of hand palm by using convhull() function. I am working on an image which is having only a hand palm in it. First I converted it to a binary image and then I applied convhull function. But it is not giving me the desired result. Kindly find the bug in my code. Here is my code:
thresh1 = 0;
thresh2 = 20;
image = imread('C:\Users\...\1_depth.png');
subplot(3,3,1)
imshow(image)
image_bin1 = (image < thresh2);
image_bin2 = (thresh1 < image);
image_bin = abs(image_bin2- image_bin1);
image_bin_filt = medfilt2(image_bin, [18,18]);
subplot(3,3,2)
imshow(imcomplement(image_bin_filt));
BW = im2bw(image_bin_filt, 0.5);
BW = imcomplement(BW);
subplot(3,3,3)
imshow(BW)
title('Binary Image of Hand');
BW2 = bwareaopen(BW, 1000);
subplot(3,3,4)
imshow(BW2)
[y,x] = find(BW2);
k = convhull(x,y);
subplot(3,3,5)
imshow(BW2,'InitialMagnification', 'fit')
hold on;
plot(x,y, 'b.')
plot(x(k), y(k), 'r', 'LineWidth', 2)
title('Objects Convex Hull');
% Find centroid.
labeledImage = bwlabel(BW2);
measurements = regionprops(labeledImage, 'Centroid', 'BoundingBox');
%xCentroid = measurements.Centroid(1);
% yCentroid = measurements.Centroid(2);
centroids = cat(1, measurements.Centroid);
subplot(3, 3, 6);
imshow(BW2);
title('Binary Image with Centroid Marked', 'FontSize', 12);
hold on;
plot(centroids(:,1),centroids(:,2), 'b*')
% Crop the image and display it in a new figure.
boundingBox = measurements.BoundingBox;
croppedImage = imcrop(BW2, boundingBox);
% Get rid of tool bar and pulldown menus that are along top of figure.
%set(gcf, 'Toolbar', 'none', 'Menu', 'none');
subplot(3,3,7)
imshow(croppedImage, []);
title('Cropped Image', 'FontSize', 12, 'Interpreter', 'None');
% Again trying to plot the convex hull
CH_objects = bwconvhull(BW);
subplot(3,3,8)
imshow(CH_objects);
title('Objects Convex Hull');
[r,c]=find(CH_objects);
CH=convhull(r,c);
subplot(3,3,9)
imshow(CH_objects)
hold on;
plot(r(CH),c(CH),'*-');
Here is the result of the code I am getting: https://ibb.co/gLZ555
But it is not the desired result. The convex hull is not proper, it should include only palm and not free space. Also, I am getting two centroids instead of one. Why it is so?
Input image I used is: https://ibb.co/hk28Q5
I want to calculate convex hull of palm containing only palm in it and then want to calculate centroid of the palm. It will be helpful in detecting palm shape.
Kindly reply with the solution for the desired output.
Do you mean the image should contain only palm which is with white pixles, not the black pixles. If it is so then you need to crop the image by considering largest blob area as extracted by 'regionprops'. Then apply convexhull on that only.
I just added this piece of code before applying convhull() and it solved my problem.
roi = regionprops(BW2, 'Area');
BW2 = bwareafilt(BW2,1);
subplot(3,3,5)
imshow(BW2)
I labeled an image using CC = bwconncomp(BW); and masking the label with maximum area using code
numPixels = cellfun(#numel,CC.PixelIdxList);
[biggest,idx] = max(numPixels);
BW(CC.PixelIdxList{idx}) = 0;
Now I want to put thin rectangular box around that maximum area instead of masking it. How it can be done?
Full Code:
f = imread('test.PNG');
subplot(2,2,1); imshow(f,[]); title('Original Image');
for i = 1:3
Image = medfilt2(Image,[3 3]);
end
[Image_Num, num] = bwlabel(Image,8);
subplot(2,2,3); imshow(Image); title('after median filtering'); %labeling algorithm
BW=im2bw(Image);
subplot(2,2,4); imshow(BW); title('binary image');
CC = bwconncomp(BW); %area based segmentation
numPixels = cellfun(#numel,CC.PixelIdxList);
[biggest,idx] = max(numPixels);
BW(CC.PixelIdxList{idx}) = 0;
figure;
imshow(BW); title('AFTER AREA BASED MASKING');
You can use bwlabel with regionprops and rectangle annotation:
lb = bwlabel( bw ); %// label each CC
st = regionprops( lb, 'Area', 'BoundingBox' ); %// get area and bounding box for each region
[mxa mxi] = max( [st.Area] ); %// find max area region
Now you can annotate
figure;
imshow( bw ); hold on;
rectangle('Position', st(mxi).BoundingBox, 'EdgeColor', 'r' );
On the 'coins.png' image this results with:
CC.PixelIdxList{idx} will give you the linear indices of the locations in the image of where your object is located.
What you can do is use ind2sub to convert the linear indices to row and column locations, then we can determine the top left and bottom right corner of these row and column indices. Once we do this, we can thus mark your image accordingly.
Therefore:
%// Determine row and column locations
[row,col] = ind2sub(size(BW), CC.PixelIdxList{idx});
%// Get top left and bottom right coordinates
topleft_row = min(row);
topleft_col = min(col);
bottomright_row = max(row);
bottomright_col = max(col);
%// Draw a white box around the object
%// Left vertical line
BW(topleft_row:bottomright_row, topleft_col) = true;
%// Right vertical line
BW(topleft_row:bottomright_row, bottomright_col) = true;
%// Top horizontal line
BW(topleft_row, topleft_col:bottomright_col) = true;
%// Bottom horizontal line
BW(bottomright_row, topleft_col:bottomright_col) = true;
Here's an example using coins.png that's built-in to MATLAB. I read in the image, threshold it and fill in the holes.
im = imread('coins.png');
BW = im2bw(im, graythresh(im));
BW = imfill(O, 'holes');
When I do that and run the above code to draw a rectangle around the largest object, this is what I get:
Where this code ties into your program, don't do any masking. Replace the masking code with the above... so:
f = imread('test.PNG');
subplot(2,2,1); imshow(f,[]); title('Original Image');
for i = 1:3
Image = medfilt2(Image,[3 3]);
end
[Image_Num, num] = bwlabel(Image,8);
subplot(2,2,3); imshow(Image); title('after median filtering'); %labeling algorithm
BW=im2bw(Image);
subplot(2,2,4); imshow(BW); title('binary image');
CC = bwconncomp(BW); %area based segmentation
numPixels = cellfun(#numel,CC.PixelIdxList);
[biggest,idx] = max(numPixels);
%-------- CHANGE HERE
%// Determine row and column locations
[row,col] = ind2sub(size(BW), CC.PixelIdxList{idx});
%// Get top left and bottom right coordinates
topleft_row = min(row);
topleft_col = min(col);
bottomright_row = max(row);
bottomright_col = max(col);
%// Draw a white box around the object
%// Left vertical line
BW(topleft_row:bottomright_row, topleft_col) = true;
%// Right vertical line
BW(topleft_row:bottomright_row, bottomright_col) = true;
%// Top horizontal line
BW(topleft_row, topleft_col:bottomright_col) = true;
%// Bottom horizontal line
BW(bottomright_row, topleft_col:bottomright_col) = true;