How to remove whitespace in mesh plot? - image

The plot results in a white space which I need to remove.
clc
clear all
x = -60:.5:150;
y = -60:.5:150;
[X,Y] = meshgrid(x,y);
Z = (90-X) + (120-Y);
fileIDAngles = fopen('E:\Capstone\Simple_Neural_1\IO Files\gena.txt','r');
angle1 = fscanf(fileIDAngles,'%f');
fileIDAngles = fopen('E:\Capstone\Simple_Neural_1\IO Files\genb.txt','r');
angle2 = fscanf(fileIDAngles,'%f');
fclose(fileIDAngles);
ans = (90-angle1) + (120-angle2);
hold on
mesh(X,Y,Z);
plot3(angle1,angle2,ans,'-o','LineWidth',1.1,'MarkerEdgeColor','k','MarkerFaceColor',[.49 1 .63],'MarkerSize',4);

You just need to set your axis mins and maxes (add this line to the end of your code):
axis([min(x) max(x) min(y) max(y)])

You can also use axis tight to bound the window within only non-zero areas of your data. This way you don't have to explicitly use min and/or max as axis tight does this for you internally. As with the other answer, place axis tight at the end of your code.

Related

How to get the length of n curves present in an image in Matlab?

Currently I have been working on obtaining the length of a curve, with the following code I have managed to get the length of a curve present in an image.
test image one curve
Then I paste the code that I used to get the length of the curve of a simple image. What I did is the following:
I got the columns and rows of the image
I got the columns in x and the rows in y
I obtained the coefficients of the curve, based on the formula of the
parable
Build the equation
Implement the arc length formula to obtain the length of the curve
grayImage = imread(fullFileName);
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
subplot(2, 2, 1);
imshow(grayImage, []);
% Get the rows (y) and columns (x).
[rows, columns] = find(binaryImage);
coefficients = polyfit(columns, rows, 2); % Gets coefficients of the formula.
% Fit a curve to 500 points in the range that x has.
fittedX = linspace(min(columns), max(columns), 500);
% Now get the y values.
fittedY = polyval(coefficients, fittedX);
% Plot the fitting:
subplot(2,2,3:4);
plot(fittedX, fittedY, 'b-', 'linewidth', 4);
grid on;
xlabel('X', 'FontSize', fontSize);
ylabel('Y', 'FontSize', fontSize);
% Overlay the original points in red.
hold on;
plot(columns, rows, 'r+', 'LineWidth', 2, 'MarkerSize', 10)
formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]);
% formulaD = vpa(formula)
df=diff(formula);
df = df^2;
f= (sqrt(1+df));
i = int(f,min(columns),max(columns));
j = double(i);
disp(j);
Now I have the image 2 which has n curves, I do not know how I can do to get the length of each curve
test image n curves
I suggest you to look at Hough Transformation:
https://uk.mathworks.com/help/images/hough-transform.html
You will need Image Processing Toolbox. Otherwise, you have to develop your own logic.
https://en.wikipedia.org/wiki/Hough_transform
Update 1
I had a two-hour thinking about your problem and I'm only able to extract the first curve. The problem is to locate the starting points of the curves. Anyway, here is the code I come up with and hopefully will give you some ideas for further development.
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP = cell(1,length(x));
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
cP{i} = [x(distances == 1), y(distances == 1);
x(distances == sqrt(2)), y(distances == sqrt(2))];
end
% pick the first point and a second point that is connected to it.
fP = P(1,:);
Q(1,:) = fP;
Q(2,:) = cP{1}(1,:);
m = 2;
while true
% take the previous point from point set Q, when current point is
% Q(m,1)
pP = Q(m-1,:);
% find the index of the current point in point set P.
i = find(P(:,1) == Q(m,1) & P(:,2) == Q(m,2));
% Find the distances from the previous points to all points connected
% to the current point.
dx = cP{i}(:,1) - pP(1)*ones(length(cP{i}),1);
dy = cP{i}(:,2) - pP(2)*ones(length(cP{i}),1);
distances = (dx.^2 + dy.^2).^0.5;
% Take the farthest point as the next point.
m = m+1;
p_cache = cP{i}(find(distances==max(distances),1),:);
% Calculate the distance of this point to the first point.
distance = ((p_cache(1) - fP(1))^2 + (p_cache(2) - fP(2))^2).^0.5;
if distance == 0 || distance == 1
break;
else
Q(m,:) = p_cache;
end
end
% By now we should have built the ordered point set Q for the first curve.
% However, there is a significant weakness and this weakness prevents us to
% build the second curve.
Update 2
Some more work since the last update. I'm able to separate each curve now. The only problem I can see here is to have a good curve fitting. I would suggest B-spline or Bezier curves than polynomial fit. I think I will stop here and leave you to figure out the rest. Hope this helps.
Note that the following script uses Image Processing Toolbox to find the edges of the curves.
clc;clear;close all;
grayImage = imread('2.png');
[rows, columns, numberOfColorBands] = size(grayImage);
if numberOfColorBands > 1
grayImage = grayImage(:, :, 2); % Take green channel.
end
% find edge.
bw = edge(grayImage,'canny');
imshow(bw);
[x, y] = find(bw == 1);
P = [x,y];
% For each point, find a point that is of distance 1 or sqrt(2) to it, i.e.
% find its connectivity.
cP =[0,0]; % add a place holder
for i = 1:length(x)
px = x(i);
py = y(i);
dx = x - px*ones(size(x));
dy = y - py*ones(size(y));
distances = (dx.^2 + dy.^2).^0.5;
c = [find(distances == 1); find(distances == sqrt(2))];
cP(end+1:end+length(c),:) = [ones(length(c),1)*i, c];
end
cP (1,:) = [];% remove the place holder
% remove duplicates
cP = unique(sort(cP,2),'rows');
% seperating curves
Q{1} = cP(1,:);
for i = 2:length(cP)
cp = cP(i,:);
% search for points in cp in Q.
for j = 1:length(Q)
check = ismember(cp,Q{j});
if ~any(check) && j == length(Q) % if neither has been saved in Q
Q{end+1} = cp;
break;
elseif sum(check) == 2 % if both points cp has been saved in Q
break;
elseif sum(check) == 1 % if only one of the points exists in Q, add the one missing.
Q{j} = [Q{j}, cp(~check)];
break;
end
end
% review sets in Q, merge the ones having common points
for j = 1:length(Q)-1
q = Q{j};
for m = j+1:length(Q)
check = ismember(q,Q{m});
if sum(check)>=1 % if there are common points
Q{m} = [Q{m}, q(~check)]; % merge
Q{j} = []; % delete the merged set
break;
end
end
end
Q = Q(~cellfun('isempty',Q)); % remove empty cells;
end
% each cell in Q represents a curve. Note that points are not ordered.
figure;hold on;axis equal;grid on;
for i = 1:length(Q)
x_ = x(Q{i});
y_ = y(Q{i});
coefficients = polyfit(y_, x_, 3); % Gets coefficients of the formula.
% Fit a curve to 500 points in the range that x has.
fittedX = linspace(min(y_), max(y_), 500);
% Now get the y values.
fittedY = polyval(coefficients, fittedX);
plot(fittedX, fittedY, 'b-', 'linewidth', 4);
% Overlay the original points in red.
plot(y_, x_, 'r.', 'LineWidth', 2, 'MarkerSize', 1)
formula = poly2sym([coefficients(1),coefficients(2),coefficients(3)]);
% formulaD = vpa(formula)
df=diff(formula);
lengthOfCurve(i) = double(int((sqrt(1+df^2)),min(y_),max(y_)));
end
Result:
You can get a good approximation of the arc lengths using regionprops to estimate the perimeter of each region (i.e. arc) and then dividing that by 2. Here's how you would do this (requires the Image Processing Toolbox):
img = imread('6khWw.png'); % Load sample RGB image
bw = ~imbinarize(rgb2gray(img)); % Convert to grayscale, then binary, then invert it
data = regionprops(bw, 'PixelList', 'Perimeter'); % Get perimeter (and pixel coordinate
% list, for plotting later)
lens = [data.Perimeter]./2; % Compute lengths
imshow(bw) % Plot image
hold on;
for iLine = 1:numel(data),
xy = mean(data(iLine).PixelList); % Get mean of coordinates
text(xy(1), xy(2), num2str(lens(iLine), '%.2f'), 'Color', 'r'); % Plot text
end
And here's the plot this makes:
As a sanity check, we can use a simple test image to see how good an approximation this gives us:
testImage = zeros(100); % 100-by-100 image
testImage(5:95, 5) = 1; % Add a vertical line, 91 pixels long
testImage(5, 10:90) = 1; % Add a horizontal line, 81 pixels long
testImage(2020:101:6060) = 1; % Add a diagonal line 41-by-41 pixels
testImage = logical(imdilate(testImage, strel('disk', 1))); % Thicken lines slightly
Running the above code on this image, we get the following:
As you can see the horizontal and vertical line lengths come out close to what we expect, and the diagonal line is a little bit more than sqrt(2)*41 due to the dilation step extending its length slightly.
I try with this post but i donĀ“t understand so much, but the idea Colours123 sounds great, this post talk about GUI https://www.mathworks.com/matlabcentral/fileexchange/24195-gui-utility-to-extract-x--y-data-series-from-matlab-figures
I think that you should go through the image and ask if there is a '1' if yes, ask the following and thus identify the beginning of a curve, get the length and save it in a BD, I am not very good with the code , But that's my idea

