Aligning a point cloud on a grid - point-cloud-library

I have to measure the Z-distances for corresponding points of two clouds.
I intend to iterate through one cloud and calculate the distance bezween Z coordinates using the same X and Y of the other cloud.
Unfortunatelly it doesn't work, as there are never a point at these X-Y coordinates in the second cloud. My current workaround is to search for a closest point in the second cloud for X-Y of the first cloud. It works, but it is very slow.
Is there a way to align points of X and Y coordinates on a defined grid using PCL? This way I hope the X-Y coortinates will match better.
EDIT
Ok, here are some images and more explanation.
Top view
Side view
There is a scan of a saddle and a horse back. Both are made independently but aligned in Z-axis - Z-Axis of both are parralel.
I want to create a model of a layer, which fits exactly under the saddle (Not just a rechtangular pad).
So given a thickness of the layer I want to iterate through the saddle points and find the Z-distance to corresponding point on the horse-back. As the Y coordinates are floats, there are nearly never a point on the horse with the same XY as on the saddle.
I think. If I could align all points to a grid with a given density, there would be a corresponding XY-point on tthe horse for each XY saddle point above it.

I am not really sure if that is what you mean, but maybe the "grid" you are talking about could just be the image plane? So instead of using the 3D point cloud you could take the depth maps/depth images and just compare the values of two depth maps at the same image coordinates. This would assume that the recordings are already aligned.
If you only have the point cloud data you'd have to perform a projection on the plane (for this you's have to know the intrinsics of the camera).
Another option might be aligning the clouds using a registration method (e.g. ICP). Then you could also get the (sum of) distance(s) for corresponding points of the clouds.

I've implemented a proof of concept and want to share it. However, I'd appreciate a "proper" solution - a PCL API function probably.
bool alignToGrid( pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud, QMap<QString, float > & grid, int density )
{
pcl::PointXYZRGBNormal p1;
p1.r=0;
p1.g=0;
p1.b=255;
QMap<QString, QList<float> > tmpGridMap;
for( std::vector<pcl::PointXYZRGBNormal, Eigen::aligned_allocator<pcl::PointXYZRGBNormal> >::iterator it1 = cloud->points.begin();
it1 != cloud->points.end(); it1++ )
{
p1.x = it1->x;
p1.y = it1->y;
p1.z = it1->z;
int gridx = p1.x*density;
int gridy = p1.y*density;
QString pos = QString("%1x%2").arg(gridx).arg(gridy);
tmpGridMap[pos].append(p1.z);
}
for (QMap<QString, QList<float> >::iterator it = tmpGridMap.begin(); it!=tmpGridMap.end(); ++it)
{
float meanZ=0;
foreach( float f, it.value() )
{
meanZ+=f;
}
meanZ /= it.value().size();
grid[it.key()] = meanZ;
}
return true;
}
The Idea is to iterate through a cloud and leave/create only points, which XY coordinates are on the defined grid. Density 1000 for Kinect clouds results in ca. 1mm-grid.
All points around the grid point are used for building the Z-average.
The cloud remains unmodified. The output is a map of xy-position to Z. XY Position is stored in string (weird, I know) as x. Using this map it is easy to find corresponding XY-points in other grid-aligned clouds.
Now I was able to map my clouds using any density. In the images e.g. 1mm and 1cm.

Related

How to draw elliptical sector with Bresenham's algorithm?

