How can I make 3d plots of planes by using spreadsheet in matlab - matlab

pointA=[9.62579 15.7309 3.3291];
pointB=[13.546 25.6869 3.3291];
pointC=[23.502 21.7667 -3.3291];
pointD=[19.5818 11.8107 -3.3291];
points=[pointA' pointB' pointC' pointD'];
fill3(points(1,:),points(2,:),points(3,:),'r')
grid on
alpha(0.3)
This code will show a filled plane(Cant add images yet T.T)
Now here is my problem. On a spreadsheet, I have x,y,z coordinates of thousands of points. The 4 consecutive points form a plane like the one shown. How do I make a code such that for every 4 consecutive points, it makes a filled plane.
Basically, if I have 400 points, I want the code to plot 100 planes.

Assuming your data are a matrix, m = (400,3)
m = rand(400,3);
for i = 1:length(m);
m2 = m'; % Transpose
end
Create a 3-D matrix in which 'j' represents each set of points:
m3=[];
%Not the most elegant way to cycle through every four points but it works!
z = 0:(length(m2)/4); z1 = (z*4)+1; z1 = z1(:,1:length(z)-1);
for j = 1:length(z1);
m3(:,:,j) = m2(:,z1(j):(z1(j)+3));
end
'j' now has a total length = 100 - representing the amount planes;
fill3(m3(1,:,1),m3(2,:,1),m3(3,:,1),'r');
% Cycle through planes- make a new figure for each plane;
for j = 1:length(z1);
fill3(m3(1,:,j),m3(2,:,j),m3(3,:,j),'r');
end

clear all, close all, clc
pointA=rand(99,1);
pointB=rand(99,1);
pointC=rand(99,1);
pointD=rand(99,1);
pointAmat = reshape(pointA,3,1,[]);
pointBmat = reshape(pointB,3,1,[]);
pointCmat = reshape(pointC,3,1,[]);
pointDmat = reshape(pointD,3,1,[]);
points=[pointAmat pointBmat pointCmat pointDmat];
for i = 1:size(points,3)
fill3(points(1,:,i),points(2,:,i),points(3,:,i),'r')
hold all
end
grid on
alpha(0.3)
Hope this helps.

Related

Matlab fill matrix with certain value between two lines (Bresenham)

For a school project we need to determine any sort of damage on a carbon fiber sheet with eight metal pins. To determine the damage we use resistivity measurements between multiple points.
We us a Matlab script to make the resistance between points visible. We plot the values in a matrix and create a line with the Bresenham function.
for x = 1:8
S1_(x) = 0;
end
p1 = [150 1];
p2 = [(150+150*sind(45)) (150-150*cosd(45))];
p3 = [300 150];
m1 = zeros(300);
m2 = zeros(300);
[x1_1,y1_1] = bresenham(p1(1),p1(2),p2(1),p2(2));
m1(sub2ind(size(m1), y1_1, x1_1)) = S1_(1);
[x1_1,y1_2] = bresenham(p1(1),p1(2),p3(1),p3(2));
m2(sub2ind(size(m2), y1_2, x1_1)) = S1_(2);
mP1=m1+m2;
The problem is as follows:
The Bresenham function does create the lines in the matrix, but we are searching for a function too fill the matrix between two lines with the average of those two lines combined. The average of S1_(1) and S1_(2) need to fill the matrix between line x1_1,y1_1 and x1_1,y1_2. The final plot is where all the points are drawn, when all areas between the lines are filled this should create a high top somewhere in the circle:
Could someone help me solving this problem?
UPDATE:
We finally got it working, we call a function to create a triangular matrix and add up all those matrices.

Modifying the polar coordinates of a disk with random dots in Matlab

I am trying to create a dynamic random dots stereogram by updating the position of the dots, so that I can get an inward motion of the dots (optic flow).
I first created a disk filled with dots whose position is randomised:
se = strel('disk',4);
x = linspace(-1,1,768); %generates 768 points in a vector with a [-1:1] interval
[X,Y] = meshgrid(x,x); %generates a rectangular grid in replicating the x vector.
[T,R] = cart2pol(X,Y);
threshold = 1 - (dot_nb / 768^2); %dot_nb=5;
Rd = double(rand(768,768)>threshold);
Rd(R>0.95 | R<0.06)=0; %remove some of the dots in order to get a circle and no dots in the middle of it
I am now trying to update the location of the dots at a specific refresh rate (20Hz) but I am having troubles with it.
I thought the following lines of code (which are in a bigger loop controlling the frame rate) could work but obviously something is missing and I do not know how else I could do it:
update = 0.1;
for i = 1:size(R,1) %R is the matrix with the radius values of the dots
for j = 1:size(R,2)
if R(i,j)<0.95 && R(i,j)>0.06
R(i,j) = R(i,j)-update;
else
R(i,j)=0;
end
end
end
Has anyone any idea how I could do to get what I'm looking for?
Thank you in advance!

