Point Cloud Generation - matlab

I have a 3-D geometrical shape which I have to convert into a point cloud.
The resultant point cloud can be considered equivalent to a point cloud output from a Laser Scan of the object.
No mesh generation is neeeded
The points generated may be evenly spaced, or maybe just randomly spaced - doesn't matter
The 3-D shape can be provided in the form of a 3-D mathematical formula
This has to be done using MATLAB

It's difficult to answer without an example but it sounds like you just want to perform a montecarlo simulation?
Lets say your shape is defined by the function f and that you have X, Y limits stored in two element vector e.g. xlim = [-10 10] i.e. all possible x values of this shape lie between x = -10 and x = 10 then I would suggest that you make f return some sort of error code if there is no value for a specific x-y pair. I'm going to assume that will be NaN. So f(x,y) is a function you are writing that either returns a z if it can or NaN if it can't
n= 10000;
counter = 1;
shape = nan(n, 3)
while counter < n
x = rand*diff(xlim) + mean(xlmin);
y = rand*diff(ylim) + mean(ylim);
z = f(x,y)
if ~isnan(z)
shape(counter, :) = [x, y, z];
counter = counter + 1
end
end
So the above code will generate 10000 (non unique, but that's easily adapted for) points randomly sample across your shape.
Now after typing this I realise that perhaps your shape is actually not all that big and maybe you can uniformly sample it rather than randomly:
for x = xlim(1):xstep:xlim(2)
for y = ylim(1):ystep:ylim(2)
shape(counter, :) = [x, y, f(x,y)];
end
end
or if you write f to be vectorized (preferable)
shape = [(xlim(1):xstep:xlim(2))', (ylim(1):ystep:ylim(2))', f(xlim(1):xstep:xlim(2), ylim(1):ystep:ylim(2));
and then either way
shape(isnan(shape(:, 3), :) = []; %remove the points that fell outside the shape

Here is the code to create a Cloud image with a Depth image from a PrimeSense Camera.
The input/Ouput of this function :
-inputs
depth -depth map
topleft -topleft coordinates of the segmented image in the whole image
-outputs
pclouds -3d point clouds
MatLab code :
depth = double(depth);
% Size of camera image
center = [320 240];
[imh, imw] = size(depth);
constant = 570.3;
% convert depth image to 3d point clouds
pclouds = zeros(imh,imw,3);
xgrid = ones(imh,1)*(1:imw) + (topleft(1)-1) - center(1);
ygrid = (1:imh)'*ones(1,imw) + (topleft(2)-1) - center(2);
pclouds(:,:,1) = xgrid.*depth/constant;
pclouds(:,:,2) = ygrid.*depth/constant;
pclouds(:,:,3) = depth;
distance = sqrt(sum(pclouds.^2,3));
Edit : This source is from this current article http://www.cs.washington.edu/rgbd-dataset/software.html
You can find some other Cloud function in MatLab and C++ that can be interest you.

Related

affine2d in Octave

In MATLAB I make a cylinder r and shift it to the position I want which is Pos. In MATLAB I use affine2d and imwarp but unfortunately Octave doesn't have these functions.
Does anybody know how I can do this in Octave without affine2d and imwarp?
The MATLAB code is
% get image limits
limX = size(image,1)/2;
limY = size(image,2)/2;
steps = 1;
% add 30% to the inner diameter to make sure it covers the complete sparse area
largeradius = 1.5*diaStart/2;
smallradius = diaStart/2;
% generate x/y points
[x,y] = meshgrid(-limX:steps:limX,-limY:steps:limY);
% calculate the radius values:
r = sqrt(x.^2 + y.^2);
r(r>largeradius) = 0;
r(r<smallradius) = 0;
% Shift translate circle in place
r = im2bw(r);
xPos = (Pos(1)-limX);
yPos = Pos(2)-limY;
tform = affine2d([1 0 0; 0 1 0; xPos yPos 1]);
r_trans = imwarp(r,tform,'OutputView',imref2d(size(image)));
It should be easy to do. affine2d is not a problem, as it is a function that changes the data type, but doesn't modify anything.
imwarp does [x y 1] = [u v 1] * T (being T the affine transformation Matrix) for each of the pixels.
So, if you know that you want the values of the pixels in some specific locations in the transformed image, then its easy to know them
In other words: you have an image r (composed by [u v 1] pixels, a transformation tform and you know that you want to know how a new image is created by that. The new image r_trans is composed by [x y 1] pixels, and you know [x,y,1] values.
Basically, you want to get r(u,v) for each [u,v,1]=[x y 1]*T^(-1);.
x will be 1:size(r,1), and y=1:size(r,2).
Therefore computing [u,v,1]=[x y 1]*T^(-1); is not a problem.
Now, you want to access r(u,v), and u and v wont be integers, they will be floating point values. To be able to get ther` values you will need interpolation.
For that, you need to use this simple piece of code;
[X,Y]=meshgrid(1:size(r,1),1:size(r,2));
value=interp2(X,Y,r,ui,vi,method); %chose method from https://www.gnu.org/software/octave/doc/interpreter/Multi_002ddimensional-Interpolation.html
r_trans(xi,yi)=value;
I didn't give you the whole code, but hopefully you understand how to do it.

Programmatically producing polar or quasi-polar plots with a variable for color in matlab

I would like to create plots using matlab that represent a numerical assessment of quality in a radial fashion.
The best method I've found seems to not work properly. One runs the following code:
theta = (0 : (360/11) : 360)*pi/180;
r = 0 : 2 : 20 ;
[TH,R] = meshgrid(theta,r);
[X,Y] = pol2cart(TH,R);
Z = meshgrid(Data);
surf(X,Y,Z);
Data is a vector of data containing 11 numbers, an example dataset being the following:
Data = 0.884, 0.882, 0.879, 0.880, 0.8776, 0.871, 0.8587, 0.829, 0.811, 0.803, 0.780
the output of surf here is this:
I would like to produce a more refined version of this type of image:
which I have generated with the following code:
for theta = 0 : pi/100 : pi;
v = [InterpolatedImageHeight;LengthVector];
x_center = InterpolatedImageHeight((HorizontalRes+1)/2);
y_center = 0; %InterpolatedImageHeight((HorizontalRes+1)/2);
center = repmat([x_center; y_center], 1, length(InterpolatedImageHeight));
R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
vo = R*(v - center) + center;
x_rotated = vo(1,:);
y_rotated = vo(2,:);
scatter(x_rotated,y_rotated,DotSize,InterpolatedData,'filled'); %x,y,area,color,properties
end
The issue with this is that it is a scatter plot where I am essentially using plot(r,Data), plotting many many copies, and increasing the dot size. The graphic itself has many seams, this takes an enormous amount of memory, and is time intensive where surf or mesh will run extremely fast and take minimal memory.
How does one produce concentric rings with a variable input for color?
There are two completely different plots in your question. The first one represents the data as rays from the origin towards the outside of the circle. The data-points are placed anti-clockwise. A refined version of this can be achieved like this:
Data = [0.884, 0.882, 0.879, 0.880, 0.8776, 0.871,...
0.8587, 0.829, 0.811, 0.803, 0.780];
theta = linspace(0,2*pi,length(Data));
r = linspace(0,20,length(Data));
[TH,R] = meshgrid(theta,r);
Z = meshgrid(Data);
[X,Y,Z] = pol2cart(TH,R,Z);
surf(X,Y,Z);
view(2);
shading interp
Note that I used linspace to generate theta and r to always match the length of Data. Z is also passed trough pol2cart. Then you can use shading interp to remove the lines between the patches and interpolate the color. With view(2) you can set the perspective as you would have a 2d-plot.
This is the result:
It's relatively easy to get a result like in your second example. There the data-points represent concentric circles around the origin and are placed from the origin towards the outside. Therefore, just transpose the meshgrid of Z by using the following line:
Z = meshgrid(Data)';
This is the result then:
based on the code by Darren Rowland in this thread I have come up with the following solution:
x = interp1(1:length(data),datax,(datax(1):datax(end)/f:datax(end)),'linear');
y = interp1(1:length(datay),datay,datay(1):datay(end)/f:datay(end),'spline');
theta = linspace(0,2*pi,n);
xr = x.'*cos(theta);
zr = x.'*sin(theta);
yr = repmat(y.',1,n);
figure;
surf(xy,yr,zr,zr*numcolors);
which is elegant, runs quickly, and produces beautiful figures. This is a sample of the output with some extra chart elements:

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

How can I assign values to a surface in matlab?

I am trying to build a 3D CFD pipe flow model using MATLAB, and I am hoping to assign values (boundary conditions) on the pipe wall. I've tried building a pipe using the cylinder function:
[X Y Z] = cylinder
but this generates me several points on the surface, which are not enough.
Aside, is there a better way to build a 3D CFD pipeflow model using MATLAB?
I would use a struct to embed information in your CFD object.
% radius = 10
r = 10;
% number of radial points = 30
n = 30;
CFD_cyl = struct;
[CFD_cyl.X, CFD_cyl.Y, CFD_cyl.Z] = cylinder(r, n);
% Creates a value vector in the CFD_cyl struct that can relate to the cylinder X, Y, Z
CFD_cyl.value = CFD_cyl.X(:,:) + CFD_cyl.Y(:,:) + CFD_cyl.Z(:,:);
Change the value field accordingly for the useful relationship that you wish to express.

Create 3D logical mask from points

I have a set of 3D points specifying points on a surface of an object. From these points, i need to construct a 3D logical mask. How can I solve this with matlab? Hope to get some insights.
% parameters
num_coordinates = 100;
max_coordinate = 20;
% generate random coordinate
x = sort(randi(max_coordinate, [num_coordinates, 1]));
y = sort(randi(max_coordinate, [num_coordinates, 1]));
z = sort(randi(max_coordinate, [num_coordinates, 1]));
% create the mask
mask = false(max_coordinate, max_coordinate, max_coordinate);
for k = 1 : length(x)
mask(x(k), y(k), z(k)) = true;
end
If speed is important, I suppose there is a faster solution.
If you have the "Curve Fitting Toolbox" you could fit a surface formula to the data.
And if you now the exact type (like a ball, cone, ...) you can define that as formular to fit to.
Maybe you can provide some example data.