How can I draw filled elliptical sector using Bresenham's algorithm and bitmap object with DrawPixel method?
I have written method for drawing ellipse, but this method uses symmetry and passes only first quadrant. This algorithm is not situable for sectors. Of course, I can write 8 cycles, but I think it's not the most elegant solution of the task.
On integer math the usual parametrization is by using limiting lines (in CW or CCW direction) instead of your angles. So if you can convert those angles to such (you need sin,cos for that but just once) then you can use integer math based rendering for this. As I mentioned in the comment bresenham is not a good approach for a sector of ellipse as you would need to compute the internal iterators and counters state for the start point of interpolation and also it will give you just the circumference points instead of filled shape.
There are many approaches out there for this here a simple one:
convert ellipse to circle
simply by rescaling the smaller radius axis
loop through bbox of such circle
simple 2 nested for loops covering the outscribed square to our circle
check if point inside circle
simply check if x^2 + y^2 <= r^2 while the circle is centered by (0,0)
check if point lies between edge lines
so it should be CW with one edge and CCW with the other. You can exploit the cross product for this (its z coordinate polarity will tell you if point is CW or CCW against the tested edge line)
but this will work only up to 180 deg slices so you need also add some checking for the quadrants to avoid false negatives. But those are just few ifs on top of this.
if all conditions are met conver the point back to ellipse and render
Here small C++ example of this:
void elliptic_arc(int x0,int y0,int rx,int ry,int a0,int a1,DWORD c)
{
// variables
int x, y, r,
xx,yy,rr,
xa,ya,xb,yb, // a0,a1 edge points with radius r
mx,my,cx,cy,sx,sy,i,a;
// my Pixel access (you can ignore it and use your style of gfx access)
int **Pixels=Main->pyx; // Pixels[y][x]
int xs=Main->xs; // resolution
int ys=Main->ys;
// init variables
r=rx; if (r<ry) r=ry; rr=r*r; // r=max(rx,ry)
mx=(rx<<10)/r; // scale from circle to ellipse (fixed point)
my=(ry<<10)/r;
xa=+double(r)*cos(double(a0)*M_PI/180.0);
ya=+double(r)*sin(double(a0)*M_PI/180.0);
xb=+double(r)*cos(double(a1)*M_PI/180.0);
yb=+double(r)*sin(double(a1)*M_PI/180.0);
// render
for (y=-r,yy=y*y,cy=(y*my)>>10,sy=y0+cy;y<=+r;y++,yy=y*y,cy=(y*my)>>10,sy=y0+cy) if ((sy>=0)&&(sy<ys))
for (x=-r,xx=x*x,cx=(x*mx)>>10,sx=x0+cx;x<=+r;x++,xx=x*x,cx=(x*mx)>>10,sx=x0+cx) if ((sx>=0)&&(sx<xs))
if (xx+yy<=rr) // inside circle
{
if ((cx>=0)&&(cy>=0)) a= 0;// actual quadrant
if ((cx< 0)&&(cy>=0)) a= 90;
if ((cx>=0)&&(cy< 0)) a=270;
if ((cx< 0)&&(cy< 0)) a=180;
if ((a >=a0)||((cx*ya)-(cy*xa)<=0)) // x,y is above a0 in clockwise direction
if ((a+90<=a1)||((cx*yb)-(cy*xb)>=0))
Pixels[sy][sx]=c;
}
}
beware both angles must be in <0,360> range. My screen has y pointing down so if a0<a1 it will be CW direction which matches the routione. If you use a1<a0 then the range will be skipped and the rest of ellipse will be rendered instead.
This approach uses a0,a1 as real angles !!!
To avoid divides inside loop I used 10 bit fixed point scales instead.
You can simply divide this to 4 quadrants to avoid 4 if inside loops to improve performance.
x,y is point in circular scale centered by (0,0)
cx,cy is point in elliptic scale centered by (0,0)
sx,sy is point in elliptic scale translated to ellipse center position
Beware my pixel access is Pixels[y][x] but most apis use Pixels[x][y] so do not forget to change it to your api to avoid access violations or 90deg rotation of the result ...

How to rotate a Vector3 using Vector2?