How would I plot the for loop from my code below?

I have 3D flow data of the velocity of a fluid through a tube. I know the diameter of the tube and have looked at the velocity field and found the centre of the field for an xy plane at both ends of the tube. So I essentially have a line through the centre axis of the tube. I want to NaN all data points that are outside of the diameter. For this I am using an equation that gives the distance to a point from a line in 3D which I found here mathworld.wolfram.com/Point-LineDistance3-Dimensional.html. I then created an if statement which states points smaller than diameter will be NaN.
I am new to matlab so I don't know how I would now plot this.
%%
diff_axis = end_axis-start_axis;
diff_axis_mag = (diff_axis(1)^2 + diff_axis(2)^2 + diff_axis(3)^2)^0.5;
[rw col pl] = size(X);
for j = 1:col
for i = 1:rw
for k = 1:pl
x_curr = X(i,j,k);
y_curr = Y(i,j,k);
z_curr= Z(i,j,k);
x0 = [x_curr y_curr z_curr]
t = - dot((start_axis-x0),(diff_axis))./(diff_axis_mag)^2;
d = sqrt(((start_axis(1) - x0(1)) + (end_axis(1) - start_end(1))*t)^2 + ((start_axis(2)-x0(2))+(end_axis(2)-start_end(2))*t)^2+((start_axis(3)-x0(3))+(end_axis(3)-start_end(3))*t)^2);
if (d > D)
x_curr=NaN
y_curr=NaN
z_curr=NaN
end
end
end
end
It were nice to have explanatory names for your X, Y, and Z. I am guessing they are flow components, and diff_axis are axis coordinates? It is a very cumbersome notation.
what you do in your loops is you take point values (X,Y,Z), copy them to temporary constants and then set them to NaN if they fall out. But the problem is that usually you do not plot point-by-point in MATLAB. So these temorary guys like x_curr will be lost.
Also, the most optimal way to do things in MATLAB is to avoid loops whenever possible.
What you can do is to create first a mask
%// remember to put a dot like in `.^` for entrywise array operations
diff_axis_mag = sqrt(diff_axis(1).^2 + diff_axis(2).^2 + diff_axis(3).^2);
%// are you sure you need to include the third axis?
%// then it is a ball, not a tube
%// create a binary mask
mask = diff_axis_mag < tube_radius
X(~mask) = NaN;
Y(~mask) = NaN;
Z(~mask) = NaN;
Then you can plot your data with quiver3 or
stream3

Pixel subtraction

