Inscribe circle of an object rotated results - Matlab - matlab

I modified a code based on the shown in https://www.mathworks.com/matlabcentral/answers/377838-please-how-can-i-find-the-center-and-the-radius-of-the-inscribed-circle-of-a-set-of-points in order to find the inscribe circle but I do not understand why the image is rotated. Why and how can I solve it?
Code:
url='https://i.pcmag.com/imagery/reviews/00uaCVfzQ4Gsuhmh85WvT3x-4.fit_scale.size_1028x578.v_1569481686.jpg';
Image = rgb2gray(imread(url));
Image = imcomplement(Image);
fontSize = 10;
% determine contours
BW = imbinarize(Image);
BW = imfill(BW,'holes');
[B,L] = bwboundaries(BW,'noholes');
k = 1;
b = B{k};
y = b(:,2);
x = b(:,1);
subplot(2, 2, 1);
plot(x, y, 'b.-', 'MarkerSize', 3);
grid on;
title('Original Points', 'FontSize', fontSize);
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0, 0.04, 1, 0.96]);
% Make data into a 1000x1000 image.
xMin = min(x)
xMax = max(x)
yMin = min(y)
yMax = max(y)
scalingFactor = 1000 / min([xMax-xMin, yMax-yMin])
x2 = (x - xMin) * scalingFactor + 1;
y2 = (y - yMin) * scalingFactor + 1;
mask = poly2mask(x2, y2, ceil(max(y2)), ceil(max(x2)));
% Display the image.
p2 = subplot(2, 2, 2);
imshow(mask);
axis(p2, 'on', 'xy');
title('Mask Image', 'FontSize', fontSize);
% Compute the Euclidean Distance Transform
edtImage = bwdist(~mask);
% Display the image.
p3 = subplot(2, 2, 3);
imshow(edtImage, []);
axis(p3, 'on', 'xy');
% Find the max
radius = max(edtImage(:))
% Find the center
[yCenter, xCenter] = find(edtImage == radius)
% Display circles over edt image.
viscircles(p3, [xCenter, yCenter], radius,'Color','g');
% Display polygon over image also.
hold on;
plot(x2, y2, 'r.-', 'MarkerSize', 3, 'LineWidth', 2);
title('Euclidean Distance Transform with Circle on it', 'FontSize', fontSize);
% Display the plot again.
subplot(2, 2, 4);
plot(x, y, 'b.-', 'MarkerSize', 3);
grid on;
% Show the circle on it.
hold on;
% Scale and shift the center back to the original coordinates.
xCenter = (xCenter - 1)/ scalingFactor + xMin
yCenter = (yCenter - 1)/ scalingFactor + yMin
radius = radius / scalingFactor
rectangle('Position',[xCenter-radius, yCenter-radius, 2*radius, 2*radius],'Curvature',[1,1]);
title('Original Points with Inscribed Circle', 'FontSize', fontSize);
Original image:
Output image

[B,L] = bwboundaries(BW,...) returns in B the row and column values (documentation). That is, the first column of B{k} is y, the second one is x.
After changing this bit of code as follows:
y = b(:,1);
x = b(:,2);
you will notice that the image is upside down! That is because in an image the y-axis increases down (y is the row number in the matrix), whereas in the plot the y-axis increases up (mathematical coordinate system).
The axes where you use imshow in are automatically set to the right coordinate system, but then you do axis(p3, 'on', 'xy');, turning it upside down again. Instead, use
axis(p1, 'on', 'image');
on the axes where you don't use imshow (i.e. the top-left and bottom-right ones).

Related

How do i obtain a cross section from a 3D volume?