akima and/or rgl are shutting down Rstudio

the following procedure is shutting dow my Rstudio: I understand is any of the akima or rgl packages or both. How to solve this? data here
s=read.csv("GRVMAX tadpoles.csv")
require(nlme)
t=s[s$SPP== levels(s$SPP)[1],]
head(t)
t=na.omit(t)
t$TEM=as.numeric(as.character(t$TEM))
library(akima)
x=t$TEM
y=t$value
z=t$time
spline <- with(t,interp(x,y,z,duplicate="median",linear=T))
# rotatable 3D plot of points and spline surface
library(rgl)
open3d(scale=c(1/diff(range(x)),1/diff(range(y)),1/diff(range(z))))
with(spline,surface3d(as.character(x),y,z, col))
points3d(x,y,z, add=T)
title3d(xlab="temperature",ylab="performance",zlab="time")
axes3d()
interp() causes the problem. I think the reason is that scale of y is much different from x (the algorithm of interp() is basically for contour of spatial map). So interp() run when you give y changed scale. (Note; I did y*10 and output/10 but maybe it is a rough scale change. It whoud be better to concider methods of changing scale)
library(nlme); library(akima); library(rgl)
s = read.csv("GRVMAX tadpoles.csv")
t = s[s$SPP == levels(s$SPP)[1],]
t = na.omit(t)
head(t)
t$TEM = as.numeric(as.character(t$TEM))
x = t$TEM
y = t$value * 10 # scale change
z = t$time
spline <- interp(x, y, z, duplicate = "median", linear = T) # with() is unnecessary
spline$y <- spline$y / 10 # rescale
y <- y / 10 # rescale
open3d() # Is scale needed ??
# persp3d() can directly take interp.obj as an argument
persp3d(spline, col = "blue", alpha = 0.5, axes = F, xlab="", ylab="", zlab="")
points3d(x, y, z, add=T)
title3d(xlab="temperature", ylab="performance", zlab="time")
axes3d()