I am working on code that select set of pixels randomly from gray images, then comparing the intensity of each 2 pixels by subtracting the intensity of pixel in one location from another one in different location.
I have code do random selection, but I am not sure of this code and I do not know how to do pixels subtraction?
thank you in advance..
{
N = 100; % number of random pixels
im = imread('image.bmp');
[nRow,nCol,c] = size(im);
randRow = randi(nRow,[N,1]);
randCol = randi(nCol,[N,1]);
subplot(2,1,1)
imagesc(im(randRow,randCol,:))
subplot(2,1,2)
imagesc(im)
}
Parag basically gave you the answer. In order to achieve this vectorized, you need to use sub2ind. However, what I would do is generate two sets of rows and columns. The reason why is because you need one set for the first set of pixels and another set for the next set of pixels so you can subtract the two sets of intensities. Therefore, do something like this:
N = 100; % number of random pixels
im = imread('image.bmp');
[nRow,nCol,c] = size(im);
%// Generate two sets of locations
randRow1 = randi(nRow,[N,1]);
randCol1 = randi(nCol,[N,1]);
randRow2 = randi(nRow,[N,1]);
randCol2 = randi(nCol,[N,1]);
%// Convert each 2D location into a single linear index
%// for vectorization, then subtract
locs1 = sub2ind([nRow, nCol], randRow1, randCol1);
locs2 = sub2ind([nRow, nCol], randRow2, randCol2);
im_subtract = im(locs1) - im(locs2);
subplot(2,1,1)
imagesc(im_subtract);
subplot(2,1,2)
imagesc(im);
However, the above code only assumes that your image is grayscale. If you want to do this for colour, you'll have to do a bit more work. You need to access each channel and subtract on a channel basis. The linear indices that were defined above are just for a single channel. As such, you'll need to offset by nRow*nCol for each channel if you want to access the same corresponding locations in the next channels. As such, I would use sub2ind in combination with bsxfun to properly generate the right values for vectorizing the subtraction. This requires just a slight modification to the above code. Therefore:
N = 100; % number of random pixels
im = imread('image.bmp');
[nRow,nCol,c] = size(im);
%// Generate two sets of locations
randRow1 = randi(nRow,[N,1]);
randCol1 = randi(nCol,[N,1]);
randRow2 = randi(nRow,[N,1]);
randCol2 = randi(nCol,[N,1]);
%// Convert each 2D location into a single linear index
%// for vectorization
locs1 = sub2ind([nRow, nCol], randRow1, randCol1);
locs2 = sub2ind([nRow, nCol], randRow2, randCol2);
%// Extend to as many channels as we have
skip_ind = permute(0:nRow*nCol:(c-1)*nRow*nCol, [1 3 2]);
%// Create 3D linear indices
locs1 = bsxfun(#plus, locs1, skip_ind);
locs2 = bsxfun(#plus, locs2, skip_ind);
%// Now subtract the locations
im_subtract = im(locs1) - im(locs2);
subplot(2,1,1)
imagesc(im_subtract);
subplot(2,1,2)
imagesc(im);

Finding 2D area defined by contour lines in Matlab

I am having difficulty with calculating 2D area of contours produced from a Kernel Density Estimation (KDE) in Matlab. I have three variables:
X and Y = meshgrid which variable 'density' is computed over (256x256)
density = density computed from the KDE (256x256)
I run the code
contour(X,Y,density,10)
This produces the plot that is attached. For each of the 10 contour levels I would like to calculate the area. I have done this in some other platforms such as R but am having trouble figuring out the correct method / syntax in Matlab.
C = contourc(density)
I believe the above line would store all of the values of the contours allowing me to calculate the areas but I do not fully understand how these values are stored nor how to get them properly.
This little script will help you. Its general for contour. Probably working for contour3 and contourf as well, with adjustments of course.
[X,Y,Z] = peaks; %example data
% specify certain levels
clevels = [1 2 3];
C = contour(X,Y,Z,clevels);
xdata = C(1,:); %not really useful, in most cases delimters are not clear
ydata = C(2,:); %therefore further steps to determine the actual curves:
%find curves
n(1) = 1; %n: indices where the certain curves start
d(1) = ydata(1); %d: distance to the next index
ii = 1;
while true
n(ii+1) = n(ii)+d(ii)+1; %calculate index of next startpoint
if n(ii+1) > numel(xdata) %breaking condition
n(end) = []; %delete breaking point
break
end
d(ii+1) = ydata(n(ii+1)); %get next distance
ii = ii+1;
end
%which contourlevel to calculate?
value = 2; %must be member of clevels
sel = find(ismember(xdata(n),value));
idx = n(sel); %indices belonging to choice
L = ydata( n(sel) ); %length of curve array
% calculate area and plot all contours of the same level
for ii = 1:numel(idx)
x{ii} = xdata(idx(ii)+1:idx(ii)+L(ii));
y{ii} = ydata(idx(ii)+1:idx(ii)+L(ii));
figure(ii)
patch(x{ii},y{ii},'red'); %just for displaying purposes
%partial areas of all contours of the same plot
areas(ii) = polyarea(x{ii},y{ii});
end
% calculate total area of all contours of same level
totalarea = sum(areas)
Example: peaks (by Matlab)
Level value=2 are the green contours, the first loop gets all contour lines and the second loop calculates the area of all green polygons. Finally sum it up.
If you want to get all total areas of all levels I'd rather write some little functions, than using another loop. You could also consider, to plot just the level you want for each calculation. This way the contourmatrix would be much easier and you could simplify the process. If you don't have multiple shapes, I'd just specify the level with a scalar and use contour to get C for only this level, delete the first value of xdata and ydata and directly calculate the area with polyarea
Here is a similar question I posted regarding the usage of Matlab contour(...) function.
The main ideas is to properly manipulate the return variable. In your example
c = contour(X,Y,density,10)
the variable c can be returned and used for any calculation over the isolines, including area.