I have set of 3D points.
Points_[x,y,z]% n*3 where n is number of points
I want to fit a plane (it is floor) and check height of plane. I think it is 2D problem .
z=bo+b1x+b2y;
I can't find a link for 2D ransac plane fitting. Can someone please give this link or file.
Secondly, Some softwares (commercial)gives height value of plane. It is mean or some complex value.
Regards,
If you form the following "A" matrix
A = [ones(numel(Points_X),1), Points_X(:), Points_Y(:)];
where the (:) is to give you column vectors (in case they were not to begin with)
Then you can write your equation as the classic linear system of equations:
A*b = Points_Z(:);
where b = [b0; b1; b2] -- a column vector of the parameters you are trying to determine.
This has the canonical solution
b=A\Points_Z(:)
or b=pinv(A)*Points_Z(:)
See help on mldivide and pinv.
You must have 3 or more points which don't all lie on a line. For an overdetermined system like this, pinv and \ will basically produce the same results. If they are nearly colinear, there may be some advantage using .
The 3 parameters in b are basically the height of the plane above the origin, the x slope, and the y slope of the plane. If you think about it, the "height" of a plane IS your z term. You can talk about height above some point (like the origin). Now, if you want height at the center of mass of the sampled points, you would then do
z_mean = [1 mean(Points_X(:) ) mean( Points_Y(:) )] * b
which is probably just equivalent to mean( Points_Z(:) ). For this definition to be meaningful, you would have to ensure that you have a uniformly spaced grid over the region of interest.
There may be other definitions, depending on your application. For instance, if you are trying to find the height at a center of a room, with points sampled along the walls and interior, then replacing mean with median might be more appropriate.
Related
Explanation of the problem:
I have points with (x,y,z) coordinates at two+ distinct times. For convenience, they can be imagined as irregularly spaced points along the surface of an inverted paraboloid.
There is some minimal thickness to the paraboloid. The paraboloid changes shape slightly as time proceeds (like a balloon inflating) and when it does so, all of the points move.
By substracting the coordinates at time2 - time1, I can get the displacement vectors at each point.
It is important to note (and I suspect this might be the source of the problem) that at the first time point, the x and y coordinates range from 0 to 2000, and the z coordinates are all within a narrower range - say 350 to 450. During the deformation, each point has an x component of displacement, y component, and z component.
The x and y components are small (~50 at most), while the z component is the largest (goes up to 400 near the center, much less near the edges).
Using weighted moving least squares at the location of each point, I am trying to fit the components of displacements to a second degree polynomial surface in terms of the original x,y,z coordinates of the point: eg.
x component of
displacement = ax^2 + bxy + cx + dy^2.. + hz^2 + iz + j
I use the lsqr function in MATLAB,like so, looping through each point for each time interval:
Ux = displacements{k,1}(:,1);
Cx = lsqr((adjust_B_matrix'*W*adjust_B_matrix),(adjust_B_matrix'*W*Ux),1e-7,10000);
W is the weight matrix, and adjust_B_matrix is the matrix of all (x,y,z) coordinates at time 1, shifted so that they're all centered around the point at which I'm trying to fit the function.
What is going wrong?
It's just not working -- once I have the functions, they're re-centered around the actual coordinates of the points.
But once I plot the resulting points (initial pointx + displacementx, initial pointy + displacementy, initial pointz + displacementz) by plugging in the coordinates at time 1 into the now-discovered functions, it just spits out a surface that looks just like the surface at time 1.
What might be going wrong? Things I have tried:
It's not an issue with the code itself- I generated 'fake' data using a grid of points and it worked perfectly. The predicted locations were superimposed with the actual coordinates and I was able to get back the function I started with. But in my trial example, I used x,y,z from 0 to 5, evenly spaced.
Global fitting works (but I need local fitting...).
I tried MATLAB's curve fitting toolbox and just tried to fit one of the displacements to only x and y coordinates, globally. It worked perfectly.
I think I shouldn't have a singular matrix issue because I use a large radius (around 75-80) points in the calculations, somewhat dispersed in 3D space.
Suspicions:
I think it has to do with the uneven distribution of initial (x,y,z) coordinates, but I don't know why or how to fix the issue, or even what method I can use.
If you read this far, thank you so much. Any advice would be greatly appreciated.
Figure for reference:
green = predicted points at time 2. Overlapping mostly with red, the actual coordinates of the points at time 1.
blue is the correct coordinates of points at time 2 (this is where the green ones should be if things were working).
image
Updated link for files:
http://a.tmp.ninja/eWfkNmFZyTFk.zip
Contents - code, sample data (please load the .mat files).
I can't actually access the code you posted, so here's some general suggestions.
It does look like the curve fitting toolbox has tools that do exactly what you are looking for, checkout the bottom of this page: https://www.mathworks.com/help/curvefit/polynomial.html#bt9ykh.
It looks like for whatever your learned function for the displacement is just very small or zero everywhere. I suspect the issue is just a minor typo/error on your part somewhere in your pipeline, possibly translating what you have to work with the fit function will reveal the issue.
This really shouldn't be the issue, but in the future if you had much more unbalanced data you could normalize it all before fitting (x_norm = (x - x_mu)/x_std).
Also, I don't think this is your problem either, but you can check if your matrix is close to singular by checking the condition number using the cord() function. So you could check cond(adjust_B_matrix'Wadjust_B_matrix). Second, If you check the documentation for lsqr there is an option to get a debug return flag, that is worth checking too.
Using plot::tube function in MuPAD, I can generate tubes with varying spine but the cross-section is always a circle, although the radius can vary along the spine. For instance:
plot::Tube([cos(t), sin(t), 0], 0.4 + 0.3*sin(t)*cos(t),t = -0.5*PI..0.5*PI,Mesh=[60,12]):
I want to plot tubes with (non-circular) elliptical cross-sections. Is there a way to achieve this in MuPAD?
P.S. I can generate tubes with arbitrary cross-sections using MATLAV, so please avoid including answers that use pure MATLAB commands.
As for your first question whether this can be done with plot::Tube: I don't think so. Consider the help of this function (emphasis mine):
plot::Tube creates generalized tubular plots, known as "canal
surfaces", with special cases known as "tube surface", "pipe surface"
or "tubular surfaces."
Intuitively, canal surfaces are space curves with thickness. More formally, a canal surface plot::Tube([x(t), y(t), z(t)], r(t), t = t_min..t_max) is the envelope of spheres with center [x(t), y(t), z(t)] and radius r(t), i.e., the thickness of the curve can vary with
the curve parameter t
The fact that a tube is defined as an envelope of a collection of spheres suggests that their cross-section is inherently circular.
I'm not familiar with MuPAD, so I don't know the elegant solution to your problem. For your simple example of a semi-circular base line I could put together this kludgy solution using the low-level plot::Surface, manually constructing the surface:
plot(
plot::Surface(
matrix([cos(t),sin(t),0])
+ numeric::rotationMatrix(t,[0,0,1]) * matrix([(0.2+0.1*sin(2*t))*cos(u),0,(0.2+0.1*cos(2*t))*sin(u)]),
t = -PI/2..PI/2,
u = 0..2*PI,
Mesh = [30,30]),
Scaling=Constrained)
Here t stands for the angular parameter along the semi-circular base line (toroidal direction), and u is the angle along the cross-section (poloidal direction). A given cross-section at angle t looks like this:
[(0.2+0.1*sin(2*t))*cos(u), 0, (0.2+0.1*cos(2*t))*sin(u)]
I.e. the semimajor axes are (0.2+0.1*sin(2*t)) and (0.2+0.1*cos(2*t)) along the cross-section of the tube.
You can see that I used a rotation matrix around the z axis to construct the surface. This made heavy use of the fact that the base line is a semi-circle. However, in general cases it should be possible to compute the derivative of your parameterized base line (with respect to t), and compute the necessary rotation angle (with parameter t) from that.
I'm not sure if this would be better asked on Mathoverflow, but I thought I would check here first. I have tried to be as clear and concise as possible; if there is anything that needs clearing up please let me know.
Background
I have two sets of points in R3 that are distributed in the form of (more-or-less) arbitrarily oriented ellipsoids. I wish to interpolate a tubular structure between these two ellipsoids. I also have coordinates of the desired centre line of this tubular structure.
I approximate the ellipsoids at either end with a minimum volume enclosing ellipsoid using the Khachiyan Algorithm implemented in Matlab, [1] which returns the coordinates of the centre of the ellipsoid (C), and matrix of the ellipse in centre form (A), such that:
(x - C)' * A * (x - C) = 1
I then extract the ellipsoid's axes lengths (a,b,c) and the rotation matrix (V) using singular value decomposition:
[U,D,V] = svd(A);
a = 1/sqrt(D(1,1));
b = 1/sqrt(D(2,2));
c = 1/sqrt(D(3,3));
I can easily interpolate the axes length parameters (e.g. linear, spline). To interpolate between the orientations, I first convert the rotation matrices to quaternion representation. Then for each point along the centre line, I use spherical linear interpolation (SLERP) implemented in another Matlab file [2]:
for iPoint = 1 : nPoints
t = iPoint / (nPoints + 2);
quat = slerp(startQuat,endQuat,t,0.001);
R = quat2rot(quat);
end
This is where I get stuck.
Unfortunately, even though SLERP "gives a straightest and shortest path between its quaternion endpoints," [3] the resulting interpolated ellipsoids are sometimes rotating in the "wrong" direction. That is, rather than resulting in a smooth tube, the interpolation results in a sort of twisted elliptical cylinder (see attached image, below).
I have tried checking to see if the dot product of the two quaternions is negative and if so, inverting one of them using quatinv. However, inverting results in something completely incorrect (see second attached image, below).
My question is: why is this happening, and what can I do to correct for this behavior? That is, how can I interpolate along the "true" shortest path between the two ellipsoid orientations?
Any suggestions would be greatly appreciated!
UPDATE
I have created a minimum working example and a required data file. I have also attached a screenshot of the result. I've zipped these up and uploaded them to Dropbox. [4]
[1] http://www.mathworks.com/matlabcentral/fileexchange/9542-minimum-volume-enclosing-ellipsoid/content/MinVolEllipse.m
[2] http://www.mathworks.com/matlabcentral/fileexchange/11827-slerp/content/slerp.m
[3] https://en.wikipedia.org/wiki/Slerp
[4] https://dl.dropboxusercontent.com/u/38218/ellipsoidInterpolation.zip
The solution was to rotate everything by the inverse of the rotation matrix of one of the reference ellipsoids, such that that reference ellipsoid was axis-aligned (i.e. had no rotation). Then after interpolating each ellipsoid, rotate it back to the original reference frame by multiplying by the original rotation matrix.
I've attached a screenshot of the result:
Update
Apparently this does not work in every case. I have posted a new question here.
As shown in image, there is a binary polygonal image. I want to find the principal direction in the image with respect to X-axis. I have shown the principal direction and X-axis with blue line. This can be done using PCA but my problem is such a small rectangle will have around 1000 pixels and I have to find Principal directions for around 100 polygons (polygon can be of arbitrary shape).
One approach that I have thought is:
Project that rectangle onto a line which is oriented at degrees at an interval (say) 5 degrees. The projection which has the maximum variance is the desired projection axis, and thus that is the desired angle. But this also falls under a greedy approach and thus will take time. Is there a smarter approach?
Also, if anybody could explain the exact procedure to do this using PCA, it would be helpful. I know the steps:
1. Take the covariance matrix.
2. Get the top eigenvector corresponding to largest eigenvalue -> that will be the principal direction.
But I am confused in the following statement which I often read everywhere:
A column vector: [0.5 0.5] is the first principal component and it gives the direction of the maximum variance. So can do I exactly calculate the angle by which I should rotate the data so that it will become parallel to X-axis.
Compute the eigenvector associated with the highest eigen value. Call that v. Normalize v. v = v/norm(v);
Compute angle between that and the horizontal direction: angle=acos(sum(v.*[1,0]))
Rotate by -angle, transformation matrix T = [cos(-angle) -sin(-angle); sin(-angle) cos(-angle)], multiply all points by that matrix. Do that for all polygons.
I want to calculate the magnetic field from a given image using biot savarts law. For example if I have a picture of a triangle, I say that this triangle forms a closed wire carrying current. Using image derivatives I can get the co-ordinates and direction of the current (normals included). I am struggling implementing this...need a bit of help with logic too. Here is what I have:
Img = imread('littletriangle.bmp');
Img = Img(:,:,1);
Img = double(Img);
[x,y] = size(Img);
[Ix, Iy] = gradient(Img);
biot savart equation is:
b = mu/4*pi sum(Idl x rn / r^2)
where mu/4pi is const, I is current magnitude, rn distance unit vector between a pixel and current, r^2 is the squared magnitude of the displacement between a pixel and the current.
So just to start off, I read the image in, turn it into a binary and then take the image gradient. This gives me the location and orientation of the 'current'. I now need to calculate the magnetic field from this 'current' at every pixel in the image. I am only interested in getting the magnetic field in the x-y plane. anything just to start me off would be brilliant!
For wire
B = mu * I /(2*pi*r)
B is vector and has. Direction is perpendicular on line between wire an point of interest. Fastest way to rotate vector by 90° is just swapping (x.y) so it becomes (y,x) vector
What about current? If you deal whit current then current is homogenous inside of wire (can be triangle) and I in upper direction is just normalized I per point and per Whole I.
So how to do this?
Get current per pixel (current / number of pixel in shape)
For each point calculate B using (r calculated form protagora) as sum of all other mini wires expressed as pixel using upper equation. (B is vector and has also direction, so keep track of B as (x,y) )
having picture of 100*100 will yield (100*100)*(100*100) calculations of B equation or something less if you will not calculate filed from empty space.
B is at the end instead of just mu * I /(2*pi*r) sum of all wire and I becomes dI
You do not need to apply any derivatives, just integration (sum)