How would I implement these equations in Matlab?

I'm trying to implement a paper. In it I need to calculate the centre of gravity and second order moment of an image.
The equations of centre of gravity and second order moment are respectively given as:
Im having trouble trying to code this in Matlab ss from what I understand p(x,y) is the pixel of the image, but I'm having trouble what y represents and how would I implement in in the sum function. This is my implementation of the first equation but since I did not incorporate the y in there I'm sure the result given is wrong.
img = imread(path);
m = numel(img);
cog = sum(img(:))/m;
i think, m should be the maximum of y, because f2 is a function of x which means in Matlab it should be a vector.
try this code to implement f2:
img = magic(10)
m = 10;
temp = 0;
for y = 1:m
temp = temp+y*img(:,y);
%temp = temp+y*img(y,:); % depends on your image coordinates system
end
f2 = temp/m
Try the following code that uses vectorized anonymous functions.
% Read the image into an array (3 dimensions).
% Note: you may need to convert to doubles
img = im2double(imread(path));
% Get the size (may need to switch m and n).
[m, n, o] = size(img);
% Create y vector
y = 1:m;
% Create functions (not sure how you want to handle the RGB values).
f2 = #(x, p) sum(y.*p(x,:,1)/m);
f3 = #(x, p) sum(y.^2.*p(x,:,1)/(m^2));
% Call the functions
x = 10; % Some pixel x position
f2_result = f2(x, img);
f3_result = f3(x, img);
Note: I may have the x and y switched depending on the orientation of your image. If that's the case then switch things around like this:
[n, m, o] = size(img);
...
f2 = #(x, p) sum(y.*p(:,x)/m);
etc...
I'm not at work so I can't run the im2double function (don't have the library) but I think it will work.

How to draw repeating straight lines with specific radius and angle in matlab?

Suppose i would like to draw an image like the following:
Where the pixel values are refined to 0 for black and white for 1.
These line are drawn with specific radius and angles
Now I create a 80 x 160 matrix
texturematrix = zeros(80,160);
then i want to change particular elements to be 1 according to the lines conditions
but how do i make them repeatedly with specific distance apart from each others effectively?
Thanks a lot everyone!
This might not be what you are looking for, but generating such an image could be done by plotting a set of lines, as follows:
% grid sizes
m = 6;
n = 5;
% line length and angle
len = 1;
theta = .1*pi;
[a,b] = meshgrid(1:m,1:n);
x = reshape([a(:),a(:)+len*cos(theta),nan(numel(a),1)]',[],1);
y = reshape([b(:),b(:)+len*sin(theta),nan(numel(b),1)]',[],1);
h = figure();
plot(x,y,'k', 'LineWidth', 2);
But this has nothing to do with a texture matrix. So, we construct a matrix of desired size:
set(gca, 'position',[0 0 1 1], 'units','normalized', 'YTick',[], 'XTick',[]);
frame = frame2im(getframe(h),[0 0 1 1]);
im = imresize(frame,[80 160]);
M = ~(im(2:end,2:end,1)==255);

Plot images as axis labels in MATLAB

I am plotting a 7x7 pixel 'image' in MATLAB, using the imagesc command:
imagesc(conf_matrix, [0 1]);
This represents a confusion matrix, between seven different objects. I have a thumbnail picture of each of the seven objects that I would like to use as the axes tick labels. Is there an easy way to do this?
I don't know an easy way. The axes properties XtickLabel which determines the labels, can only be strings.
If you want a not-so-easy way, you could do something in the spirit of the following non-complete (in the sense of a non-complete solution) code, creating one label:
h = imagesc(rand(7,7));
axh = gca;
figh = gcf;
xticks = get(gca,'xtick');
yticks = get(gca,'ytick');
set(gca,'XTickLabel','');
set(gca,'YTickLabel','');
pos = get(axh,'position'); % position of current axes in parent figure
pic = imread('coins.png');
x = pos(1);
y = pos(2);
dlta = (pos(3)-pos(1)) / length(xticks); % square size in units of parant figure
% create image label
lblAx = axes('parent',figh,'position',[x+dlta/4,y-dlta/2,dlta/2,dlta/2]);
imagesc(pic,'parent',lblAx)
axis(lblAx,'off')
One problem is that the label will have the same colormap of the original image.
#Itmar Katz gives a solution very close to what I want to do, which I've marked as 'accepted'. In the meantime, I made this dirty solution using subplots, which I've given here for completeness. It only works up to a certain size input matrix though, and only displays well when the figure is square.
conf_mat = randn(5);
A = imread('peppers.png');
tick_images = {A, A, A, A, A};
n = length(conf_mat) + 1;
% plotting axis labels at left and top
for i = 1:(n-1)
subplot(n, n, i + 1);
imshow(tick_images{i});
subplot(n, n, i * n + 1);
imshow(tick_images{i});
end
% generating logical array for where the confusion matrix should be
idx = 1:(n*n);
idx(1:n) = 0;
idx(mod(idx, n)==1) = 0;
% plotting the confusion matrix
subplot(n, n, find(idx~=0));
imshow(conf_mat);
axis image
colormap(gray)

Resources