I want to simulate particles driven by wind on a three.js globe. The data I have is a Vector3 for the position of a particle and a Vector2 indicating wind speed and direction, think North/East. How do I get the new Vector3?
I've consulted numerous examples and read the documentation and believe the solution involves quaternions, but the axis of rotation is not given. Also, there are thousands of particles, it should be fast, however real-time is not required.
The radius of the sphere is 1.
I would recommend you have a look at the Spherical class provided by three.js. Instead of cartesian coordinates (x,y,z), a point is represented in terms of a spherical coordinate-system (θ (theta), φ (phi), r).
The value of theta is the longitude and phi is the latitude for your globe (r - sphereRadius would be the height above the surface). Your wind-vectors can then be interpreted as changes to these two values. So what I would try is basically this:
// a) convert particle-location to spherical
const sphericalPosition = new THREE.Spherical()
.setFromVector3(particle.position);
// b) update theta/phi (note that windSpeed is assumed to
// be given in radians/time, but for a sphere of size 1 that
// shouldn't make a difference)
sphericalPosition.theta += windSpeed.x; // east-direction
sphericalPosition.phi += windSpeed.y; // north-direction
// c) write back to particle-position
particle.position.setFromSpherical(sphericalPosition);
Performance wise this shouldn't be a problem at all (maybe don't create a new Spherical-instance for every particle like I did above). The conversions involve a bit of trigonometry, but we're talking just thousands of points, not millions.
Hope that helps!
If you just want to rotate a vector based on an angle, just perform a simple rotation of values on the specified plane yourself using trig as per this page eg for a rotation on the xz plane:
var x = cos(theta)*vec_to_rotate.x - sin(theta)*vec_to_rotate.z;
var z = sin(theta)*vec_to_rotate.x + cos(theta)*vec_to_rotate.z;
rotated_vector = new THREE.Vector3(x,vec_to_rotate.y,z);
But to move particles with wind, you're not really rotating a vector, you should be adding a velocity vector, and it 'rotates' its own heading based on a combination of initial velocity, inertia, air friction, and additional competing forces a la:
init(){
position = new THREE.Vector(0,0,0);
velocity = new THREE.Vector3(1,0,0);
wind_vector = new THREE.Vector3(0,0,1);
}
update(){
velocity.add(wind_vector);
position.add(velocity);
velocity.multiplyScalar(.95);
}
This model is truer to how wind will influence a particle. This particle will start off heading along the x axis, and then 'turn' eventually to go in the direction of the wind, without any rotation of vectors. It has a mass, and a velocity in a direction, a force is acting on it, it turns.
You can see that because the whole velocity is subject to friction (the multscalar), our initial velocity diminishes as the wind vector accumulates, which causes a turn without performing any rotations. Thought i'd throw this out just in case you're unfamiliar with working with particle systems and maybe were just thinking about it wrong.

Find center of a fixed-width bounding box