I want to obtain a 2D slice from the 3D volume in the example (slightly modified) How do I resolve this issue with 3D image visualization? as follows:
% create input image
imageSizeX = 10;
imageSizeY = 10;
imageSizeZ = 10
% generate 3D grid using voxel size = 0.5
[Xq, Yq, Zq] = ndgrid(1:0.5:imageSizeX-1, 1:0.5:imageSizeY-1, 1:0.5:imageSizeZ-1);
% obtain coordinates of all internal vertices, faces, and edges
allCoords = [Xq(:), Yq(:), Zq(:)]; % i need this bit for something very important but not shown in the question.
% Re-generate 3D grid using voxel size = 1
[columnsInImage, rowsInImage, pagesInImage] = ndgrid(1: imageSizeX-1, 1: imageSizeY-1, 1: imageSizeZ-1);
% create the sphere in the image.
centerY = imageSizeY/2;
centerX = imageSizeX/2;
centerZ = imageSizeZ/2;
diameter = 4;
radius = diameter/2;
sphereVoxels = flipud((rowsInImage - centerY).^2 ...
+ (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2);
% change image from logical to numeric labels.
Img = double(sphereVoxels);
for ii = 1:numel(Img)
if Img(ii) == 0
Img(ii) = 2; % intermediate phase voxels
end
end
% specify the desired angle
angle = 30;
% specify desired pixel height and width of solid
width = imageSizeX;
height = imageSizeY;
page = imageSizeZ;
% Find the row point at which theta will be created
y = centerY - ( radius*cos(angle * pi/180) )
% determine top of the solid bar
y0 = max(1, y-height);
% label everything from y0 to y to be = 3 (solid)
Img(1:width, y0:y, 1:page)=3;
%%%%%% Plot the surfaces
[X, Y, Z, C] = build_voxels(Img > 0);
hSurface = patch(X, Y, Z, Img(C),...
'AmbientStrength', 0.5, ...
'BackFaceLighting', 'unlit', ...
'EdgeColor', 'none', ...
'FaceLighting', 'flat');
colormap([1 0 0; 1 1 0]);
axis equal;
axis tight;
view(45, 45);
grid on;
xlabel('x-axis (voxels)');
ylabel('y-axis (voxels)');
zlabel('z-axis (voxels)');
light('Position', get(gca, 'CameraPosition'), 'Style', 'local');
zoom on;
hold on;
Vq = griddata(columnsInImage, rowsInImage, pagesInImage, Img, Xq, Yq, Zq);
figure
h1 = slice(permute(Xq, [2 1 3]),permute(Yq, [2 1 3]),permute(Zq, [2 1 3]), Vq, 5,2,5);
When i run the code, i get an Error message:
"The number of data point locations should equal the number of data point values.
Error in griddata>useScatteredInterp (line 188)
F = scatteredInterpolant(inargs{1}(:),inargs{2}(:),inargs{3}(:), ..."
I want to believe this is so because the size of columnsInImage and size of pagesInImage are not equal to size(P,1) and size(P,3), respectively.
Nonetheless, I also tried to use a vector as follows:
figure
h1 = slice(Img(:,1), Img(:,2), Img(:,3), Img, 5,2,5);
I however still end up with the error message:
"Error using griddedInterpolant
The grid was created from grid vectors that were not strictly monotonic increasing.
Error in interp3 (line 142)
F = griddedInterpolant(X, Y, Z, V, method,extrap);"
Please, guys i need suggestions/ideas on how i could remedy these. Many thanks in advance!..

Draw a circle around the recognized image in Matlab

I have a reference picture and i want to draw a circle around a picture that exists in the reference picture.
Now it draw a rectangle over the picture that exists in the reference picture but i don't know how to make it circle.
boxImage = imread('RefImg.jpg');
sceneImage = imread('full_image.jpg');
boxPoints = detectSURFFeatures(rgb2gray(boxImage));
scenePoints = detectSURFFeatures(rgb2gray(sceneImage));
[boxFeatures, boxPoints] = extractFeatures(rgb2gray(boxImage), boxPoints);
[sceneFeatures, scenePoints] = extractFeatures(rgb2gray(sceneImage), scenePoints);
boxPairs = matchFeatures(boxFeatures, sceneFeatures);
matchedBoxPoints = boxPoints(boxPairs(:, 1), :);
matchedScenePoints = scenePoints(boxPairs(:, 2), :);
figure;
showMatchedFeatures(rgb2gray(boxImage),rgb2gray(sceneImage), matchedBoxPoints, ...
matchedScenePoints, 'montage');
title('Putatively Matched Points (Including Outliers)');
[tform, inlierBoxPoints, inlierScenePoints] = ...
estimateGeometricTransform(matchedBoxPoints, matchedScenePoints, 'affine');
figure;
showMatchedFeatures(rgb2gray(boxImage), rgb2gray(sceneImage), inlierBoxPoints, ...
inlierScenePoints, 'montage');
title('Matched Points (Inliers Only)');
boxPolygon = [1, 1;... % top-left
size(boxImage, 2), 1;... % top-right
size(boxImage, 2), size(boxImage, 1);... % bottom-right
1, size(boxImage, 1);... % bottom-left
1, 1]; % top-left again to close the polygon
newBoxPolygon = transformPointsForward(tform, boxPolygon);
figure;
imshow(sceneImage);
hold on;
line(newBoxPolygon(:, 1), newBoxPolygon(:, 2), 'Color', 'y');
title('Detected Box');
Thanks,
You can use rectangle to actually draw an ellipse around your object of interest by using the Curvature parameter.
%// Transform your points
boxCorners = [1, 1; size(boxImage, 2), size(boxImage, 1)];
box = transformPointsForward(tform, boxCorners);
%// Position as [x, y, width, height]
position = [boxCorners(1,:), diff(boxCorners)];
%// Display the image
imshow(sceneImage);
hold on
%// Plot an ellipse at this location
rectangle('Position', position, 'Curvature', [1 1])
If you want to enforce an actual circle, you will want the diameter to be the diagonal distance across the rectangle and the center to be the midpoint of the diagonal of the rectangle.
boxCorners = [1, 1; size(boxImage, 2), size(boxImage, 1)];
box = transformPointsForward(tform, boxCorners);
%// Now compute the diagonal distance (diameter)
diameter = sqrt(sum(diff(box).^2));
%// Now determine the middle of the circle
center = mean(box);
%// Display the image
imshow(sceneImage);
hold on
%// Now plot the circle
t = linspace(0, 2*pi, 100);
plot(center(1) + cos(t) * diameter/2, ...
center(2) + sin(t) * diameter/2);

Matlab scatter and histogram plot

I have 20 numerical data points with x and y coordinates. I would like to plot them in a 2D plot. They will be concentrated around an x and y coordinate. To better visualise this behaviour, I would like to add histogram bars on top of the 2D scatter plot for the x axis, and histogram bars on the right of the 2D plot for the y axis this way, they do not interfere with the axis labels. Now, my 20 numerical points are in fact two sets of 10 and I would like to have both sets plotted in different colours. Something like this:
python plot
How can I do this?
Update:
FWHM11Avg = [3.88,3.43,3.16,3.22,3.73,2.43,2.88,3.01,3.59,2.17];
FWHM11Med = [4.4,3.1,3,3.15,3.9,2,3.00,2.85,3.85,2.2];
FWHM12Avg = [3.50,2.30,2.97,2.97,2.98,2.28,2.94,2.36,3.51,1.7];
FWHM12Med = [3.3,2.1,2.9,2.8,2.9,2.1,2.8,2.30,3.5,1.7];
minx = min([FWHM11Avg; FWHM11Med]);
maxx = max([FWHM11Avg; FWHM11Med]);
miny = min([FWHM12Avg; FWHM12Med]);
maxy = max([FWHM12Avg; FWHM12Med]);
% make figure
figure(1)
clf
% first subplot -- y-data histc
ah1 = subplot(2, 2, 1);
y_bins = 1.5:.25:4.5;
n = hist(FWHM12Avg, y_bins);
bar(y_bins, n, 'vertical', 'on')
hold on
hist(FWHM12Med, y_bins)
bar(y_bins, n, 'vertical', 'on')
% x-data histc
ah2 = subplot(2, 2, 4);
x_bins = 1.5:.25:4.5;
n = hist(FWHM11Avg, x_bins);
bar(x_bins, n, 'horizontal', 'on')
hold on
n = hist(FWHM11Med, x_bins);
bar(x_bins, n, 'horizontal', 'on')
% scatterplot
ah3 = subplot(2, 2, 2);
hold on
scatter(FWHM11Avg, FWHM11Med)
scatter(FWHM12Avg, FWHM12Med)
% link axes, adjust histc orientation
linkaxes([ah1, ah3], 'y')
linkaxes([ah3, ah2], 'x')
set(ah3,'XLim',[minx, maxx]);
set(ah3,'YLim',[miny, maxy]);
ah1.Box = 'off';
ah1.View = [180, -90];
ah1.Visible = 'off';
ah2.Visible = 'off';
ah2.Box = 'off';
ah2.View = [0, -90];
Also there seems not to be an option available for adding numerical axes to the histograms to see how many points there are in a bar - at least in the documentation I did not see any option. Is that so?
Second Update with applied suggestions to the above syntax:
FWHM11Avg = [3.88,3.43,3.16,3.22,3.73,2.43,2.88,3.01,3.59,2.17];
FWHM11Med = [4.4,3.1,3,3.15,3.9,2,3.00,2.85,3.85,2.2];
FWHM12Avg = [3.50,2.30,2.97,2.97,2.98,2.28,2.94,2.36,3.51,1.7];
FWHM12Med = [3.3,2.1,2.9,2.8,2.9,2.1,2.8,2.30,3.5,1.7];
minx = min([FWHM11Avg; FWHM11Med]);
maxx = max([FWHM11Avg; FWHM11Med]);
miny = min([FWHM12Avg; FWHM12Med]);
maxy = max([FWHM12Avg; FWHM12Med]);
% make figure
figure(1)
clf
% first subplot -- y-data histc
ah1 = subplot(2, 2, 1);
y_bins = 1.5:.25:4.5;
n = hist(FWHM12Avg, y_bins);
bar(y_bins, n, 'vertical', 'on')
hold on
hist(FWHM12Med, y_bins)
bar(y_bins, n, 'vertical', 'on')
% x-data histc
ah2 = subplot(2, 2, 4);
x_bins = 1.5:.25:4.5;
n = hist(FWHM11Avg, x_bins);
bar(x_bins, n, 'horizontal', 'on')
hold on
n = hist(FWHM11Med, x_bins);
bar(x_bins, n, 'horizontal', 'on')
% scatterplot
ah3 = subplot(2, 2, 2);
hold on
scatter(FWHM11Avg, FWHM11Med)
scatter(FWHM12Avg, FWHM12Med)
% link axes, adjust histc orientation
linkaxes([ah1, ah3], 'y')
linkaxes([ah3, ah2], 'x')
set(ah3,'XLim',[minx, maxx]);
set(ah3,'YLim',[miny, maxy]);
set(ah1,'Box','off');
set(ah1,'View',[180, -90]);
set(ah1,'Visible','off');
set(ah2,'Visible','off');
set(ah2,'Box','off');
set(ah2,'View',[0, -90]);
Please research before asking. There is a function in Matlab scatterhist which does this
x0 = 6.1;
y0 = 3.2;
n = 50;
r = rand(n ,1 );
theta = 2*pi*rand(n, 1);
x = x0 + r.*cos(theta);
y = y0 + r.*sin(theta);
scatterhist(x,y, 'Direction','out', 'Location', 'NorthEast')
Edit: Using the data you provided. Is this what you want?
FWHM11Avg = [3.88,3.43,3.16,3.22,3.73,2.43,2.88,3.01,3.59,2.17];
FWHM11Med = [4.4,3.1,3,3.15,3.9,2,3.00,2.85,3.85,2.2];
FWHM12Avg = [3.50,2.30,2.97,2.97,2.98,2.28,2.94,2.36,3.51,1.7];
FWHM12Med = [3.3,2.1,2.9,2.8,2.9,2.1,2.8,2.30,3.5,1.7];
% make figure
figure(1)
clf
FWHM11Avg = FWHM11Avg(:);
FWHM11Med = FWHM11Med(:);
FWHM12Avg = FWHM12Avg(:);
FWHM12Med = FWHM12Med(:);
minX = min([FWHM11Avg; FWHM12Avg]);
maxX = max([FWHM11Avg; FWHM12Avg]);
minY = min([FWHM11Med; FWHM12Med]);
maxY = max([FWHM11Med; FWHM12Med]);
resX = 0.25;
resY = 0.25;
nBinsX = ceil((maxX - minX) / resX);
nBinsY = ceil((maxY - minY) / resY);
label = vertcat( ...
num2cell(repmat('FWHM11', size(FWHM11Avg)),2), ...
num2cell(repmat('FWHM12', size(FWHM11Avg)),2));
Avg = vertcat(FWHM11Avg, FWHM12Avg);
Med = vertcat(FWHM11Med, FWHM12Med);
% scatterplot
scatterhist(Avg, Med, 'Group', label, 'Direction','out', ...
'Location', 'NorthEast', 'NBins', [nBinsX, nBinsY])
This is something I've been using lately:
% generate some random data
mu = [1 2];
sigma = [1 0.5; 0.5 2];
R = chol(sigma);
my_data1 = repmat(mu,100,1) + randn(100,2)*R;
mu = [2 1];
sigma = [3 -0.5; -0.5 2];
R = chol(sigma);
my_data2 = repmat(mu,100,1) + randn(100,2)*R;
% find limits
minx = min([my_data1(:, 1); my_data2(:, 1)]);
maxx = max([my_data1(:, 1); my_data2(:, 1)]);
miny = min([my_data1(:, 2); my_data2(:, 2)]);
maxy = max([my_data1(:, 2); my_data2(:, 2)]);
% make figure
figure(1)
clf
% first subplot -- y-data histogram
ah1 = subplot(2, 2, 1);
histogram(my_data1(:, 2), 'Orientation','horizontal', 'Normalization', 'probability', 'BinWidth', 0.5)
hold on
histogram(my_data2(:, 2), 'Orientation','horizontal', 'Normalization', 'probability', 'BinWidth', 0.5)
% x-data histogram
ah2 = subplot(2, 2, 4);
histogram(my_data1(:, 1), 'Normalization', 'probability', 'BinWidth', 0.5)
hold on
histogram(my_data2(:, 1), 'Normalization', 'probability', 'BinWidth', 0.5)
% scatterplot
ah3 = subplot(2, 2, 2);
hold on
scatter(my_data1(:, 1), my_data1(:, 2))
scatter(my_data2(:, 1), my_data2(:, 2))
% link axes, adjust histogram orientation
linkaxes([ah1, ah3], 'y')
linkaxes([ah3, ah2], 'x')
ah3.XLim = [minx, maxx];
ah3.YLim = [miny, maxy];
ah1.Box = 'off';
ah1.View = [180, -90];
ah1.Visible = 'off';
ah2.Visible = 'off';
ah2.Box = 'off';
ah2.View = [0, -90];
producing this plot
This code assumes a recent version of MATLAB (I use 2014b), but can be easily adapted using the old histogram functions (hist, histc) and the set(..) syntax for graphical objects.

Multi dimensional (2d better 3d) scatter-plot with different errorbars in matlab

I am trying to program scatterplot with specific errorbars. The only build in function i found is
errorbar()
but this only enables me to make a 2d plot with errorbars in y direction. What i am asking for is a method to plot this with errorbars in x and y direction.
At the end my goal is to make a 3D-scatter-plot with 3 errorbars.
Perfect would be if the resulting image would be a 3d-plot with 3d geometric shapes (coordinate x,y,z with expansion in the dimension proportional to the errorbars) as 'marker'.
I found this page while searching the internet: http://code.izzid.com/2007/08/19/How-to-make-a-3D-plot-with-errorbars-in-matlab.html
But unfortunately they use only one errorbar.
My data is set of 6 arrays each containing either the x,y or z coordinate or the specific standard derivation i want to show as errorbar.
The code you posted looks very easy to adapt to draw all three error bars. Try this (note that I adapted it also so that you can change the shape and colour etc of the plots as you normally would by using varargin, e.g. you can call plot3d_errorbars(...., '.r'):
function [h]=plot3d_errorbars(x, y, z, ex, ey, ez, varargin)
% create the standard 3d scatterplot
hold off;
h=plot3(x, y, z, varargin{:});
% looks better with large points
set(h, 'MarkerSize', 25);
hold on
% now draw the vertical errorbar for each point
for i=1:length(x)
xV = [x(i); x(i)];
yV = [y(i); y(i)];
zV = [z(i); z(i)];
xMin = x(i) + ex(i);
xMax = x(i) - ex(i);
yMin = y(i) + ey(i);
yMax = y(i) - ey(i);
zMin = z(i) + ez(i);
zMax = z(i) - ez(i);
xB = [xMin, xMax];
yB = [yMin, yMax];
zB = [zMin, zMax];
% draw error bars
h=plot3(xV, yV, zB, '-k');
set(h, 'LineWidth', 2);
h=plot3(xB, yV, zV, '-k');
set(h, 'LineWidth', 2);
h=plot3(xV, yB, zV, '-k');
set(h, 'LineWidth', 2);
end
Example of use:
x = [1, 2];
y = [1, 2];
z = [1, 2];
ex = [0.1, 0.1];
ey = [0.1, 0.5];
ez = [0.1, 0.3];
plot3d_errorbars(x, y, z, ex, ey, ez, 'or')

3D body plot in matlab ( volume visualization )

I have little or no experience with volumetric data in MATLAB,
I need to complete next task:
I have 3 vectors ( rows ):
x_ = vector(1:smpl:max_row,1);
y_ = vector(1:smpl:max_row,2);
z_ = vector(1:smpl:max_row,3);
that are samples from large 3 columns array vector with height max_row.
x_ , y_ , z_ are points of 3D figure - surface points of the figure ( volume ). They represent 3D body that should be drawn in matlab.
I created linear grid:
%linear grid
a = -1.1:step:(-1.1+step*(length(x_)-1));
b = -1.1:step:(-1.1+step*(length(y_)-1));
c = -1.1:step:(-1.1+step*(length(z_)-1));
[x,y,z] = meshgrid(-1.1:step:(-1.1+step*(length(x_)-1)));
and also I create array v length(x_)*length(x_)*length(x_) that contains '1' in cells that are of 3D body representation function points and '0' another.
I tryied to make interpolation:
vi = interp3(x,y,z,v,x,y,z,'nearest');
but then vi = v that I've already created.
Now I need to plot the v array on 3D and form 3D body like in
http://www.mathworks.com/help/techdoc/ref/isonormals.html
for example.
I make that next way:
%plotting:
figure
p = patch(isosurface(x,y,z,v,1e-5,'verbose'),'FaceColor','green','EdgeColor','none');
grid on;
isonormals(v,p);
daspect([1 1 1])
view(3);
axis tight;
camproj perspective;
camlight
lighting gouraud
colormap(hsv)
but I get then only small rectangles in place of function '1' that are not connected like in picture that is attached.
I expect solid body enclosed by that points to be plotted.
Does anybody know what is the problem , how to draw 3D body from the x,y,z,v arrays ?
Thanks in advance.
image:
http://imgur.com/Ulegj
Try this, which will be a nice plot (it interpolates a bit though):
x = vector(1:smpl:max_row,1);
y = vector(1:smpl:max_row,2);
z = vector(1:smpl:max_row,3);
% Settings
displaySurface = 1;
displayPoints = 0;
xres = 800; % Resolution, the higher, the smoother
yres = 800;
cm = 'default'; % Colormap
% Axes Limits
xmin = min(x);
ymin = min(y);
xmax = max(x);
ymax = max(y);
xi = linspace(xmin, xmax, xres);
yi = linspace(ymin, ymax, yres);
% Figure
myfig = figure('Position', [200 200 800 600]);
rotate3d off
[XI, YI] = meshgrid(xi, yi);
ZI = griddata(x, y, z, XI, YI, 'cubic');
mesh(XI,YI,ZI);
colormap(cm)
if(displaySurface == 1)
hold on;
surf(XI, YI, ZI, 'EdgeColor', 'none');
end
hold on;
xlabel('x');
ylabel('y');
zlabel('z');
title('Title', 'FontWeight', 'bold');
xlim([xmin xmax])
ylim([ymin ymax])
grid off;
if(displayPoints == 1)
hold on
plot3(x, y, z,'marker','p','markerfacecolor','w','linestyle','none')
hidden off
end