Given a collection of points, I'd like to find the center of a bounding box (fixed-length and width) that maximizes the number of points within said box. I'm at a loss for an efficient way to do this.
Algorithm with complexity O(N^2*logN) (I hope that better one exists):
Edit: article exploiting interval trees claims O(NlogN) complexity
Sort data array A by X coordinate.
Scan A with sweep line left to right.
For every point in A get LeftX = A[k].X - left coordinate of vertical band, find the rightmost coordinate of vertical band RightX = LeftX + Width.
Copy points inside the band to another array B.
Sort B by Y-coordinate.
Scan B width sweep line top to down.
For every point B[i] get TopY = B[i].Y - top coordinate of rectangle, calculate BottomY = TopY + Height.
Use binary search in B:
B[j] is the last bottom point in B with B[j].Y <= BottomY.
Find number of points in the current rectangle:
Number of points is N(k, i) = j - i + 1
Check whether N(k, i) is maximum among others
This seems like a difficult problem, here is my idea:
Hold a graph, each node holds a rectangle and a subset of points. the rectangle defines the area where placing the bounding box in would overlap all the points in the subset.
To build the graph:
Start with a root node holding the empty set and the rect [top:-inf, bottom:inf, left:-inf, right:inf]
For each point in the tree call this recursive function with the root node (pseudo code):
function addPoint(node, point)
// check that you didn't already try to add this point to this node
// node.tested can be a hash set
if(node.tested contains point)
return
node.tested.add(point)
newRect = node.rect.intersectWith(boundingBoxAround(point))
// if the bounding box around the point does not intersect the rectangle, return
if(newRect is invalid) // rect is invalid if right<left or bottom<top
return
node.addChild(new node(newRect, node.pointSet U {point})
for each child of node
addPoint(child, point)
Now you just pick the node with the largest subset, you can keep track of that when building the graph so you don't need to run through the graph again.
I hope my idea is clear, let me know if I can explain it better.

3D: Check point inside elliptical cone

I seem to have searched the whole internet trying to find an implementation of checking if a 3d point is within an elliptical cone defined by (origin, length, horizontal angle, vertical angle). Unfortunately without success as I only really found one math solution which I did not understand.
Now I am aware on how to use implement it using a normal cone:
inRange = magnitude(point - origin) <= length;
heading = normalized(point - origin);
return dot(forward, heading) >= cos(angle) && inRange;
However there the height detection is far too tall. I would really like to implement a more realistic vision cone for the AI for a game but this requires having the cone shaped more like a human field of view being more wide than tall.
Thanks a lot for any help:)
Given a 3D elliptic cone, with base at B=(x_B,y_B,z_B), height h along the cone axis k=(k_x,k_y,j_z), major base radius a, minor base radius b and direction along the major axis i=(i_x,i_y,i_z) you need to find if a point P=(x,y,z) lies inside the cone. It is your choice on how to parametrize the major axis direction and I think your are trying to use spherical coordinates with two angles.
Here are the steps to take:
Establish a coordinate system with origin on the base B and with the local x axis along your major axis i. The local z axis should be towards the tip along k. Finally the local y axis should be
j=cross(k,i)=(i_z*k_y-i_y*k_z, i_x*k_z-i_z*k_x, i_y*k_x-i_x*k_y)
j=normalize(j)
Your 3×3 rotation matrix is defined by the columns E=[i,j,k]
Transform your point P=(x,y,z) into the local coordinates with
P2 = transpose(E)*(P-B) = (x2,y2,z2)
Now establish how far along the axis of the cone is with s=(h-z2)/h where s=0 at the tip and s=1 at the base.
If s>1 or s<0 then the point is outside
Otherwise if s>0 you need to check that (x2/(s*a))^2+(y2/(s*b))^2<=1 for the point to be inside.
If s=0 then check that x2=0 and y2=0 for the point being exactly at the tip.
If you cannot do basic vector algebra, like cross products, 3D transformations and normalization that I suggest you have some reading to do before you can understand what is going on here.
Note:
// | i_x i_y i_z |
// transpose(E) = | j_x j_y j_z |
// | k_x k_y k_z |

How can I convert 3D space coordinates to 2D space coordinates?

I'm using a Lua API. I'm trying to transform 3D space coordinates to 2D space coordinates. I've asked google but I can't find anything apart from snippets using OpenGL function. I don't need source code or anything just a simple way on how to do it? I can acquire the Camera's perspective, the original position to be transformed, window size and aspect ratio if that's any help? Thanks in advance for any suggestions :)
If you're talking about transforming world-space (x,y,z) coordinates to screen-space (u,v) coordinates, then the basic approach is:
u = x / z;
v = y / z;
If the camera is not at the origin, transform (x,y,z) by the view matrix before the projection matrix. You may also want to adjust for the camera perspective, aspect ratio etc., in which case I'd refer to this Wikipedia article.
My apologies if you're looking for something specific to the Lua API, which I am not familiar with.
For 3d projection you will need a line of field of view.
For example on a 400*400 window ;
200 will be ok.
As you can see in the given image.
Actually you can increase or decrease this 200 value according to your screen size because using wrong value can stretch your 3d model.
IMAGE
So you can use the given formula to convert your 3d points to 2d points.
Here, x or y means new x or y coordinate after perspective projection and oldx and oldy means old x and y coordinates.
x=(200÷(200+z))*(oldx);
Same formula for y also.
Y=(200÷(200+z))*(oldy);
Here is a java code example for converting 3d coordinates to 2d coordinates with depth of z axis.
// 'double[] a' indicates your 3d coordinates.eg: a=[x,y,z];
// int b indicates whether you wanted to return your 2d x coordinate or y coordinate. 0 will return x and 1 will return y.
// if your image stretches then you can adjust the fovl(field of view line).
public static double PERSPECTIVE_PROJECTION(double[] a,int b){
int fovl=200;
double oldpos=a[b];
double z=a[2];
double newpos=(double)(fovl/(fovl+z))*oldpos;
return newpos;
}

Resources