update to r733 (again)
This commit is contained in:
parent
ab0dc46ed6
commit
5aed26340d
48 changed files with 18342 additions and 0 deletions
|
@ -0,0 +1,849 @@
|
|||
/*
|
||||
* compacttree implementation
|
||||
*
|
||||
* Copyright (C) Jan Elseberg, Kai Lingemann, Jan Elseberg
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Efficient representation of an octree
|
||||
* @author Jan Elsberg. Automation Group, Jacobs University Bremen gGmbH, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector>
|
||||
using std::vector;
|
||||
#include <deque>
|
||||
using std::deque;
|
||||
#include <set>
|
||||
using std::set;
|
||||
#include <list>
|
||||
using std::list;
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "slam6d/globals.icc"
|
||||
#include "slam6d/point_type.h"
|
||||
|
||||
#include "slam6d/Boctree.h"
|
||||
#include "show/compacttree.h"
|
||||
#include "show/colormanager.h"
|
||||
#include "show/scancolormanager.h"
|
||||
#include "show/viewcull.h"
|
||||
|
||||
using namespace show;
|
||||
compactTree::~compactTree(){
|
||||
delete alloc;
|
||||
|
||||
delete[] mins;
|
||||
delete[] maxs;
|
||||
}
|
||||
|
||||
|
||||
void compactTree::AllPoints( cbitoct &node, vector<double*> &vp, double center[3], double size) {
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
tshort *point = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
double *p = new double[3];
|
||||
//cout << point[0] << " " << point[1] << " " << point[2] << endl;
|
||||
for (unsigned int k = 0; k < 3; k++){
|
||||
p[k] = point[k] * precision + ccenter[k];
|
||||
}
|
||||
|
||||
vp.push_back(p);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else { // recurse
|
||||
AllPoints( children->node, vp, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void compactTree::GetOctTreeCenter(vector<double*>&c, cbitoct &node, double *center, double size) {
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (unsigned char i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
double * cp = new double[POINTDIM];
|
||||
for (unsigned int iterator = 0; iterator < POINTDIM; iterator++) {
|
||||
cp[iterator] = ccenter[iterator];
|
||||
}
|
||||
c.push_back(cp);
|
||||
} else { // recurse
|
||||
GetOctTreeCenter(c, children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
long compactTree::countNodes(cbitoct &node) {
|
||||
long result = 0;
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf
|
||||
// ++result;
|
||||
} else { // recurse
|
||||
result += countNodes(children->node) + 1;
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
long compactTree::countLeaves(cbitoct &node) {
|
||||
long result = 0;
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf
|
||||
lint nrpts = children->getLength();
|
||||
result += POINTDIM*nrpts + 1;
|
||||
} else { // recurse
|
||||
result += countLeaves(children->node);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void compactTree::deletetNodes(cbitoct &node) {
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
bool haschildren = false;
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf
|
||||
tshort *points = children->getPoints();
|
||||
delete [] points;
|
||||
// delete [] children->points;
|
||||
} else { // recurse
|
||||
deletetNodes(children->node);
|
||||
}
|
||||
++children; // next child
|
||||
haschildren = true;
|
||||
}
|
||||
}
|
||||
// delete children
|
||||
if (haschildren) {
|
||||
cbitoct::getChildren(node, children);
|
||||
delete[] children;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long compactTree::maxTargetPoints( cbitoct &node ) {
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
unsigned long max = 0;
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
lint length = children->getLength();
|
||||
if (length > max) max = length;
|
||||
} else { // recurse
|
||||
unsigned long tp = maxTargetPoints( children->node);
|
||||
if (tp > max) max = tp;
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
|
||||
return max*POPCOUNT(node.valid);
|
||||
}
|
||||
|
||||
void compactTree::displayOctTreeAll( cbitoct &node, double *center, double size) {
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
tshort *point = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
glBegin(GL_POINTS);
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
//cout << "C " << point[1] << " " << cm << endl;
|
||||
//glVertex3f( point[0], point[1], point[2]);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
glEnd();
|
||||
} else { // recurse
|
||||
displayOctTreeAll( children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::displayOctTreeAllCulled( cbitoct &node, double *center, double size ) {
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeAll(node, center, size);
|
||||
return;
|
||||
}
|
||||
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
tshort *point = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
glBegin(GL_POINTS);
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
//glVertex3f( point[0], point[1], point[2]);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeAllCulled( children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::displayOctTreeCulledLOD(long targetpts, cbitoct &node, double *center, double size ) {
|
||||
if (targetpts <= 0) return; // no need to display anything
|
||||
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeLOD(targetpts, node, center, size);
|
||||
return;
|
||||
}
|
||||
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
unsigned short nc = POPCOUNT(node.valid);
|
||||
long newtargetpts = targetpts;
|
||||
if (nc > 0) {
|
||||
newtargetpts = newtargetpts/nc;
|
||||
if (newtargetpts <= 0 ) return;
|
||||
}
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
tshort *point = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
glBegin(GL_POINTS);
|
||||
if (length > 10 && !LOD(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) { // only a single pixel on screen only paint one point
|
||||
if(cm) cm->setColor(point);
|
||||
//glVertex3f( point[0], point[1], point[2]);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
} else if (length <= newtargetpts) { // more points requested than possible, plot all
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
//glVertex3f( point[0], point[1], point[2]);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else { // select points to show
|
||||
// TODO smarter subselection of points here
|
||||
double each = (double)POINTDIM * (double)((double)length/(double)newtargetpts);
|
||||
tshort *p;
|
||||
int index;
|
||||
for(unsigned int iterator = 0; iterator < newtargetpts; iterator++ ) {
|
||||
index = (double)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
//glVertex3f( p[0], p[1], p[2]);
|
||||
glVertex3f( p[0] * precision + ccenter[0], p[1] * precision + ccenter[1], p[2] * precision + ccenter[2]);
|
||||
//point += each;
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
} else { // recurse
|
||||
displayOctTreeCulledLOD(newtargetpts, children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::displayOctTreeLOD(long targetpts, cbitoct &node, double *center, double size ) {
|
||||
if (targetpts <= 0) return; // no need to display anything
|
||||
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
unsigned short nc = POPCOUNT(node.valid);
|
||||
long newtargetpts = targetpts;
|
||||
if (nc > 0) {
|
||||
newtargetpts = newtargetpts/nc;
|
||||
if (newtargetpts <= 0 ) return;
|
||||
}
|
||||
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
tshort *point = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
glBegin(GL_POINTS);
|
||||
/* if (length > 10 && !LOD(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) { // only a single pixel on screen only paint one point
|
||||
if(cm) cm->setColor(point);
|
||||
//glVertex3f( point[0], point[1], point[2]);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
} else*/ if (length <= newtargetpts) { // more points requested than possible, plot all
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
//glVertex3f( point[0], point[1], point[2]);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else { // select points to show
|
||||
// TODO smarter subselection of points here
|
||||
double each = (double)POINTDIM * (double)((double)length/(double)newtargetpts);
|
||||
tshort *p;
|
||||
int index;
|
||||
for(unsigned int iterator = 0; iterator < newtargetpts; iterator++ ) {
|
||||
index = (double)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
//glVertex3f( p[0], p[1], p[2]);
|
||||
glVertex3f( p[0] * precision + ccenter[0], p[1] * precision + ccenter[1], p[2] * precision + ccenter[2]);
|
||||
//point += each;
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
} else { // recurse
|
||||
displayOctTreeLOD(newtargetpts, children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::displayOctTreeCulledLOD2(float ratio, cbitoct &node, double *center, double size ) {
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeLOD2(ratio, node, center, size);
|
||||
return;
|
||||
}
|
||||
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
tshort *point = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
l = max((int)(l*l*ratio), 0);
|
||||
if (l != 0) {
|
||||
if ((int)length > l ) {
|
||||
double each = (double)POINTDIM * (double)((double)length/(double)l);
|
||||
tshort *p;
|
||||
int index;
|
||||
for(int iterator = 0; iterator < l; iterator++ ) {
|
||||
index = (double)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
glVertex3f( p[0] * precision + ccenter[0], p[1] * precision + ccenter[1], p[2] * precision + ccenter[2]);
|
||||
}
|
||||
} else if ((int)length <= l) {
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else if (l == 1) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
l = max((int)(l*l*ratio), 0);
|
||||
if (l > 0) {
|
||||
displayOctTreeCulledLOD2(ratio, children->node, ccenter, size/2.0);
|
||||
}
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::displayOctTreeLOD2(float ratio, cbitoct &node, double *center, double size ) {
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
tshort *point = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
l = max((int)(l*l*ratio), 0);
|
||||
if (l > 1) {
|
||||
if ((int)length > l ) {
|
||||
double each = (double)POINTDIM * (double)((double)length/(double)l);
|
||||
tshort *p;
|
||||
int index;
|
||||
for(int iterator = 0; iterator < l; iterator++ ) {
|
||||
index = (double)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
glVertex3f( p[0] * precision + ccenter[0], p[1] * precision + ccenter[1], p[2] * precision + ccenter[2]);
|
||||
}
|
||||
} else if ((int)length <= l) {
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0] * precision + ccenter[0], point[1] * precision + ccenter[1], point[2] * precision + ccenter[2]);
|
||||
}
|
||||
} else { // recurse
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
l = max((int)(l*l*ratio), 0);
|
||||
if (l > 0) {
|
||||
displayOctTreeLOD2(ratio, children->node, ccenter, size/2.0);
|
||||
}
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void compactTree::displayOctTreeCAllCulled( cbitoct &node, double *center, double size, double minsize ) {
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeCAll(node, center, size, minsize);
|
||||
return;
|
||||
}
|
||||
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf || minsize > size ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
showCube(ccenter, size/2.0);
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeCAllCulled( children->node, ccenter, size/2.0, minsize);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::displayOctTreeCAll( cbitoct &node, double *center, double size, double minsize ) {
|
||||
double ccenter[3];
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf || minsize > size ) { // if ith node is leaf get center
|
||||
showCube(ccenter, size/2.0);
|
||||
} else { // recurse
|
||||
displayOctTreeCAll( children->node, ccenter, size/2.0, minsize);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::showCube(double *center, double size) {
|
||||
glLineWidth(1.0);
|
||||
glBegin(GL_QUADS); // draw a cube with 6 quads
|
||||
glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] + size);
|
||||
glColor3f(1.0f,0.5f,0.0f); // Set The Color To Orange
|
||||
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] - size);
|
||||
|
||||
glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] + size);
|
||||
|
||||
glColor3f(1.0f,1.0f,0.0f); // Set The Color To Yellow
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] - size);
|
||||
|
||||
glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] + size);
|
||||
|
||||
glColor3f(1.0f,0.0f,1.0f); // Set The Color To Violet
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] - size);
|
||||
|
||||
|
||||
glEnd();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
void compactTree::selectRay(vector<T *> &points) {
|
||||
//selectRay(points, *root, center, size);
|
||||
}
|
||||
|
||||
|
||||
void compactTree::childcenter(double *pcenter, double *ccenter, double size, unsigned char i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
ccenter[0] = pcenter[0] - size / 2.0;
|
||||
ccenter[1] = pcenter[1] - size / 2.0;
|
||||
ccenter[2] = pcenter[2] - size / 2.0;
|
||||
break;
|
||||
case 1:
|
||||
ccenter[0] = pcenter[0] + size / 2.0;
|
||||
ccenter[1] = pcenter[1] - size / 2.0;
|
||||
ccenter[2] = pcenter[2] - size / 2.0;
|
||||
break;
|
||||
case 2:
|
||||
ccenter[0] = pcenter[0] - size / 2.0;
|
||||
ccenter[1] = pcenter[1] + size / 2.0;
|
||||
ccenter[2] = pcenter[2] - size / 2.0;
|
||||
break;
|
||||
case 3:
|
||||
ccenter[0] = pcenter[0] + size / 2.0;
|
||||
ccenter[1] = pcenter[1] + size / 2.0;
|
||||
ccenter[2] = pcenter[2] - size / 2.0;
|
||||
break;
|
||||
case 4:
|
||||
ccenter[0] = pcenter[0] - size / 2.0;
|
||||
ccenter[1] = pcenter[1] - size / 2.0;
|
||||
ccenter[2] = pcenter[2] + size / 2.0;
|
||||
break;
|
||||
case 5:
|
||||
ccenter[0] = pcenter[0] + size / 2.0;
|
||||
ccenter[1] = pcenter[1] - size / 2.0;
|
||||
ccenter[2] = pcenter[2] + size / 2.0;
|
||||
break;
|
||||
case 6:
|
||||
ccenter[0] = pcenter[0] - size / 2.0;
|
||||
ccenter[1] = pcenter[1] + size / 2.0;
|
||||
ccenter[2] = pcenter[2] + size / 2.0;
|
||||
break;
|
||||
case 7:
|
||||
ccenter[0] = pcenter[0] + size / 2.0;
|
||||
ccenter[1] = pcenter[1] + size / 2.0;
|
||||
ccenter[2] = pcenter[2] + size / 2.0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void compactTree::GetOctTreeCenter(vector<double*>&c) { GetOctTreeCenter(c, *root, center, size); }
|
||||
void compactTree::AllPoints(vector<double *> &vp) { AllPoints(*compactTree::root, vp, center, size); }
|
||||
|
||||
long compactTree::countNodes() { return 1 + countNodes(*root); }
|
||||
long compactTree::countLeaves() { return 1 + countLeaves(*root); }
|
||||
|
||||
void compactTree::setColorManager(ColorManager *_cm) { cm = _cm; }
|
||||
|
||||
void compactTree::drawLOD(float ratio) {
|
||||
switch (current_lod_mode) {
|
||||
case 1:
|
||||
glBegin(GL_POINTS);
|
||||
displayOctTreeCulledLOD2(ratio , *root, center, size);
|
||||
glEnd();
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
#ifdef WITH_GLEE
|
||||
if (GLEE_ARB_point_parameters) {
|
||||
glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0);
|
||||
glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, 100000.0);
|
||||
GLfloat p[3] = {0.0, 0.0000, 0.0000005};
|
||||
glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, p);
|
||||
displayOctTreeCPAllCulled(*BOctTree<T>::root, BOctTree<T>::center, BOctTree<T>::size, BOctTree<T>::size/ pow(2, min( (int)(ratio * BOctTree<T>::max_depth ), BOctTree<T>::max_depth - 3) ) );
|
||||
p[0] = 1.0;
|
||||
p[2] = 0.0;
|
||||
glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, p);
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
//break;
|
||||
case 0:
|
||||
glBegin(GL_POINTS);
|
||||
displayOctTreeCulledLOD(maxtargetpoints * ratio, *root, center, size);
|
||||
glEnd();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void compactTree::draw() {
|
||||
displayOctTreeAllCulled(*root, center, size);
|
||||
}
|
||||
|
||||
void compactTree::displayOctTree(double minsize ) {
|
||||
displayOctTreeCAllCulled(*root, center, size, minsize);
|
||||
}
|
||||
|
||||
shortpointrep* compactTree::createPoints(lint length) {
|
||||
//shortpointrep *points = new shortpointrep[POINTDIM*length];
|
||||
shortpointrep *points = alloc->allocate<shortpointrep> (POINTDIM*length);
|
||||
return points;
|
||||
}
|
||||
void compactTree::deserialize(std::string filename ) {
|
||||
char buffer[sizeof(float) * 20];
|
||||
float *p = reinterpret_cast<float*>(buffer);
|
||||
|
||||
std::ifstream file;
|
||||
file.open (filename.c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
// read magic bits
|
||||
file.read(buffer, 2);
|
||||
if ( buffer[0] != 'X' || buffer[1] != 'T') {
|
||||
std::cerr << "Not an octree file!!" << endl;
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// read header
|
||||
pointtype = PointType::deserialize(file);
|
||||
|
||||
file.read(buffer, 5 * sizeof(float));
|
||||
voxelSize = p[0];
|
||||
center[0] = p[1];
|
||||
center[1] = p[2];
|
||||
center[2] = p[3];
|
||||
size = p[4];
|
||||
|
||||
file.read(buffer, sizeof(int));
|
||||
int *ip = reinterpret_cast<int*>(buffer);
|
||||
POINTDIM = *ip;
|
||||
|
||||
float *fmins = new float[POINTDIM];
|
||||
float *fmaxs = new float[POINTDIM];
|
||||
mins = new double[POINTDIM];
|
||||
maxs = new double[POINTDIM];
|
||||
|
||||
file.read(reinterpret_cast<char*>(fmins), POINTDIM * sizeof(float));
|
||||
file.read(reinterpret_cast<char*>(fmaxs), POINTDIM * sizeof(float));
|
||||
|
||||
for (unsigned int i = 0; i < POINTDIM; i++) {
|
||||
mins[i] = fmins[i];
|
||||
maxs[i] = fmaxs[i];
|
||||
}
|
||||
|
||||
double vs = size;
|
||||
while (vs > voxelSize) {
|
||||
vs = vs * 0.5;
|
||||
}
|
||||
// precision = vs / 32768; // 2^15
|
||||
precision = vs / TSHORT_MAXP1; // 2^15
|
||||
|
||||
|
||||
// read root node
|
||||
//root = new cbitoct();
|
||||
root = alloc->allocate<cbitoct>();
|
||||
deserialize(file, *root );
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void compactTree::deserialize(std::ifstream &f, cbitoct &node) {
|
||||
char buffer[2];
|
||||
f.read(buffer, 2);
|
||||
node.valid = buffer[0];
|
||||
node.leaf = buffer[1];
|
||||
|
||||
unsigned short n_children = POPCOUNT(node.valid);
|
||||
|
||||
// create children
|
||||
//cbitunion<tshort> *children = new cbitunion<tshort>[n_children];
|
||||
cbitunion<tshort> *children = alloc->allocate<cbitunion<tshort> >(n_children);
|
||||
cbitoct::link(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf read points
|
||||
lint length;
|
||||
f.read(reinterpret_cast<char*>(&length), sizeof(lint));
|
||||
shortpointrep *points = createPoints(length);
|
||||
|
||||
f.read(reinterpret_cast<char*>(points), sizeof(shortpointrep) * length * POINTDIM); // read the points
|
||||
children->linkPoints(points, length);
|
||||
} else { // write child
|
||||
deserialize(f, children->node);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void compactTree::serialize(std::string filename) {
|
||||
char buffer[sizeof(float) * 20];
|
||||
float *p = reinterpret_cast<float*>(buffer);
|
||||
|
||||
std::ofstream file;
|
||||
file.open (filename.c_str(), std::ios::out | std::ios::binary);
|
||||
|
||||
// write magic bits
|
||||
buffer[0] = 'X';
|
||||
buffer[1] = 'T';
|
||||
file.write(buffer, 2);
|
||||
|
||||
// write header
|
||||
pointtype.serialize(file);
|
||||
|
||||
p[0] = voxelSize;
|
||||
p[1] = center[0];
|
||||
p[2] = center[1];
|
||||
p[3] = center[2];
|
||||
p[4] = size;
|
||||
|
||||
int *ip = reinterpret_cast<int*>(&(buffer[5 * sizeof(float)]));
|
||||
*ip = POINTDIM;
|
||||
|
||||
file.write(buffer, 5 * sizeof(float) + sizeof(int));
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < POINTDIM; i++) {
|
||||
p[i] = mins[i];
|
||||
}
|
||||
for (unsigned int i = 0; i < POINTDIM; i++) {
|
||||
p[i+POINTDIM] = maxs[i];
|
||||
}
|
||||
|
||||
file.write(buffer, 2*POINTDIM * sizeof(float));
|
||||
|
||||
// write root node
|
||||
serialize(file, *root);
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
void compactTree::serialize(std::ofstream &of, cbitoct &node) {
|
||||
char buffer[2];
|
||||
buffer[0] = node.valid;
|
||||
buffer[1] = node.leaf;
|
||||
of.write(buffer, 2);
|
||||
|
||||
// write children
|
||||
cbitunion<tshort> *children;
|
||||
cbitoct::getChildren(node, children);
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf write points
|
||||
tshort *points = children->getPoints();
|
||||
lint length = children->getLength();
|
||||
|
||||
of.write(reinterpret_cast<char*>(&length), sizeof(lint) );
|
||||
|
||||
of.write(reinterpret_cast<char*>(points), POINTDIM*length*sizeof(tshort) );
|
||||
|
||||
} else { // write child
|
||||
serialize(of, children->node);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
/**
|
||||
* Point Cloud Segmentation using Felzenszwalb-Huttenlocher Algorithm
|
||||
*
|
||||
* Copyright (C) Jacobs University Bremen
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
* @author Mihai-Cotizo Sima
|
||||
*/
|
||||
|
||||
#include <segmentation/FHGraph.h>
|
||||
#include <map>
|
||||
#include <omp.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
FHGraph::FHGraph(std::vector< Point >& ps, double weight(Point, Point), double sigma, double eps, int neighbors, float radius) :
|
||||
points( ps ), V( ps.size() )
|
||||
{
|
||||
/*
|
||||
* 1. create adjency list using a map<int, vector<half_edge> >
|
||||
* 2. use get_neighbors(e, max_dist) to get all the edges e' that are at a distance smaller than max_dist than e
|
||||
* 3. using all these edges, compute the gaussian smoothed weight
|
||||
* 4. insert the edges in a new list
|
||||
*/
|
||||
nr_neighbors = neighbors;
|
||||
this->radius = radius;
|
||||
|
||||
compute_neighbors(weight, eps);
|
||||
|
||||
|
||||
if ( sigma > 0.01 )
|
||||
{
|
||||
do_gauss(sigma);
|
||||
}
|
||||
else
|
||||
{
|
||||
without_gauss();
|
||||
}
|
||||
|
||||
adjency_list.clear();
|
||||
}
|
||||
|
||||
void FHGraph::compute_neighbors(double weight(Point, Point), double eps)
|
||||
{
|
||||
|
||||
adjency_list.reserve(points.size());
|
||||
adjency_list.resize(points.size());
|
||||
|
||||
ANNpointArray pa = annAllocPts(points.size(), 3);
|
||||
for (size_t i=0; i<points.size(); ++i)
|
||||
{
|
||||
pa[i] = new ANNcoord[3];
|
||||
pa[i][0] = points[i].x;
|
||||
pa[i][1] = points[i].y;
|
||||
pa[i][2] = points[i].z;
|
||||
}
|
||||
|
||||
ANNkd_tree t(pa, points.size(), 3);
|
||||
|
||||
if ( radius < 0 ) // Using knn search
|
||||
{
|
||||
nr_neighbors++;
|
||||
ANNidxArray n = new ANNidx[nr_neighbors];
|
||||
ANNdistArray d = new ANNdist[nr_neighbors];
|
||||
|
||||
for (size_t i=0; i<points.size(); ++i)
|
||||
{
|
||||
ANNpoint p = pa[i];
|
||||
|
||||
t.annkSearch(p, nr_neighbors, n, d, eps);
|
||||
|
||||
for (int j=0; j<nr_neighbors; ++j)
|
||||
{
|
||||
if ( n[j] == (int)i ) continue;
|
||||
|
||||
he e;
|
||||
e.x = n[j];
|
||||
e.w = weight(points[i], points[n[j]]);
|
||||
|
||||
adjency_list[i].push_back(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete[] n;
|
||||
delete[] d;
|
||||
}
|
||||
else // Using radius search
|
||||
{
|
||||
float sqradius = radius*radius;
|
||||
|
||||
|
||||
ANNidxArray n;
|
||||
ANNdistArray d;
|
||||
int nret;
|
||||
int total = 0;
|
||||
|
||||
const int MOD = 1000;
|
||||
int TMP = MOD;
|
||||
|
||||
for (size_t i=0; i<points.size(); ++i)
|
||||
{
|
||||
ANNpoint p = pa[i];
|
||||
|
||||
nret = t.annkFRSearch(p, sqradius, 0, NULL, NULL, eps);
|
||||
total += nret;
|
||||
|
||||
n = new ANNidx[nret];
|
||||
d = new ANNdist[nret];
|
||||
t.annkFRSearch(p, sqradius, nret, n, d, eps);
|
||||
|
||||
if ( nr_neighbors > 0 && nr_neighbors < nret )
|
||||
{
|
||||
random_shuffle(n, n+nret);
|
||||
nret = nr_neighbors;
|
||||
}
|
||||
|
||||
for (int j=0; j<nret; ++j)
|
||||
{
|
||||
if ( n[j] == (int)i ) continue;
|
||||
|
||||
he e;
|
||||
e.x = n[j];
|
||||
e.w = weight(points[i], points[n[j]]);
|
||||
|
||||
adjency_list[i].push_back(e);
|
||||
}
|
||||
|
||||
delete[] n;
|
||||
delete[] d;
|
||||
if ( TMP==0 )
|
||||
{
|
||||
TMP = MOD;
|
||||
cout << "Point " << i << "/" << V << ", or "<< (i*100.0 / V) << "%\r"; cout.flush();
|
||||
}
|
||||
TMP --;
|
||||
}
|
||||
cout << "Average nr of neighbors: " << (float) total / points.size() << endl;
|
||||
|
||||
}
|
||||
|
||||
annDeallocPts(pa);
|
||||
}
|
||||
|
||||
static double gauss(double x, double miu, double sigma)
|
||||
{
|
||||
double tmp = ((x-miu)/sigma);
|
||||
return exp(- .5 * tmp * tmp);
|
||||
}
|
||||
|
||||
static void normalize(std::vector<double>& v)
|
||||
{
|
||||
double s = 0;
|
||||
for (size_t i=0; i<v.size(); ++i)
|
||||
s += v[i];
|
||||
for (size_t i=0; i<v.size(); ++i)
|
||||
v[i] /= s;
|
||||
}
|
||||
|
||||
string tostr(int x)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void FHGraph::do_gauss(double sigma)
|
||||
{
|
||||
edges.reserve( V * nr_neighbors);
|
||||
list<he>::iterator k, j;
|
||||
vector<double> gauss_weight, edge_weight;
|
||||
edge e;
|
||||
#pragma omp parallel for private(j, k, e, gauss_weight, edge_weight) schedule(dynamic)
|
||||
for (int i=0; i<V; ++i)
|
||||
{
|
||||
for (j=adjency_list[i].begin();
|
||||
j!=adjency_list[i].end();
|
||||
j++)
|
||||
{
|
||||
|
||||
gauss_weight.clear();
|
||||
edge_weight.clear();
|
||||
|
||||
for (k=adjency_list[i].begin();
|
||||
k!=adjency_list[i].end();
|
||||
++k)
|
||||
{
|
||||
gauss_weight.push_back(gauss(k->w, j->w, sigma));
|
||||
edge_weight.push_back(k->w);
|
||||
}
|
||||
for (k=adjency_list[j->x].begin();
|
||||
k!=adjency_list[j->x].end();
|
||||
++k)
|
||||
{
|
||||
gauss_weight.push_back(gauss(k->w, j->w, sigma));
|
||||
edge_weight.push_back(k->w);
|
||||
}
|
||||
normalize(gauss_weight);
|
||||
|
||||
e.a = i; e.b = j->x;
|
||||
e.w = 0;
|
||||
for (size_t k=0; k<edge_weight.size(); ++k)
|
||||
e.w += gauss_weight[k] * edge_weight[k];
|
||||
|
||||
#pragma omp critical
|
||||
{
|
||||
edges.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FHGraph::without_gauss()
|
||||
{
|
||||
edges.reserve( V * nr_neighbors);
|
||||
list<he>::iterator j;
|
||||
edge e;
|
||||
|
||||
for (int i=0; i<V; ++i)
|
||||
{
|
||||
for (j=adjency_list[i].begin();
|
||||
j!=adjency_list[i].end();
|
||||
j++)
|
||||
{
|
||||
e.a = i; e.b = j->x; e.w = j->w;
|
||||
edges.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
edge* FHGraph::getGraph()
|
||||
{
|
||||
edge* ret = new edge[edges.size()];
|
||||
for (size_t i=0; i<edges.size(); ++i)
|
||||
ret[i] = edges[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
Point FHGraph::operator[](int index)
|
||||
{
|
||||
return points[index];
|
||||
}
|
||||
|
||||
int FHGraph::getNumPoints()
|
||||
{
|
||||
return V;
|
||||
}
|
||||
|
||||
int FHGraph::getNumEdges()
|
||||
{
|
||||
return edges.size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void vectorFree(T& t) {
|
||||
T tmp;
|
||||
t.swap(tmp);
|
||||
}
|
||||
|
||||
void FHGraph::dispose() {
|
||||
vectorFree(edges);
|
||||
vectorFree(points);
|
||||
vectorFree(adjency_list);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
IF (WITH_THERMO)
|
||||
find_package(OpenCV REQUIRED)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/cvblob)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include/shapes/)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include/thermo/)
|
||||
include_directories(/usr/include/)
|
||||
include_directories(/usr/include/opencv)
|
||||
|
||||
add_executable(caliboard caliboard.cc)
|
||||
add_executable(thermo thermo.cc)
|
||||
# add_executable(thermo thermo.cc src/cvaux.cpp src/cvblob.cpp src/cvcolor.cpp src/cvcontour.cpp src/cvlabel.cpp src/cvtrack.cpp)
|
||||
|
||||
IF(UNIX)
|
||||
target_link_libraries(caliboard scan shape newmat dl ANN)
|
||||
target_link_libraries(thermo scan shape newmat dl ANN)
|
||||
target_link_libraries(thermo cv cvaux cxcore GL GLU highgui cvblob scan ANN)
|
||||
ENDIF(UNIX)
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(caliboard scan shape newmat XGetopt ANN)
|
||||
target_link_libraries(thermo scan shape newmat XGetopt ANN)
|
||||
target_link_libraries(thermo cv cvaux cxcore GL GLU highgui cvblob scan ANN)
|
||||
ENDIF(WIN32)
|
||||
|
||||
|
||||
ENDIF(WITH_THERMO)
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* plane implementation
|
||||
*
|
||||
* Copyright (C) Dorit Borrmann
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Dorit Borrmann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#include <cfloat>
|
||||
#include <fstream>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#else
|
||||
#include "XGetopt.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
using std::ofstream;
|
||||
using std::flush;
|
||||
using std::cout;
|
||||
using std::string;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <strings.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "shapes/hough.h"
|
||||
#include "shapes/shape.h"
|
||||
#include "shapes/ransac.h"
|
||||
|
||||
enum plane_alg {
|
||||
RHT, SHT, PHT, PPHT, APHT, RANSAC
|
||||
};
|
||||
|
||||
void usage(char* prog) {
|
||||
#ifndef _MSC_VER
|
||||
const string bold("\033[1m");
|
||||
const string normal("\033[m");
|
||||
#else
|
||||
const string bold("");
|
||||
const string normal("");
|
||||
#endif
|
||||
cout << endl
|
||||
<< bold << "USAGE " << normal << endl
|
||||
<< " " << prog << " [options] directory" << endl << endl;
|
||||
cout << bold << "OPTIONS" << normal << endl
|
||||
|
||||
<< bold << " -f" << normal << " F, " << bold << "--format=" << normal << "F" << endl
|
||||
<< " using shared library F for input" << endl
|
||||
<< " (chose F from {uos, uos_map, uos_rgb, uos_frames, uos_map_frames, old, rts, rts_map, ifp, riegl_txt, riegl_rgb, riegl_bin, zahn, ply})" << endl
|
||||
<< endl
|
||||
<< bold << " -m" << normal << " NR, " << bold << "--max=" << normal << "NR" << endl
|
||||
<< " neglegt all data points with a distance larger than NR 'units'" << endl
|
||||
<< endl
|
||||
<< bold << " -M" << normal << " NR, " << bold << "--min=" << normal << "NR" << endl
|
||||
<< " neglegt all data points with a distance smaller than NR 'units'" << endl
|
||||
<< endl
|
||||
<< bold << " -p" << normal << " P, " << bold << "--plane=" << normal << "P" << endl
|
||||
<< " using algorithm P for plane detection" << endl
|
||||
<< " (chose P from {rht, sht, pht, ppht, apht, ran})" << endl
|
||||
<< endl
|
||||
<< bold << " -r" << normal << " NR, " << bold << "--reduce=" << normal << "NR" << endl
|
||||
<< " turns on octree based point reduction (voxel size=<NR>)" << endl
|
||||
<< endl
|
||||
<< bold << " -O" << normal << " NR (optional), " << bold << "--octree=" << normal << "NR (optional)" << endl
|
||||
<< " use randomized octree based point reduction (pts per voxel=<NR>)" << endl
|
||||
<< " requires " << bold << "-r" << normal <<" or " << bold << "--reduce" << endl
|
||||
<< endl
|
||||
<< bold << " -s" << normal << " NR, " << bold << "--start=" << normal << "NR" << endl
|
||||
<< " start at scan NR (i.e., neglects the first NR scans)" << endl
|
||||
<< " [ATTENTION: counting naturally starts with 0]" << endl
|
||||
<< endl
|
||||
<< bold << " -S, --scanserver" << normal << endl
|
||||
<< " Use the scanserver as an input method and handling of scan data" << endl
|
||||
<< endl
|
||||
<< endl << endl;
|
||||
|
||||
cout << bold << "EXAMPLES " << normal << endl
|
||||
<< " " << prog << " -m 500 -r 5 dat" << endl
|
||||
<< " " << prog << " --max=5000 -r 10.2 dat" << endl
|
||||
<< " " << prog << " -s 2 -e 10 -r dat" << endl << endl;
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses command line arguments needed for plane detection. For details about
|
||||
* the argument see usage().
|
||||
*/
|
||||
|
||||
int parseArgs(int argc, char **argv, string &dir, double &red, int &start, int
|
||||
&maxDist, int&minDist, int &octree, IOType &type, plane_alg &alg, bool
|
||||
&quiet, bool& scanserver)
|
||||
{
|
||||
bool reduced = false;
|
||||
int c;
|
||||
// from unistd.h:
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
/* options descriptor */
|
||||
// 0: no arguments, 1: required argument, 2: optional argument
|
||||
static struct option longopts[] = {
|
||||
{ "format", required_argument, 0, 'f' },
|
||||
{ "max", required_argument, 0, 'm' },
|
||||
{ "min", required_argument, 0, 'M' },
|
||||
{ "start", required_argument, 0, 's' },
|
||||
{ "reduce", required_argument, 0, 'r' },
|
||||
{ "plane", required_argument, 0, 'p' },
|
||||
{ "quiet", no_argument, 0, 'q' },
|
||||
{ "octree", optional_argument, 0, 'O' },
|
||||
{ "scanserver", no_argument, 0, 'S' },
|
||||
{ 0, 0, 0, 0} // needed, cf. getopt.h
|
||||
};
|
||||
|
||||
cout << endl;
|
||||
while ((c = getopt_long(argc, argv, "f:r:s:e:m:M:p:O:q", longopts, NULL)) != -1)
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
red = atof(optarg);
|
||||
reduced = true;
|
||||
break;
|
||||
case 's':
|
||||
start = atoi(optarg);
|
||||
if (start < 0) { cerr << "Error: Cannot start at a negative scan number.\n"; exit(1); }
|
||||
break;
|
||||
case 'f':
|
||||
try {
|
||||
type = formatname_to_io_type(optarg);
|
||||
} catch (...) { // runtime_error
|
||||
cerr << "Format " << optarg << " unknown." << endl;
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if(strcasecmp(optarg, "rht") == 0) alg = RHT;
|
||||
else if(strcasecmp(optarg, "sht") == 0) alg = SHT;
|
||||
else if(strcasecmp(optarg, "pht") == 0) alg = PHT;
|
||||
else if(strcasecmp(optarg, "ppht") == 0) alg = PPHT;
|
||||
else if(strcasecmp(optarg, "apht") == 0) alg = APHT;
|
||||
else if(strcasecmp(optarg, "ran") == 0) alg = RANSAC;
|
||||
else abort();
|
||||
break;
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
case 'm':
|
||||
maxDist = atoi(optarg);
|
||||
break;
|
||||
case 'O':
|
||||
if (optarg) {
|
||||
octree = atoi(optarg);
|
||||
} else {
|
||||
octree = 1;
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
minDist = atoi(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
scanserver = true;
|
||||
break;
|
||||
case '?':
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (optind != argc-1) {
|
||||
cerr << "\n*** Directory missing ***" << endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
dir = argv[optind];
|
||||
|
||||
#ifndef _MSC_VER
|
||||
if (dir[dir.length()-1] != '/') dir = dir + "/";
|
||||
#else
|
||||
if (dir[dir.length()-1] != '\\') dir = dir + "\\";
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function. The Hough Transform or RANSAC are called for the scan indicated as
|
||||
* argument.
|
||||
*
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
cout << "(c) Jacobs University Bremen, gGmbH, 2010" << endl << endl;
|
||||
|
||||
if (argc <= 1) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
// parsing the command line parameters
|
||||
// init, default values if not specified
|
||||
string dir;
|
||||
double red = -1.0;
|
||||
int start = 0;
|
||||
int maxDist = -1;
|
||||
int minDist = -1;
|
||||
int octree = 0;
|
||||
bool quiet = false;
|
||||
IOType type = UOS;
|
||||
plane_alg alg = RHT;
|
||||
bool scanserver = false;
|
||||
|
||||
cout << "Parse args" << endl;
|
||||
parseArgs(argc, argv, dir, red, start, maxDist, minDist, octree, type, alg, quiet, scanserver);
|
||||
int fileNr = start;
|
||||
string planedir = dir + "planes";
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int success = mkdir(planedir.c_str());
|
||||
#else
|
||||
int success = mkdir(planedir.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
#endif
|
||||
if(success == 0) {
|
||||
if(!quiet) {
|
||||
cout << "Writing planes to " << planedir << endl;
|
||||
}
|
||||
} else if(errno == EEXIST) {
|
||||
cout << "Directory " << planedir << " exists already. CONTINUE" << endl;
|
||||
} else {
|
||||
cerr << "Creating directory " << planedir << " failed" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Scan::openDirectory(scanserver, dir, type, fileNr, fileNr);
|
||||
Scan* scan = Scan::allScans.front();
|
||||
scan->setRangeFilter(maxDist, minDist);
|
||||
scan->setReductionParameter(red, octree);
|
||||
// scan->setSearchTreeParameter(nns_method, use_cuda);
|
||||
scan->toGlobal();
|
||||
|
||||
double id[16];
|
||||
M4identity(id);
|
||||
for(int i = 0; i < 10; i++) {
|
||||
scan->transform(id, Scan::ICP, 0); // write end pose
|
||||
}
|
||||
|
||||
if (!quiet) cout << "start plane detection" << endl;
|
||||
long starttime = GetCurrentTimeInMilliSec();
|
||||
if(alg >= RANSAC) {
|
||||
vector<double *> points;
|
||||
CollisionPlane<double> * plane;
|
||||
plane = new CollisionPlane<double>(1.0); // 1.0 cm maxdist
|
||||
Ransac(*plane, Scan::allScans[0], &points);
|
||||
starttime = (GetCurrentTimeInMilliSec() - starttime);
|
||||
|
||||
cout << "nr points " << points.size() << endl;
|
||||
double nx,ny,nz,d;
|
||||
plane->getPlane(nx,ny,nz,d);
|
||||
if(!quiet) cout << "DONE " << endl;
|
||||
|
||||
if(!quiet) cout << nx << " " << ny << " " << nz << " " << d << endl;
|
||||
|
||||
/*
|
||||
for (unsigned int i = 0; i < points.size(); i++) {
|
||||
cerr << points[i][0] << " " << points[i][1] << " " << points[i][2] << endl;
|
||||
}
|
||||
*/
|
||||
for(int i = points.size() - 1; i > -1; i--) {
|
||||
delete[] points[i];
|
||||
}
|
||||
|
||||
delete plane;
|
||||
} else {
|
||||
Hough hough(Scan::allScans[0], quiet);
|
||||
starttime = (GetCurrentTimeInMilliSec() - starttime);
|
||||
cout << "Time for Constructor call: " << starttime << endl;
|
||||
|
||||
starttime = GetCurrentTimeInMilliSec();
|
||||
if (!quiet) cout << "algorithm: " << alg << endl;
|
||||
// choose Hough method here
|
||||
switch(alg) {
|
||||
case RHT: hough.RHT();
|
||||
break;
|
||||
case SHT: hough.SHT();
|
||||
break;
|
||||
case PHT: hough.PHT();
|
||||
break;
|
||||
case PPHT: hough.PPHT();
|
||||
break;
|
||||
case APHT: hough.APHT();
|
||||
break;
|
||||
default: usage(argv[0]);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
hough.writePlanes(0);
|
||||
cout << "Write Planes done" << endl;
|
||||
starttime = (GetCurrentTimeInMilliSec() - starttime);
|
||||
}
|
||||
|
||||
cout << "Time for Plane Detection " << starttime << endl;
|
||||
delete Scan::allScans[0];
|
||||
Scan::allScans.clear();
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* kd implementation
|
||||
*
|
||||
* Copyright (C) Andreas Nuechter, Kai Lingemann, Thomas Escher
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief An optimized k-d tree implementation
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Thomas Escher Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include "slam6d/kd.h"
|
||||
#include "slam6d/globals.icc"
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
#include <algorithm>
|
||||
using std::swap;
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
// KDtree class static variables
|
||||
template<class PointData, class AccessorData, class AccessorFunc>
|
||||
KDParams KDTreeImpl<PointData, AccessorData, AccessorFunc>::params[MAX_OPENMP_NUM_THREADS];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Create a KD tree from the points pointed to by the array pts
|
||||
*
|
||||
* @param pts 3D array of points
|
||||
* @param n number of points
|
||||
*/
|
||||
KDtree::KDtree(double **pts, int n)
|
||||
{
|
||||
create(Void(), pts, n);
|
||||
}
|
||||
|
||||
KDtree::~KDtree()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the closest point within the tree,
|
||||
* wrt. the point given as first parameter.
|
||||
* @param _p point
|
||||
* @param maxdist2 maximal search distance.
|
||||
* @param threadNum Thread number, for parallelization
|
||||
* @return Pointer to the closest point
|
||||
*/
|
||||
double *KDtree::FindClosest(double *_p, double maxdist2, int threadNum) const
|
||||
{
|
||||
params[threadNum].closest = 0;
|
||||
params[threadNum].closest_d2 = maxdist2;
|
||||
params[threadNum].p = _p;
|
||||
_FindClosest(Void(), threadNum);
|
||||
return params[threadNum].closest;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/** @file
|
||||
* @brief Representation of the optimized k-d tree. MetaScan variant.
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Thomas Escher
|
||||
*/
|
||||
|
||||
#ifndef __KD_META_H__
|
||||
#define __KD_META_H__
|
||||
|
||||
#include "kdparams.h"
|
||||
#include "searchTree.h"
|
||||
#include "data_types.h"
|
||||
#include "kdTreeImpl.h"
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if !defined _OPENMP && defined OPENMP
|
||||
#define _OPENMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class Scan;
|
||||
|
||||
|
||||
struct Index {
|
||||
unsigned int s, i;
|
||||
inline void set(unsigned int _s, unsigned int _i) { s = _s; i = _i; }
|
||||
};
|
||||
|
||||
struct IndexAccessor {
|
||||
inline double* operator() (const DataXYZ* const* pts, const Index& i) const {
|
||||
return (*pts[i.s])[i.i];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The optimized k-d tree.
|
||||
*
|
||||
* A kD tree for points, with limited
|
||||
* capabilities (find nearest point to
|
||||
* a given point, or to a ray).
|
||||
**/
|
||||
class KDtreeMetaManaged :
|
||||
public SearchTree,
|
||||
private KDTreeImpl<const DataXYZ* const*, Index, IndexAccessor>
|
||||
{
|
||||
public:
|
||||
KDtreeMetaManaged(const vector<Scan*>& scans);
|
||||
virtual ~KDtreeMetaManaged();
|
||||
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
//! Aquires cached data first to pass on to the usual KDtree to process
|
||||
virtual double* FindClosest(double *_p, double maxdist2, int threadNum = 0) const;
|
||||
private:
|
||||
Scan** m_scans;
|
||||
DataXYZ** m_data;
|
||||
unsigned int m_size;
|
||||
|
||||
//! Mutex for safely reducing points just once in a multithreaded environment
|
||||
boost::mutex m_mutex_locking;
|
||||
volatile unsigned int m_count_locking;
|
||||
|
||||
// constructor initializer list hacks
|
||||
Index* m_temp_indices;
|
||||
Index* prepareTempIndices(const vector<Scan*>& scans);
|
||||
unsigned int getPointsSize(const vector<Scan*>& scans);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,297 @@
|
|||
/**
|
||||
* Point Cloud Segmentation using Felzenszwalb-Huttenlocher Algorithm
|
||||
*
|
||||
* Copyright (C) Jacobs University Bremen
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
* @author Billy Okal <b.okal@jacobs-university.de>
|
||||
* @author Mihai-Cotizo Sima
|
||||
* @file fhsegmentation.cc
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <errno.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <slam6d/io_types.h>
|
||||
#include <slam6d/globals.icc>
|
||||
#include <slam6d/scan.h>
|
||||
#include <scanserver/clientInterface.h>
|
||||
|
||||
#include <segmentation/FHGraph.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#else
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace std;
|
||||
|
||||
/// validate IO types
|
||||
void validate(boost::any& v, const std::vector<std::string>& values,
|
||||
IOType*, int) {
|
||||
if (values.size() == 0)
|
||||
throw std::runtime_error("Invalid model specification");
|
||||
string arg = values.at(0);
|
||||
try {
|
||||
v = formatname_to_io_type(arg.c_str());
|
||||
} catch (...) { // runtime_error
|
||||
throw std::runtime_error("Format " + arg + " unknown.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse commandline options
|
||||
void parse_options(int argc, char **argv, int &start, int &end, bool &scanserver, int &max_dist, int &min_dist, string &dir,
|
||||
IOType &iotype, float &sigma, int &k, int &neighbors, float &eps, float &radius, int &min_size)
|
||||
{
|
||||
/// ----------------------------------
|
||||
/// set up program commandline options
|
||||
/// ----------------------------------
|
||||
po::options_description cmd_options("Usage: fhsegmentation <options> where options are (default values in brackets)");
|
||||
cmd_options.add_options()
|
||||
("help,?", "Display this help message")
|
||||
("start,s", po::value<int>(&start)->default_value(0), "Start at scan number <arg>")
|
||||
("end,e", po::value<int>(&end)->default_value(-1), "Stop at scan number <arg>")
|
||||
("scanserver,S", po::value<bool>(&scanserver)->default_value(false), "Use the scanserver as an input method")
|
||||
("format,f", po::value<IOType>(&iotype)->default_value(UOS),
|
||||
"using shared library <arg> for input. (chose format from [uos|uosr|uos_map|"
|
||||
"uos_rgb|uos_frames|uos_map_frames|old|rts|rts_map|ifp|"
|
||||
"riegl_txt|riegl_rgb|riegl_bin|zahn|ply])")
|
||||
("max,M", po::value<int>(&max_dist)->default_value(-1),"neglegt all data points with a distance larger than <arg> 'units")
|
||||
("min,m", po::value<int>(&min_dist)->default_value(-1), "neglegt all data points with a distance smaller than <arg> 'units")
|
||||
("K,k", po::value<int>(&k)->default_value(1), "<arg> value of K value used in the FH segmentation")
|
||||
("neighbors,N", po::value<int>(&neighbors)->default_value(1), "use approximate <arg>-nearest neighbors search or limit the number of points")
|
||||
("sigma,v", po::value<float>(&sigma)->default_value(1.0), "Set the Gaussian variance for smoothing to <arg>")
|
||||
("radius,r", po::value<float>(&radius)->default_value(-1.0), "Set the range of radius search to <arg>")
|
||||
("eps,E", po::value<float>(&eps)->default_value(1.0), "Set error threshold used by the AKNN algorithm to <arg>")
|
||||
("minsize,z", po::value<int>(&min_size)->default_value(0), "Keep segments of size at least <arg>")
|
||||
;
|
||||
|
||||
po::options_description hidden("Hidden options");
|
||||
hidden.add_options()
|
||||
("input-dir", po::value<string>(&dir), "input dir");
|
||||
|
||||
po::positional_options_description pd;
|
||||
pd.add("input-dir", 1);
|
||||
|
||||
po::options_description all;
|
||||
all.add(cmd_options).add(hidden);
|
||||
|
||||
po::variables_map vmap;
|
||||
po::store(po::command_line_parser(argc, argv).options(all).positional(pd).run(), vmap);
|
||||
po::notify(vmap);
|
||||
|
||||
if (vmap.count("help")) {
|
||||
cout << cmd_options << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// read scan path
|
||||
if (dir[dir.length()-1] != '/') dir = dir + "/";
|
||||
|
||||
}
|
||||
|
||||
/// distance measures
|
||||
double weight1(Point a, Point b)
|
||||
{
|
||||
return a.distance(b);
|
||||
}
|
||||
|
||||
double weight2(Point a, Point b)
|
||||
{
|
||||
return a.distance(b) * .5 + fabs(a.reflectance-b.reflectance) * .5;
|
||||
}
|
||||
|
||||
|
||||
/// Write a pose file with the specofied name
|
||||
void writePoseFiles(string dir, const double* rPos, const double* rPosTheta, int num, int outnum)
|
||||
{
|
||||
for (int i = outnum; i < num; i++) {
|
||||
string poseFileName = dir + "segments/scan" + to_string(i, 3) + ".pose";
|
||||
ofstream posout(poseFileName.c_str());
|
||||
|
||||
posout << rPos[0] << " "
|
||||
<< rPos[1] << " "
|
||||
<< rPos[2] << endl
|
||||
<< deg(rPosTheta[0]) << " "
|
||||
<< deg(rPosTheta[1]) << " "
|
||||
<< deg(rPosTheta[2]) << endl;
|
||||
posout.clear();
|
||||
posout.close();
|
||||
}
|
||||
}
|
||||
|
||||
/// write scan files for all segments
|
||||
void writeScanFiles(string dir, int outnum, const vector<vector<Point>* > cloud)
|
||||
{
|
||||
for (int i = outnum, j = 0; i < (int)cloud.size() && j < (int)cloud.size(); i++, j++) {
|
||||
vector<Point>* segment = cloud[j];
|
||||
string scanFileName = dir + "segments/scan" + to_string(i,3) + ".3d";
|
||||
ofstream scanout(scanFileName.c_str());
|
||||
|
||||
for (int k = 0; k < (int)segment->size(); k++) {
|
||||
Point p = segment->at(k);
|
||||
scanout << p.x << " " << p.y << " " << p.z << endl;
|
||||
}
|
||||
scanout.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// =============================================
|
||||
/// Main
|
||||
/// =============================================
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int start, end;
|
||||
bool scanserver;
|
||||
int max_dist, min_dist;
|
||||
string dir;
|
||||
IOType iotype;
|
||||
float sigma;
|
||||
int k, neighbors;
|
||||
float eps;
|
||||
float radius;
|
||||
int min_size;
|
||||
|
||||
parse_options(argc, argv, start, end, scanserver, max_dist, min_dist,
|
||||
dir, iotype, sigma, k, neighbors, eps, radius, min_size);
|
||||
|
||||
/// ----------------------------------
|
||||
/// Prepare and read scans
|
||||
/// ----------------------------------
|
||||
if (scanserver) {
|
||||
try {
|
||||
ClientInterface::create();
|
||||
} catch(std::runtime_error& e) {
|
||||
cerr << "ClientInterface could not be created: " << e.what() << endl;
|
||||
cerr << "Start the scanserver first." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Make directory for saving the scan segments
|
||||
string segdir = dir + "segments";
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int success = mkdir(segdir.c_str());
|
||||
#else
|
||||
int success = mkdir(segdir.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
#endif
|
||||
if(success == 0) {
|
||||
cout << "Writing segments to " << segdir << endl;
|
||||
} else if(errno == EEXIST) {
|
||||
cout << "WARN: Directory " << segdir << " exists already. Contents will be overwriten" << endl;
|
||||
} else {
|
||||
cerr << "Creating directory " << segdir << " failed" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/// Read the scans
|
||||
Scan::openDirectory(scanserver, dir, iotype, start, end);
|
||||
if(Scan::allScans.size() == 0) {
|
||||
cerr << "No scans found. Did you use the correct format?" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/// --------------------------------------------
|
||||
/// Initialize and perform segmentation
|
||||
/// --------------------------------------------
|
||||
std::vector<Scan*>::iterator it = Scan::allScans.begin();
|
||||
int outscan = start;
|
||||
|
||||
for( ; it != Scan::allScans.end(); ++it) {
|
||||
Scan* scan = *it;
|
||||
const double* rPos = scan->get_rPos();
|
||||
const double* rPosTheta = scan->get_rPosTheta();
|
||||
|
||||
/// read scan into points
|
||||
DataXYZ xyz(scan->get("xyz"));
|
||||
vector<Point> points;
|
||||
points.reserve(xyz.size());
|
||||
|
||||
for(unsigned int j = 0; j < xyz.size(); j++) {
|
||||
Point p(xyz[j][0], xyz[j][1], xyz[j][2]);
|
||||
points.push_back(p);
|
||||
}
|
||||
|
||||
/// create the graph and get the segments
|
||||
cout << "creating graph" << endl;
|
||||
FHGraph sgraph(points, weight2, sigma, eps, neighbors, radius);
|
||||
|
||||
cout << "segmenting graph" << endl;
|
||||
edge* sedges = sgraph.getGraph();
|
||||
universe* segmented = segment_graph(sgraph.getNumPoints(),
|
||||
sgraph.getNumEdges(),
|
||||
sedges, k);
|
||||
|
||||
cout << "post processing" << endl;
|
||||
for (int i = 0; i < sgraph.getNumEdges(); ++i)
|
||||
{
|
||||
int a = sedges[i].a;
|
||||
int b = sedges[i].b;
|
||||
|
||||
int aa = segmented->find(a);
|
||||
int bb = segmented->find(b);
|
||||
|
||||
if ( (aa!=bb) &&
|
||||
(segmented->size(aa) < min_size ||
|
||||
segmented->size(bb) < min_size) )
|
||||
segmented->join(aa, bb);
|
||||
}
|
||||
|
||||
delete[] sedges;
|
||||
|
||||
int nr = segmented->num_sets();
|
||||
cout << "Obtained " << nr << " segment(s)" << endl;
|
||||
|
||||
/// write point clouds with segments
|
||||
vector< vector<Point>* > clouds;
|
||||
clouds.reserve(nr);
|
||||
for (int i=0; i<nr; ++i)
|
||||
clouds.push_back( new vector<Point> );
|
||||
|
||||
map<int, int> components2cloud;
|
||||
int kk = 0;
|
||||
|
||||
for (int i = 0; i < sgraph.getNumPoints(); ++i)
|
||||
{
|
||||
int component = segmented->find(i);
|
||||
if ( components2cloud.find(component)==components2cloud.end() )
|
||||
{
|
||||
components2cloud[component] = kk++;
|
||||
clouds[components2cloud[component]]->reserve(segmented->size(component));
|
||||
}
|
||||
clouds[components2cloud[component]]->push_back(sgraph[i]);
|
||||
}
|
||||
|
||||
// pose file (repeated for the number of segments
|
||||
writePoseFiles(dir, rPos, rPosTheta, clouds.size(), outscan);
|
||||
// scan files for all segments
|
||||
writeScanFiles(dir, outscan, clouds);
|
||||
|
||||
outscan += clouds.size();
|
||||
|
||||
/// clean up
|
||||
sgraph.dispose();
|
||||
}
|
||||
|
||||
// shutdown everything
|
||||
if (scanserver)
|
||||
ClientInterface::destroy();
|
||||
else
|
||||
Scan::closeDirectory();
|
||||
|
||||
cout << "Normal program end" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
2497
.svn/pristine/21/21c8eebf31843a931b8d4277e259942c97b42530.svn-base
Normal file
2497
.svn/pristine/21/21c8eebf31843a931b8d4277e259942c97b42530.svn-base
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,982 @@
|
|||
/*
|
||||
* veloscan implementation
|
||||
*
|
||||
* Copyright (C) Andreas Nuechter, Li Wei, Li Ming
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of a 3D scan and of 3D scan matching in all variants
|
||||
* @author Li Wei, Wuhan University, China
|
||||
* @author Li Ming, Wuhan University, China
|
||||
* @author Andreas Nuechter. Jacobs University Bremen, Germany
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef OPENMP
|
||||
#define _OPENMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
#include <sstream>
|
||||
using std::stringstream;
|
||||
|
||||
#include "veloslam/veloscan.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#else
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
using std::flush;
|
||||
|
||||
#include "slam6d/Boctree.h"
|
||||
#include "veloslam/veloscan.h"
|
||||
#include "veloslam/pcddump.h"
|
||||
#include "veloslam/trackermanager.h"
|
||||
#include "veloslam/clusterboundingbox.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#else
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
using std::flush;
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <GL/glut.h>
|
||||
#else
|
||||
#include <GL/freeglut.h>
|
||||
#endif
|
||||
#include "veloslam/velodefs.h"
|
||||
#include "veloslam/color_util.h"
|
||||
|
||||
int scanCount =0;
|
||||
TrackerManager trackMgr;
|
||||
float absf(float a)
|
||||
{
|
||||
return a>0?a:-a;
|
||||
}
|
||||
|
||||
Trajectory::Trajectory()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* default Constructor
|
||||
*/
|
||||
VeloScan::VeloScan()
|
||||
// : BasicScan()
|
||||
{
|
||||
isTrackerHandled =false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Desctuctor
|
||||
*/
|
||||
VeloScan::~VeloScan()
|
||||
{
|
||||
FreeAllCellAndCluterMemory();
|
||||
}
|
||||
|
||||
int VeloScan::DeletePoints()
|
||||
{
|
||||
FreeAllCellAndCluterMemory();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*/
|
||||
/*
|
||||
VeloScan::VeloScan(const VeloScan& s)
|
||||
: BasicScan(s)
|
||||
{ }
|
||||
*/
|
||||
|
||||
int VeloScan::TransferToCellArray(int maxDist, int minDist)
|
||||
{
|
||||
#define DefaultColumnSize 360
|
||||
Point P;
|
||||
DataXYZ xyz(get("xyz"));
|
||||
int size= xyz.size();
|
||||
|
||||
int columnSize= 360; //cfg.cfgPlaneDetect.ColumnSize;
|
||||
int CellSize= 50; //cfg.cfgPlaneDetect.CellSize;
|
||||
|
||||
int MinRad=minDist; //cfg.cfgPlaneDetect.MinRad;
|
||||
int MaxRad=maxDist; //cfg.cfgPlaneDetect.MaxRad
|
||||
|
||||
if((MaxRad-MinRad)%CellSize!=0)
|
||||
CellSize=10;
|
||||
|
||||
int i,j,count=0;
|
||||
int CellNumber=(MaxRad-MinRad)/CellSize;
|
||||
float flag;
|
||||
int offset;
|
||||
|
||||
if(columnSize==0)
|
||||
return -1;
|
||||
|
||||
if(columnSize%360!=0)
|
||||
columnSize=DefaultColumnSize;
|
||||
|
||||
int sectionSize=columnSize/8;
|
||||
|
||||
scanCellArray.resize(columnSize);
|
||||
for(i=0; i<columnSize; ++i)
|
||||
scanCellArray[i].resize(CellNumber);
|
||||
|
||||
float inc=(M_PI*2)/columnSize;
|
||||
|
||||
vector<float> tanv;
|
||||
vector<float>::iterator result;
|
||||
|
||||
for(i=0; i<sectionSize; ++i)
|
||||
{
|
||||
tanv.push_back(tan(inc*i));
|
||||
}
|
||||
|
||||
int diff;
|
||||
|
||||
for(i=0; i<size; ++i)
|
||||
{
|
||||
count++;
|
||||
Point pt;
|
||||
pt.x = xyz[i][0];
|
||||
pt.y = xyz[i][1];
|
||||
pt.z = xyz[i][2];
|
||||
|
||||
pt.point_id = i; //important for find point in scans ---raw points
|
||||
|
||||
pt.rad = sqrt(pt.x*pt.x + pt.z*pt.z);
|
||||
pt.tan_theta = pt.z/pt.x ;
|
||||
|
||||
if(pt.rad <=MinRad || pt.rad>=MaxRad)
|
||||
continue;
|
||||
|
||||
// some point losted which on the vline or hline
|
||||
if(pt.x >=0 && pt.z>=0 )
|
||||
{
|
||||
if(pt.x > pt.z)
|
||||
{
|
||||
flag= pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset=result-tanv.begin();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
flag=1/pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
diff=result-tanv.begin();
|
||||
offset=sectionSize*2-1-(diff);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else if(pt.x <= 0 && pt.z >=0)
|
||||
{
|
||||
if(-pt.x>pt.z)
|
||||
{
|
||||
flag=-pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize*3;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset=sectionSize*4-1-(result-tanv.begin());
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
flag=1/-pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize*3-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset=sectionSize*2+(result-tanv.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(pt.x<=0 && pt.z<=0)
|
||||
{
|
||||
if(-pt.x>-pt.z)
|
||||
{
|
||||
flag=pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize*5-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset=sectionSize*4+(result-tanv.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
flag=1/pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize*5;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset=sectionSize*6-1-(result-tanv.begin());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else if(pt.x>=0&&pt.z<=0)
|
||||
{
|
||||
if(pt.x>-pt.z)
|
||||
{
|
||||
flag=-pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize*7;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset=sectionSize*8-1-(result-tanv.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
flag=1/-pt.tan_theta;
|
||||
result=upper_bound(tanv.begin(),tanv.end(),flag);
|
||||
if(result==tanv.end())
|
||||
{
|
||||
offset=sectionSize*7-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset=sectionSize*6+(result-tanv.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int k= (int)((pt.rad-MinRad)/(CellSize*1.0));
|
||||
scanCellArray[offset][k].push_back(&pt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int VeloScan::CalcCellFeature(cell& cellobj, cellFeature& f)
|
||||
{
|
||||
int outlier;
|
||||
float lastMaxY;
|
||||
f.size=cellobj.size();
|
||||
f.cellType=0;
|
||||
|
||||
if(f.size==0)
|
||||
{
|
||||
f.cellType|=CELL_TYPE_INVALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f.ave_x= f.ave_y = f.ave_z=0.0;
|
||||
f.delta_y=0;
|
||||
|
||||
int i=0;
|
||||
for(i=0; i<f.size; ++i)
|
||||
{
|
||||
f.ave_x+=cellobj[i]->x;
|
||||
f.ave_z+=cellobj[i]->z;
|
||||
f.ave_y+=cellobj[i]->y;
|
||||
|
||||
// if(cellobj[i]->type & POINT_TYPE_BELOW_R)
|
||||
// f.cellType |=CELL_TYPE_BELOW_R;
|
||||
|
||||
if(i==0)
|
||||
{
|
||||
outlier=0;
|
||||
f.min_x=f.max_x=cellobj[i]->x;
|
||||
f.min_z=f.max_z=cellobj[i]->z;
|
||||
lastMaxY=f.min_y=f.max_y=cellobj[i]->y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(f.max_x<cellobj[i]->x) f.max_x=cellobj[i]->x;
|
||||
|
||||
if(f.min_x>cellobj[i]->x) f.min_x=cellobj[i]->x;
|
||||
|
||||
if(f.max_z<cellobj[i]->z) f.max_z=cellobj[i]->z;
|
||||
|
||||
if(f.min_z>cellobj[i]->z) f.min_z=cellobj[i]->z;
|
||||
|
||||
if(f.max_y<cellobj[i]->y)
|
||||
{
|
||||
lastMaxY=f.max_y;
|
||||
f.max_y=cellobj[i]->y;
|
||||
outlier=i;
|
||||
}
|
||||
|
||||
if(f.min_y>cellobj[i]->y)
|
||||
f.min_y=cellobj[i]->y;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(f.size>1)
|
||||
{
|
||||
int y=f.ave_y-cellobj[outlier]->y;
|
||||
y/=(f.size-1)*1.0;
|
||||
|
||||
if(cellobj[outlier]->y-y<50)
|
||||
{
|
||||
outlier=-1;
|
||||
f.ave_y/=f.size*1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
f.max_y=lastMaxY;
|
||||
f.ave_y=y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outlier=-1;
|
||||
f.ave_y/=f.size*1.0;
|
||||
}
|
||||
|
||||
f.ave_x/=f.size*1.0;
|
||||
f.ave_z/=f.size*1.0;
|
||||
|
||||
for(i=0; i<f.size; ++i)
|
||||
{
|
||||
if(i==outlier)
|
||||
continue;
|
||||
f.delta_y+= absf(cellobj[i]->y - f.ave_y);
|
||||
}
|
||||
|
||||
float threshold;
|
||||
threshold=f.delta_y;
|
||||
|
||||
float GridThresholdGroundDetect =120;
|
||||
if( threshold > GridThresholdGroundDetect)
|
||||
f.cellType =CELL_TYPE_STATIC;
|
||||
else
|
||||
f.cellType =CELL_TYPE_GROUND;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int VeloScan::CalcScanCellFeature()
|
||||
{
|
||||
int i,j;
|
||||
|
||||
if( scanCellArray.size()==0)
|
||||
return -1;
|
||||
|
||||
int columnSize=scanCellArray.size();
|
||||
int cellNumber=scanCellArray[0].size();
|
||||
|
||||
if( scanCellFeatureArray.size()==0)
|
||||
{
|
||||
scanCellFeatureArray.resize(columnSize);
|
||||
for(i=0; i<columnSize; ++i)
|
||||
scanCellFeatureArray[i].resize(cellNumber);
|
||||
}
|
||||
|
||||
for(j=0; j <columnSize; j++)
|
||||
{
|
||||
cellColumn &column=scanCellArray[j];
|
||||
cellNumber=column.size();
|
||||
for( i=0; i<cellNumber; i++)
|
||||
{
|
||||
cell &cellObj=scanCellArray[j][i];
|
||||
cellFeature &feature=scanCellFeatureArray[j][i];
|
||||
|
||||
feature.columnID=j;
|
||||
feature.cellID=i;
|
||||
|
||||
feature.pCell=&cellObj;
|
||||
CalcCellFeature(cellObj,feature);
|
||||
|
||||
// if( feature.delta_y > 120)
|
||||
// {
|
||||
// scanCellFeatureArray[j][i].cellType |= CELL_TYPE_STATIC;
|
||||
// for(int k=0;k <scanCellArray[j][i].size(); k++)
|
||||
// scanCellArray[j][i][k]->type |= POINT_TYPE_ABOVE_DELTA_Y;
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VeloScan::SearchNeigh(cluster& clu,charvv& flagvv,int i,int j)
|
||||
{
|
||||
int columnSize=scanCellArray.size();
|
||||
int cellNumber=scanCellArray[0].size();
|
||||
|
||||
if(i==-1)
|
||||
i= columnSize-1;
|
||||
|
||||
if(i==columnSize)
|
||||
i= 0;
|
||||
|
||||
|
||||
if(i<0||i>=columnSize||j<0||j>=cellNumber)
|
||||
return 0;
|
||||
|
||||
if(flagvv[i][j]==1)
|
||||
return 0;
|
||||
if(scanCellFeatureArray[i][j].size==0)
|
||||
{
|
||||
flagvv[i][j]=1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(scanCellFeatureArray[i][j].cellType & CELL_TYPE_STATIC)
|
||||
{
|
||||
flagvv[i][j]=1;
|
||||
|
||||
clu.push_back(&scanCellFeatureArray[i][j]);
|
||||
|
||||
SearchNeigh(clu,flagvv,i-1,j-1);
|
||||
SearchNeigh(clu,flagvv,i-1,j);
|
||||
SearchNeigh(clu,flagvv,i-1,j+1);
|
||||
SearchNeigh(clu,flagvv,i,j-1);
|
||||
SearchNeigh(clu,flagvv,i,j+1);
|
||||
SearchNeigh(clu,flagvv,i+1,j-1);
|
||||
SearchNeigh(clu,flagvv,i+1,j);
|
||||
SearchNeigh(clu,flagvv,i+1,j+1);
|
||||
|
||||
SearchNeigh(clu,flagvv,i,j+2);
|
||||
SearchNeigh(clu,flagvv,i,j-2);
|
||||
SearchNeigh(clu,flagvv,i+2,j);
|
||||
SearchNeigh(clu,flagvv,i-2,j);
|
||||
|
||||
//SearchNeigh(clu,flagvv,i,j+3);
|
||||
//SearchNeigh(clu,flagvv,i,j-3);
|
||||
//SearchNeigh(clu,flagvv,i+3,j);
|
||||
//SearchNeigh(clu,flagvv,i-3,j);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VeloScan::CalcClusterFeature(cluster& clu, clusterFeature& f)
|
||||
{
|
||||
f.size=clu.size();
|
||||
|
||||
if(f.size==0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
f.clusterType=0;
|
||||
f.pointNumber=0;
|
||||
|
||||
f.avg_x =0; f.avg_y=0; f.avg_z=0;
|
||||
|
||||
int i=0;
|
||||
for(i=0; i<f.size; ++i)
|
||||
{
|
||||
f.avg_x += clu[i]->ave_x;
|
||||
f.avg_y += clu[i]->ave_y;
|
||||
f.avg_z += clu[i]->ave_z;
|
||||
|
||||
if(i==0)
|
||||
{
|
||||
f.min_x=f.max_x=clu[i]->min_x;
|
||||
f.min_z=f.max_z=clu[i]->min_z;
|
||||
f.min_y=f.max_y=clu[i]->min_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(f.max_x<clu[i]->max_x)
|
||||
f.max_x=clu[i]->max_x;
|
||||
|
||||
if(f.min_x>clu[i]->min_x)
|
||||
f.min_x=clu[i]->min_x;
|
||||
|
||||
if(f.max_z<clu[i]->max_z)
|
||||
f.max_z=clu[i]->max_z;
|
||||
|
||||
if(f.min_z>clu[i]->min_z)
|
||||
f.min_z=clu[i]->min_z;
|
||||
|
||||
if(f.max_y<clu[i]->max_y)
|
||||
f.max_y=clu[i]->max_y;
|
||||
|
||||
if(f.min_y>clu[i]->min_y)
|
||||
f.min_y=clu[i]->min_y;
|
||||
|
||||
}
|
||||
f.pointNumber+=clu[i]->size;
|
||||
f.theta += clu[i]->size*clu[i]->columnID;
|
||||
f.radius += clu[i]->size*clu[i]->cellID;
|
||||
}
|
||||
|
||||
f.size_x=f.max_x-f.min_x;
|
||||
f.size_z=f.max_z-f.min_z;
|
||||
f.size_y=f.max_y-f.min_y;
|
||||
|
||||
f.avg_x /= f.size;
|
||||
f.avg_y /= f.size;
|
||||
f.avg_z /= f.size;
|
||||
|
||||
f.theta=f.theta / (f.pointNumber*1.0);
|
||||
f.radius=f.radius / (f.pointNumber*1.0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VeloScan::FindAndCalcScanClusterFeature()
|
||||
{
|
||||
int i,j;
|
||||
|
||||
if( scanCellArray.size()==0)
|
||||
return -1;
|
||||
|
||||
int columnSize=scanCellArray.size();
|
||||
int cellNumber=scanCellArray[0].size();
|
||||
|
||||
charvv searchedFlag;
|
||||
searchedFlag.resize(columnSize);
|
||||
for(i=0; i<columnSize; ++i)
|
||||
searchedFlag[i].resize(cellNumber,0);
|
||||
|
||||
for(i=0; i<columnSize; ++i)
|
||||
{
|
||||
for(j=0; j<cellNumber; ++j)
|
||||
{
|
||||
cluster clu;
|
||||
SearchNeigh(clu,searchedFlag,i,j);
|
||||
if(clu.size())
|
||||
scanClusterArray.push_back(clu);
|
||||
}
|
||||
}
|
||||
|
||||
int clustersize=scanClusterArray.size();
|
||||
if(scanClusterFeatureArray.size()==0)
|
||||
scanClusterFeatureArray.resize(clustersize);
|
||||
|
||||
cout<<"clusterSize:"<<clustersize<<endl;
|
||||
for(i=0; i<clustersize; ++i)
|
||||
{
|
||||
CalcClusterFeature(scanClusterArray[i],scanClusterFeatureArray[i]);
|
||||
// BoundingBox clusterBox;
|
||||
// clusterBox.CalBestRectangleBox(scanClusterArray[i],scanClusterFeatureArray[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VeloScan::FreeAllCellAndCluterMemory()
|
||||
{
|
||||
int i,j;
|
||||
int columnSize=scanCellArray.size();
|
||||
int cellNumber=scanCellArray[0].size();
|
||||
|
||||
for(j=0; j <columnSize; j++)
|
||||
{
|
||||
cellColumn &column=scanCellArray[j];
|
||||
cellFeatureColumn &columnFeature=scanCellFeatureArray[j];
|
||||
|
||||
cellNumber=column.size();
|
||||
for( i=0; i<cellNumber; i++)
|
||||
{
|
||||
cell &cellObj=scanCellArray[j][i];
|
||||
cellFeature &feature=scanCellFeatureArray[j][i];
|
||||
cellObj.clear();
|
||||
|
||||
}
|
||||
column.clear();
|
||||
columnFeature.clear();
|
||||
}
|
||||
|
||||
scanCellArray.clear();
|
||||
scanCellFeatureArray.clear();
|
||||
int ClusterSize=scanClusterArray.size();
|
||||
for(j=0; j <ClusterSize; j++)
|
||||
{
|
||||
cluster &cludata=scanClusterArray[j];
|
||||
clusterFeature &clu=scanClusterFeatureArray[j];
|
||||
cludata.clear();
|
||||
// clu.clear();
|
||||
}
|
||||
scanClusterArray.clear();
|
||||
scanClusterFeatureArray.clear();
|
||||
}
|
||||
|
||||
void VeloScan::calcReducedPoints_byClassifi(double voxelSize, int nrpts, PointType pointtype)
|
||||
{
|
||||
// only copy the points marked POINT_TYPE_STATIC_OBJECT
|
||||
int realCount =0;
|
||||
|
||||
// get xyz to start the scan load, separated here for time measurement
|
||||
DataXYZ xyz(get("xyz"));
|
||||
DataType Pt(get("type"));
|
||||
|
||||
// if the scan hasn't been loaded we can't calculate anything
|
||||
if(xyz.size() == 0)
|
||||
throw runtime_error("Could not calculate reduced points, XYZ data is empty");
|
||||
|
||||
for (int i = 0; i < xyz.size(); i++)
|
||||
{
|
||||
if( Pt[i] & POINT_TYPE_STATIC_OBJECT)
|
||||
{
|
||||
realCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// load only static part of scans in point_red for icp6D
|
||||
DataXYZ xyz_t(create("xyz reduced", sizeof(double)*3*realCount));
|
||||
realCount=0;
|
||||
int j=0;
|
||||
for (int i = 0; i < xyz.size(); i++)
|
||||
{
|
||||
if( Pt[i] & POINT_TYPE_STATIC_OBJECT)
|
||||
{
|
||||
xyz_t[j][0] = xyz[i][0];
|
||||
xyz_t[j][1] = xyz[i][1];
|
||||
xyz_t[j][2] = xyz[i][2];
|
||||
j++;
|
||||
realCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// build octree-tree from CurrentScan
|
||||
// put full data into the octtree
|
||||
BOctTree<double> *oct = new BOctTree<double>(PointerArray<double>(xyz_t).get(),
|
||||
xyz_t.size(), reduction_voxelSize, reduction_pointtype);
|
||||
|
||||
vector<double*> center;
|
||||
center.clear();
|
||||
|
||||
if (reduction_nrpts > 0) {
|
||||
if (reduction_nrpts == 1) {
|
||||
oct->GetOctTreeRandom(center);
|
||||
} else {
|
||||
oct->GetOctTreeRandom(center, reduction_nrpts);
|
||||
}
|
||||
} else {
|
||||
oct->GetOctTreeCenter(center);
|
||||
}
|
||||
|
||||
// storing it as reduced scan
|
||||
unsigned int size = center.size();
|
||||
DataXYZ xyz_r(create("xyz reduced", sizeof(double)*3*size));
|
||||
for(unsigned int i = 0; i < size; ++i) {
|
||||
for(unsigned int j = 0; j < 3; ++j) {
|
||||
xyz_r[i][j] = center[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
delete oct;
|
||||
}
|
||||
|
||||
bool findBusCluster(clusterFeature &glu, cluster &gluData)
|
||||
{
|
||||
/* double labelSVM;
|
||||
for(int i=0;i<360;i++)
|
||||
{
|
||||
nod[i].index=i+1;
|
||||
nod[i].value=intersectionFeature[i].slashLength/slashMaxLength;
|
||||
}
|
||||
nod[360].index=-1;
|
||||
labelSVM= svm_predict(m,nod);
|
||||
|
||||
ofstream output;
|
||||
output.open("intersection.txt");
|
||||
output<<"labelSVM:"<<labelSVM<<endl;
|
||||
for(int j=0;j<360;j++)
|
||||
output<<j<<":"<<" "<<nod[j].value;
|
||||
output.close();
|
||||
|
||||
if(labelSVM>0.5)
|
||||
cout<<"intersection"<<endl;
|
||||
else
|
||||
cout<<"segment"<<endl;
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
//long objcount =0;
|
||||
// In one scans find which the more like moving object such as pedestrian, car, bus.
|
||||
bool FilterNOMovingObjcets(clusterFeature &glu, cluster &gluData)
|
||||
{
|
||||
// small object do not use it!
|
||||
if(glu.size <3)
|
||||
return false;
|
||||
if(glu.size_x > 800 || glu.size_z > 800 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// no filter
|
||||
|
||||
//char filename[256];
|
||||
//string file;
|
||||
//sprintf(filename,"c:\\filename%d.txt", objcount);
|
||||
//file =filename;
|
||||
//DumpPointtoFile(gluData, file);
|
||||
//DumpFeaturetoFile(glu, "c:\\feature");
|
||||
//objcount++;
|
||||
}
|
||||
|
||||
//long objcount =0;
|
||||
// In one scans find which the more like moving object such as pedestrian, car, bus.
|
||||
bool FindMovingObjcets(clusterFeature &glu, cluster &gluData)
|
||||
{
|
||||
// for debug moving object detections.
|
||||
|
||||
if( glu.size_y > 200 && ((glu.size_x>glu.size_y?glu.size_x:glu.size_y))<360)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if((glu.size_y>350 && glu.size_x<140)|| (glu.size_x>350 && glu.size_y<140))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(glu.size_y > 250 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if((glu.size_x>glu.size_y?glu.size_x:glu.size_y)>420 && glu.size_z<130)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if((glu.size_x>glu.size_y?glu.size_x:glu.size_y)>3.5
|
||||
&& ((glu.size_x>glu.size_y?glu.size_x:glu.size_y)/(glu.size_x<glu.size_y?glu.size_x:glu.size_y)>4))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(glu.size_x<700 && glu.size_z<700 && glu.size_y > 100 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(glu.size_x>1500 || glu.size_z>1500 || glu.size_x*glu.size_z >600*600 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (glu.size_x*glu.size_z > 500*500 && glu.size_x/glu.size_z < 1.5)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(glu.size_y < 100)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if((glu.size_x + glu.size_y + glu.size_z)<1.5)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(glu.size_z>700)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(glu.size_x>700)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(( glu.size_x + glu.size_z) <4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if( glu.size_x/glu.size_z> 3.0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// bi classification for distigushed the moving or static
|
||||
void VeloScan::ClassifiAllObject()
|
||||
{
|
||||
int i,j;
|
||||
int clustersize=scanClusterArray.size();
|
||||
|
||||
//Find moving Ojbects
|
||||
for(i=0; i<clustersize; ++i)
|
||||
{
|
||||
clusterFeature &glu = scanClusterFeatureArray[i];
|
||||
cluster &gluData=scanClusterArray[i];
|
||||
|
||||
if( FilterNOMovingObjcets(glu,gluData))
|
||||
{
|
||||
if(FindMovingObjcets(glu,gluData))
|
||||
glu.clusterType =CLUSTER_TYPE_MOVING_OBJECT;
|
||||
else
|
||||
glu.clusterType =CLUSTER_TYPE_STATIC_OBJECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
glu.clusterType =CLUSTER_TYPE_STATIC_OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
//Mark No Moving Ojbects CELLS
|
||||
int k;
|
||||
for(i=0; i<clustersize; ++i)
|
||||
{
|
||||
clusterFeature &glu = scanClusterFeatureArray[i];
|
||||
if(glu.clusterType & CLUSTER_TYPE_MOVING_OBJECT)
|
||||
{
|
||||
cluster &gclu = scanClusterArray[i];
|
||||
for(j =0; j< gclu.size() ; ++j)
|
||||
{
|
||||
cellFeature &gcF = *(gclu[j]);
|
||||
gcF.cellType = CELL_TYPE_MOVING;
|
||||
}
|
||||
}
|
||||
if(glu.clusterType & CLUSTER_TYPE_STATIC_OBJECT)
|
||||
{
|
||||
cluster &gclu = scanClusterArray[i];
|
||||
for(j =0; j< gclu.size() ; ++j)
|
||||
{
|
||||
cellFeature &gcF = *(gclu[j]);
|
||||
gcF.cellType = CELL_TYPE_STATIC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void VeloScan::ClassifibyTrackingAllObject(int currentNO ,int windowsize )
|
||||
{
|
||||
trackMgr.ClassifiyTrackersObjects(Scan::allScans, currentNO, windowsize) ;
|
||||
}
|
||||
|
||||
void VeloScan::MarkStaticorMovingPointCloud()
|
||||
{
|
||||
int i,j,k;
|
||||
DataXYZ xyz(get("xyz"));
|
||||
DataType Pt(get("type"));
|
||||
|
||||
int startofpoint = 0;
|
||||
int colMax= scanCellFeatureArray.size();
|
||||
for(i=0; i<colMax; ++i)
|
||||
{
|
||||
cellFeatureColumn &gFeatureCol = scanCellFeatureArray[i];
|
||||
int rowMax= gFeatureCol.size();
|
||||
for(j=0;j< rowMax; ++j)
|
||||
{
|
||||
cellFeature &gcellFreature = gFeatureCol[j];
|
||||
startofpoint += gcellFreature.pCell->size();
|
||||
cell &gCell =*( gcellFreature.pCell);
|
||||
|
||||
for( k=0; k< gcellFreature.pCell->size();++k)
|
||||
{
|
||||
// find Point in scan raw points by point_id;
|
||||
Point p = *(gCell[k]);
|
||||
if(gcellFreature.cellType & CELL_TYPE_STATIC)
|
||||
Pt[p.point_id] = POINT_TYPE_STATIC_OBJECT;
|
||||
if(gcellFreature.cellType & CELL_TYPE_MOVING)
|
||||
Pt[p.point_id] = POINT_TYPE_MOVING_OBJECT;
|
||||
if(gcellFreature.cellType & CELL_TYPE_GROUND)
|
||||
Pt[p.point_id] = POINT_TYPE_GROUND;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VeloScan::FindingAllofObject(int maxDist, int minDist)
|
||||
{
|
||||
TransferToCellArray(maxDist, minDist);
|
||||
CalcScanCellFeature();
|
||||
FindAndCalcScanClusterFeature();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void VeloScan::TrackingAllofObject(int trackingAlgo)
|
||||
{
|
||||
trackMgr.HandleScan(*this,trackingAlgo);
|
||||
}
|
||||
|
||||
void VeloScan::ClassifiAllofObject()
|
||||
{
|
||||
ClassifiAllObject();
|
||||
}
|
||||
|
||||
void VeloScan::ExchangePointCloud()
|
||||
{
|
||||
MarkStaticorMovingPointCloud();
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* Point Cloud Segmentation using Felzenszwalb-Huttenlocher Algorithm
|
||||
*
|
||||
* Copyright (C) Jacobs University Bremen
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
* @author Mihai-Cotizo Sima
|
||||
*/
|
||||
|
||||
|
||||
#include <segmentation/disjoint-set.h>
|
||||
|
||||
universe::universe(int elements) {
|
||||
elts = new uni_elt[elements];
|
||||
num = elements;
|
||||
for (int i = 0; i < elements; i++) {
|
||||
elts[i].rank = 0;
|
||||
elts[i].size = 1;
|
||||
elts[i].p = i;
|
||||
}
|
||||
}
|
||||
|
||||
universe::~universe() {
|
||||
delete [] elts;
|
||||
}
|
||||
|
||||
int universe::find(int x) {
|
||||
int y = x;
|
||||
while (y != elts[y].p)
|
||||
y = elts[y].p;
|
||||
elts[x].p = y;
|
||||
return y;
|
||||
}
|
||||
|
||||
void universe::join(int x, int y) {
|
||||
if (elts[x].rank > elts[y].rank) {
|
||||
elts[y].p = x;
|
||||
elts[x].size += elts[y].size;
|
||||
} else {
|
||||
elts[x].p = y;
|
||||
elts[y].size += elts[x].size;
|
||||
if (elts[x].rank == elts[y].rank)
|
||||
elts[y].rank++;
|
||||
}
|
||||
num--;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
This file describes the scanserver functionality, the code changes and its behaviour.
|
||||
|
||||
To run with the scanserver functionality, pass -S or --scanserver to the slam6D/show call. Start the scanserver with bin/scanserver & first. If you want to directly jump to usage examples, see the "USAGE" section below.
|
||||
|
||||
The scanserver is a new method to load and manage scans for 'slam6D', 'show' and some few other tools (so far). It removes all the IO code from the clients and handles it in the server process. This separation offers persistence of scan data and avoids unneccessary reloads of full scans or even reduced versions thereof. By using a caching framework it also transparently handles the available memory given and enables (nearly) endless amounts of data. The client is only required to open the interface, load a directory and start working on those scans without having to alter its workflow (e.g., pre-reduce them) to accomodate huge data volumes.
|
||||
|
||||
If you have questions or problems (or both), contact Thomas Escher <tescher@uos.de>.
|
||||
|
||||
|
||||
|
||||
USAGE:
|
||||
|
||||
1. General
|
||||
|
||||
Start the scanserver once (in another terminal, or in the same one as a background process):
|
||||
bin/scanserver &
|
||||
|
||||
Do all the normal work as you would normally do, adding the parameter -S:
|
||||
bin/slam6D dat -S
|
||||
bin/show dat -S
|
||||
|
||||
2. Changing the available memory size
|
||||
|
||||
Changing the cache memory size used by scan data (about half the system memory usually works):
|
||||
|
||||
bin/scanserver -c 3500 (for 8GB RAM)
|
||||
|
||||
If you intend to not reload the full scans for different reduction parameters or don't have too much memory/disk space, disable binary scan caching. Binary scan caching saves the full scans as long as the range or height parameters aren't touched, which would cause a full reload:
|
||||
|
||||
bin/scanserver -b 0
|
||||
|
||||
If your dataset contains many scans and loops (e.g., 'hannover' with 468 scans), the default data memory (150M) won't be enough to hold all the animation frames and you need to increase it:
|
||||
|
||||
bin/scanserver -d 250
|
||||
|
||||
3. Altering the shared memory on your linux system (bus_error)
|
||||
|
||||
If you receive a bus_error, the size of your shared memory is too small and the requested allocation was too big. This is resolved via remounting your shm device. Default is half of the available RAM. This limit can be increased to nearly 90% of the RAM if required.
|
||||
|
||||
sudo mount -o remount,size=7000M /dev/shm (for 8GB RAM)
|
||||
|
||||
4. Locking the memory to avoid swapping (Linux only)
|
||||
|
||||
If a great portion of the RAM is used for the cache data, swapping will usually occur after 50% of usage. To avoid this, the scanserver tries to lock the whole memory in place. This will fail without superuser rights, as well as on a full shared memory (see 3.) even with rights. Add these two additional lines to '/etc/security/limits.conf':
|
||||
|
||||
* soft memlock unlimited
|
||||
* hard memlock unlimited
|
||||
After adding these lines and rebooting the system the scanserver can be started without superuser rights.
|
||||
|
||||
5. Using the octtree serialization feature in show with scanserver
|
||||
|
||||
The octtree serialization behaves slightly different than before. Since the scanserver caches octtrees between calls of 'show', the loading of octtrees only becomes relevant if no octtrees are in the cache and have to be created from the scan itself. If this has been done once before and the octtrees have been saved via --saveOct before this can be used to speed up the octtree loading with --loadOct.
|
||||
|
||||
bin/show dat --loadOct --saveOct
|
||||
|
||||
If octtrees are not cached, they are deserialized if available, created otherwise and then saved for future calls.
|
||||
|
||||
IMPLEMENTATION STATUS:
|
||||
|
||||
Currently only 'slam6D' and 'show' are working with the scanserver.
|
||||
|
||||
Since the scanserver handles the disk IO now and the filtering has been optimized, not all ScanIOs are updated yet. Just copy and paste and change the minor parts about reading the input lines.
|
||||
|
||||
Working: 'ls src/scanio' in a shell
|
|
@ -0,0 +1,71 @@
|
|||
/** @file
|
||||
* @brief Representation of the optimized k-d tree.
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Thomas Escher
|
||||
*/
|
||||
|
||||
#ifndef __KD_MANAGED_H__
|
||||
#define __KD_MANAGED_H__
|
||||
|
||||
#include "slam6d/kdparams.h"
|
||||
#include "slam6d/searchTree.h"
|
||||
#include "slam6d/data_types.h"
|
||||
#include "slam6d/kdTreeImpl.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if !defined _OPENMP && defined OPENMP
|
||||
#define _OPENMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
class Scan;
|
||||
|
||||
struct ArrayAccessor {
|
||||
inline double *operator() (const DataXYZ& pts, unsigned int i) {
|
||||
return pts[i];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The optimized k-d tree.
|
||||
*
|
||||
* A kD tree for points, with limited
|
||||
* capabilities (find nearest point to
|
||||
* a given point, or to a ray).
|
||||
**/
|
||||
class KDtreeManaged :
|
||||
public SearchTree,
|
||||
private KDTreeImpl<const DataXYZ&, unsigned int, ArrayAccessor>
|
||||
|
||||
{
|
||||
public:
|
||||
KDtreeManaged(Scan* scan);
|
||||
virtual ~KDtreeManaged() {}
|
||||
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
//! Aquires cached data first to pass on to the usual KDtree to process
|
||||
virtual double* FindClosest(double *_p, double maxdist2, int threadNum = 0) const;
|
||||
private:
|
||||
Scan* m_scan;
|
||||
DataXYZ* m_data;
|
||||
|
||||
//! Mutex for safely reducing points just once in a multithreaded environment
|
||||
boost::mutex m_mutex_locking;
|
||||
volatile unsigned int m_count_locking;
|
||||
|
||||
// constructor initializer list hacks
|
||||
unsigned int* m_temp_indices;
|
||||
unsigned int* prepareTempIndices(unsigned int n);
|
||||
};
|
||||
|
||||
#endif
|
2048
.svn/pristine/30/30a170f1cfcc358de8779570e93c8768d2668763.svn-base
Normal file
2048
.svn/pristine/30/30a170f1cfcc358de8779570e93c8768d2668763.svn-base
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright (C) 2006 Pedro Felzenszwalb
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef SEGMENT_GRAPH
|
||||
#define SEGMENT_GRAPH
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "disjoint-set.h"
|
||||
|
||||
// threshold function
|
||||
#define THRESHOLD(size, c) (c/size)
|
||||
|
||||
typedef struct {
|
||||
float w;
|
||||
int a, b;
|
||||
} edge;
|
||||
|
||||
bool operator<(const edge &a, const edge &b);
|
||||
|
||||
/*
|
||||
* Segment a graph
|
||||
*
|
||||
* Returns a disjoint-set forest representing the segmentation.
|
||||
*
|
||||
* num_vertices: number of vertices in graph.
|
||||
* num_edges: number of edges in graph
|
||||
* edges: array of edges.
|
||||
* c: constant for treshold function.
|
||||
*/
|
||||
universe *segment_graph(int num_vertices, int num_edges, edge *edges,
|
||||
float c);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
@file
|
||||
@brief Displaying of a matched 3D scene
|
||||
@author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
@author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#ifndef __SHOW_ICC__
|
||||
#define __SHOW_ICC__
|
||||
/**
|
||||
sets the OpenGL point,
|
||||
(z axis is inverted in OpenGL)
|
||||
*/
|
||||
inline void setGLPoint(GLdouble pX, GLdouble pY, GLdouble pZ)
|
||||
{
|
||||
// pZ *= -1.0;
|
||||
glVertex3d(pX, pY, pZ);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
sets the OpenGL point,
|
||||
(z axis is inverted in OpenGL)
|
||||
*/
|
||||
inline void setGLPoint(GLdouble* p)
|
||||
{
|
||||
GLdouble pZ = 1.0 * p[2];
|
||||
|
||||
glVertex3d(p[0], p[1], pZ);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,787 @@
|
|||
/*
|
||||
* scan implementation
|
||||
*
|
||||
* Copyright (C) Andreas Nuechter, Kai Lingemann, Dorit Borrmann, Jan Elseberg, Thomas Escher
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "slam6d/scan.h"
|
||||
|
||||
#include "slam6d/basicScan.h"
|
||||
#include "slam6d/managedScan.h"
|
||||
#include "slam6d/metaScan.h"
|
||||
#include "slam6d/searchTree.h"
|
||||
#include "slam6d/kd.h"
|
||||
#include "slam6d/Boctree.h"
|
||||
#include "slam6d/globals.icc"
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
#include "slam6d/metrics.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _NO_PARALLEL_READ
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define _NO_PARALLEL_READ
|
||||
#endif
|
||||
|
||||
using std::vector;
|
||||
|
||||
|
||||
vector<Scan*> Scan::allScans;
|
||||
bool Scan::scanserver = false;
|
||||
|
||||
|
||||
void Scan::openDirectory(bool scanserver, const std::string& path, IOType type,
|
||||
int start, int end)
|
||||
{
|
||||
Scan::scanserver = scanserver;
|
||||
if(scanserver)
|
||||
ManagedScan::openDirectory(path, type, start, end);
|
||||
else
|
||||
BasicScan::openDirectory(path, type, start, end);
|
||||
}
|
||||
|
||||
void Scan::closeDirectory()
|
||||
{
|
||||
if(scanserver)
|
||||
ManagedScan::closeDirectory();
|
||||
else
|
||||
BasicScan::closeDirectory();
|
||||
}
|
||||
|
||||
Scan::Scan()
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// pose and transformations
|
||||
for(i = 0; i < 3; ++i) rPos[i] = 0;
|
||||
for(i = 0; i < 3; ++i) rPosTheta[i] = 0;
|
||||
for(i = 0; i < 4; ++i) rQuat[i] = 0;
|
||||
M4identity(transMat);
|
||||
M4identity(transMatOrg);
|
||||
M4identity(dalignxf);
|
||||
|
||||
// trees and reduction methods
|
||||
cuda_enabled = false;
|
||||
nns_method = -1;
|
||||
kd = 0;
|
||||
ann_kd_tree = 0;
|
||||
|
||||
// reduction on-demand
|
||||
reduction_voxelSize = 0.0;
|
||||
reduction_nrpts = 0;
|
||||
reduction_pointtype = PointType();
|
||||
|
||||
// flags
|
||||
m_has_reduced = false;
|
||||
|
||||
// octtree
|
||||
octtree_reduction_voxelSize = 0.0;
|
||||
octtree_voxelSize = 0.0;
|
||||
octtree_pointtype = PointType();
|
||||
octtree_loadOct = false;
|
||||
octtree_saveOct = false;
|
||||
}
|
||||
|
||||
Scan::~Scan()
|
||||
{
|
||||
if(kd) delete kd;
|
||||
}
|
||||
|
||||
void Scan::setReductionParameter(double voxelSize, int nrpts, PointType pointtype)
|
||||
{
|
||||
reduction_voxelSize = voxelSize;
|
||||
reduction_nrpts = nrpts;
|
||||
reduction_pointtype = pointtype;
|
||||
}
|
||||
|
||||
void Scan::setSearchTreeParameter(int nns_method, bool cuda_enabled)
|
||||
{
|
||||
searchtree_nnstype = nns_method;
|
||||
searchtree_cuda_enabled = cuda_enabled;
|
||||
}
|
||||
|
||||
void Scan::setOcttreeParameter(double reduction_voxelSize, double voxelSize, PointType pointtype, bool loadOct, bool saveOct)
|
||||
{
|
||||
octtree_reduction_voxelSize = reduction_voxelSize;
|
||||
octtree_voxelSize = voxelSize;
|
||||
octtree_pointtype = pointtype;
|
||||
octtree_loadOct = loadOct;
|
||||
octtree_saveOct = saveOct;
|
||||
}
|
||||
|
||||
void Scan::clear(unsigned int types)
|
||||
{
|
||||
if(types & DATA_XYZ) clear("xyz");
|
||||
if(types & DATA_RGB) clear("rgb");
|
||||
if(types & DATA_REFLECTANCE) clear("reflectance");
|
||||
if(types & DATA_TEMPERATURE) clear("temperature");
|
||||
if(types & DATA_AMPLITUDE) clear("amplitude");
|
||||
if(types & DATA_TYPE) clear("type");
|
||||
if(types & DATA_DEVIATION) clear("deviation");
|
||||
}
|
||||
|
||||
SearchTree* Scan::getSearchTree()
|
||||
{
|
||||
// if the search tree hasn't been created yet, calculate everything
|
||||
if(kd == 0) {
|
||||
createSearchTree();
|
||||
}
|
||||
return kd;
|
||||
}
|
||||
|
||||
void Scan::toGlobal() {
|
||||
calcReducedPoints();
|
||||
transform(transMatOrg, INVALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a search tree depending on the type.
|
||||
*/
|
||||
void Scan::createSearchTree()
|
||||
{
|
||||
// multiple threads will call this function at the same time because they all work on one pair of Scans, just let the first one (who sees a nullpointer) do the creation
|
||||
boost::lock_guard<boost::mutex> lock(m_mutex_create_tree);
|
||||
if(kd != 0) return;
|
||||
|
||||
// make sure the original points are created before starting the measurement
|
||||
DataXYZ xyz_orig(get("xyz reduced original"));
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
Timer tc = ClientMetric::create_tree_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
createSearchTreePrivate();
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::create_tree_time.end(tc);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
void Scan::calcReducedOnDemand()
|
||||
{
|
||||
// multiple threads will call this function at the same time because they all work on one pair of Scans, just let the first one (who sees count as zero) do the reduction
|
||||
boost::lock_guard<boost::mutex> lock(m_mutex_reduction);
|
||||
if(m_has_reduced) return;
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
Timer t = ClientMetric::on_demand_reduction_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
calcReducedOnDemandPrivate();
|
||||
|
||||
m_has_reduced = true;
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::on_demand_reduction_time.end(t);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
void Scan::copyReducedToOriginal()
|
||||
{
|
||||
#ifdef WITH_METRICS
|
||||
Timer t = ClientMetric::copy_original_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
DataXYZ xyz_r(get("xyz reduced"));
|
||||
unsigned int size = xyz_r.size();
|
||||
DataXYZ xyz_r_orig(create("xyz reduced original", sizeof(double)*3*size));
|
||||
for(unsigned int i = 0; i < size; ++i) {
|
||||
for(unsigned int j = 0; j < 3; ++j) {
|
||||
xyz_r_orig[i][j] = xyz_r[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::copy_original_time.end(t);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
void Scan::copyOriginalToReduced()
|
||||
{
|
||||
#ifdef WITH_METRICS
|
||||
Timer t = ClientMetric::copy_original_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
DataXYZ xyz_r_orig(get("xyz reduced original"));
|
||||
unsigned int size = xyz_r_orig.size();
|
||||
DataXYZ xyz_r(create("xyz reduced", sizeof(double)*3*size));
|
||||
for(unsigned int i = 0; i < size; ++i) {
|
||||
for(unsigned int j = 0; j < 3; ++j) {
|
||||
xyz_r[i][j] = xyz_r_orig[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::copy_original_time.end(t);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Computes an octtree of the current scan, then getting the
|
||||
* reduced points as the centers of the octree voxels.
|
||||
*/
|
||||
void Scan::calcReducedPoints()
|
||||
{
|
||||
#ifdef WITH_METRICS
|
||||
Timer t = ClientMetric::scan_load_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
// get xyz to start the scan load, separated here for time measurement
|
||||
DataXYZ xyz(get("xyz"));
|
||||
|
||||
// if the scan hasn't been loaded we can't calculate anything
|
||||
if(xyz.size() == 0)
|
||||
throw runtime_error("Could not calculate reduced points, XYZ data is empty");
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::scan_load_time.end(t);
|
||||
Timer tl = ClientMetric::calc_reduced_points_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
// no reduction needed
|
||||
// copy vector of points to array of points to avoid
|
||||
// further copying
|
||||
if(reduction_voxelSize <= 0.0) {
|
||||
// copy the points
|
||||
DataXYZ xyz_r(create("xyz reduced", sizeof(double)*3*xyz.size()));
|
||||
for(unsigned int i = 0; i < xyz.size(); ++i) {
|
||||
for(unsigned int j = 0; j < 3; ++j) {
|
||||
xyz_r[i][j] = xyz[i][j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// start reduction
|
||||
|
||||
// build octree-tree from CurrentScan
|
||||
// put full data into the octtree
|
||||
BOctTree<double> *oct = new BOctTree<double>(PointerArray<double>(xyz).get(),
|
||||
xyz.size(), reduction_voxelSize, reduction_pointtype);
|
||||
|
||||
vector<double*> center;
|
||||
center.clear();
|
||||
|
||||
if (reduction_nrpts > 0) {
|
||||
if (reduction_nrpts == 1) {
|
||||
oct->GetOctTreeRandom(center);
|
||||
} else {
|
||||
oct->GetOctTreeRandom(center, reduction_nrpts);
|
||||
}
|
||||
} else {
|
||||
oct->GetOctTreeCenter(center);
|
||||
}
|
||||
|
||||
// storing it as reduced scan
|
||||
unsigned int size = center.size();
|
||||
DataXYZ xyz_r(create("xyz reduced", sizeof(double)*3*size));
|
||||
for(unsigned int i = 0; i < size; ++i) {
|
||||
for(unsigned int j = 0; j < 3; ++j) {
|
||||
xyz_r[i][j] = center[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
delete oct;
|
||||
}
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::calc_reduced_points_time.end(tl);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the scan's intrinsic coordinates with the robot position.
|
||||
* @param prevScan The scan that's transformation is extrapolated,
|
||||
* i.e., odometry extrapolation
|
||||
*
|
||||
* For additional information see the following paper (jfr2007.pdf):
|
||||
*
|
||||
* Andreas Nüchter, Kai Lingemann, Joachim Hertzberg, and Hartmut Surmann,
|
||||
* 6D SLAM - 3D Mapping Outdoor Environments Journal of Field Robotics (JFR),
|
||||
* Special Issue on Quantitative Performance Evaluation of Robotic and Intelligent
|
||||
* Systems, Wiley & Son, ISSN 1556-4959, Volume 24, Issue 8-9, pages 699 - 722,
|
||||
* August/September, 2007
|
||||
*
|
||||
*/
|
||||
void Scan::mergeCoordinatesWithRoboterPosition(Scan* prevScan)
|
||||
{
|
||||
double tempMat[16], deltaMat[16];
|
||||
M4inv(prevScan->get_transMatOrg(), tempMat);
|
||||
MMult(prevScan->get_transMat(), tempMat, deltaMat);
|
||||
transform(deltaMat, INVALID); //apply delta transformation of the previous scan
|
||||
}
|
||||
|
||||
/**
|
||||
* The method transforms all points with the given transformation matrix.
|
||||
*/
|
||||
void Scan::transformAll(const double alignxf[16])
|
||||
{
|
||||
DataXYZ xyz(get("xyz"));
|
||||
unsigned int i=0 ;
|
||||
// #pragma omp parallel for
|
||||
for(; i < xyz.size(); ++i) {
|
||||
transform3(alignxf, xyz[i]);
|
||||
}
|
||||
// TODO: test for ManagedScan compability, may need a touch("xyz") to mark saving the new values
|
||||
}
|
||||
|
||||
//! Internal function of transform which alters the reduced points
|
||||
void Scan::transformReduced(const double alignxf[16])
|
||||
{
|
||||
#ifdef WITH_METRICS
|
||||
Timer t = ClientMetric::transform_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
DataXYZ xyz_r(get("xyz reduced"));
|
||||
unsigned int i=0;
|
||||
// #pragma omp parallel for
|
||||
for( ; i < xyz_r.size(); ++i) {
|
||||
transform3(alignxf, xyz_r[i]);
|
||||
}
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::transform_time.end(t);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
//! Internal function of transform which handles the matrices
|
||||
void Scan::transformMatrix(const double alignxf[16])
|
||||
{
|
||||
double tempxf[16];
|
||||
|
||||
// apply alignxf to transMat and update pose vectors
|
||||
MMult(alignxf, transMat, tempxf);
|
||||
memcpy(transMat, tempxf, sizeof(transMat));
|
||||
Matrix4ToEuler(transMat, rPosTheta, rPos);
|
||||
Matrix4ToQuat(transMat, rQuat);
|
||||
|
||||
#ifdef DEBUG
|
||||
cerr << "(" << rPos[0] << ", " << rPos[1] << ", " << rPos[2] << ", "
|
||||
<< rPosTheta[0] << ", " << rPosTheta[1] << ", " << rPosTheta[2] << ")" << endl;
|
||||
|
||||
cerr << transMat << endl;
|
||||
#endif
|
||||
|
||||
// apply alignxf to dalignxf
|
||||
MMult(alignxf, dalignxf, tempxf);
|
||||
memcpy(dalignxf, tempxf, sizeof(transMat));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the scan by a given transformation and writes a new frame. The idea
|
||||
* is to write for every transformation in all files, such that the show program
|
||||
* is able to determine, whcih scans have to be drawn in which color. Hidden scans
|
||||
* (or later processed scans) are written with INVALID.
|
||||
*
|
||||
* @param alignxf Transformation matrix
|
||||
* @param colour Specifies which colour should the written to the frames file
|
||||
* @param islum Is the transformtion part of LUM, i.e., all scans are transformed?
|
||||
* In this case only LUM transformation is stored, otherwise all scans are processed
|
||||
* -1 no transformation is stored
|
||||
* 0 ICP transformation
|
||||
* 1 LUM transformation, all scans except last scan
|
||||
* 2 LUM transformation, last scan only
|
||||
*/
|
||||
void Scan::transform(const double alignxf[16], const AlgoType type, int islum)
|
||||
{
|
||||
MetaScan* meta = dynamic_cast<MetaScan*>(this);
|
||||
|
||||
if(meta) {
|
||||
for(unsigned int i = 0; i < meta->size(); ++i) {
|
||||
meta->getScan(i)->transform(alignxf, type, -1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TRANSFORM_ALL_POINTS
|
||||
transformAll(alignxf);
|
||||
#endif //TRANSFORM_ALL_POINTS
|
||||
|
||||
#ifdef DEBUG
|
||||
cerr << alignxf << endl;
|
||||
cerr << "(" << rPos[0] << ", " << rPos[1] << ", " << rPos[2] << ", "
|
||||
<< rPosTheta[0] << ", " << rPosTheta[1] << ", " << rPosTheta[2] << ") ---> ";
|
||||
#endif
|
||||
|
||||
// transform points
|
||||
transformReduced(alignxf);
|
||||
|
||||
// update matrices
|
||||
transformMatrix(alignxf);
|
||||
|
||||
// store transformation in frames
|
||||
if(type != INVALID) {
|
||||
#ifdef WITH_METRICS
|
||||
Timer t = ClientMetric::add_frames_time.start();
|
||||
#endif //WITH_METRICS
|
||||
bool in_meta;
|
||||
MetaScan* meta = dynamic_cast<MetaScan*>(this);
|
||||
int found = 0;
|
||||
unsigned int scans_size = allScans.size();
|
||||
|
||||
switch (islum) {
|
||||
case -1:
|
||||
// write no tranformation
|
||||
break;
|
||||
case 0:
|
||||
for(unsigned int i = 0; i < scans_size; ++i) {
|
||||
Scan* scan = allScans[i];
|
||||
in_meta = false;
|
||||
if(meta) {
|
||||
for(unsigned int j = 0; j < meta->size(); ++j) {
|
||||
if(meta->getScan(j) == scan) {
|
||||
found = i;
|
||||
in_meta = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(scan == this || in_meta) {
|
||||
found = i;
|
||||
scan->addFrame(type);
|
||||
} else {
|
||||
if(found == 0) {
|
||||
scan->addFrame(ICPINACTIVE);
|
||||
} else {
|
||||
scan->addFrame(INVALID);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
addFrame(type);
|
||||
break;
|
||||
case 2:
|
||||
for(unsigned int i = 0; i < scans_size; ++i) {
|
||||
Scan* scan = allScans[i];
|
||||
if(scan == this) {
|
||||
found = i;
|
||||
addFrame(type);
|
||||
allScans[0]->addFrame(type);
|
||||
continue;
|
||||
}
|
||||
if (found != 0) {
|
||||
scan->addFrame(INVALID);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << "invalid point transformation mode" << endl;
|
||||
}
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::add_frames_time.end(t);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the scan by a given transformation and writes a new frame. The idea
|
||||
* is to write for every transformation in all files, such that the show program
|
||||
* is able to determine, whcih scans have to be drawn in which color. Hidden scans
|
||||
* (or later processed scans) are written with INVALID.
|
||||
*
|
||||
* @param alignQuat Quaternion for the rotation
|
||||
* @param alignt Translation vector
|
||||
* @param colour Specifies which colour should the written to the frames file
|
||||
* @param islum Is the transformtion part of LUM, i.e., all scans are transformed?
|
||||
* In this case only LUM transformation is stored, otherwise all scans are processed
|
||||
* -1 no transformation is stored
|
||||
* 0 ICP transformation
|
||||
* 1 LUM transformation, all scans except last scan
|
||||
* 2 LUM transformation, last scan only
|
||||
*/
|
||||
void Scan::transform(const double alignQuat[4], const double alignt[3],
|
||||
const AlgoType type, int islum)
|
||||
{
|
||||
double alignxf[16];
|
||||
QuatToMatrix4(alignQuat, alignt, alignxf);
|
||||
transform(alignxf, type, islum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the scan, so that the given Matrix
|
||||
* prepresent the next pose.
|
||||
*
|
||||
* @param alignxf Transformation matrix to which this scan will be set to
|
||||
* @param islum Is the transformation part of LUM?
|
||||
*/
|
||||
void Scan::transformToMatrix(double alignxf[16], const AlgoType type, int islum)
|
||||
{
|
||||
double tinv[16];
|
||||
M4inv(transMat, tinv);
|
||||
transform(tinv, INVALID);
|
||||
transform(alignxf, type, islum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the scan, so that the given Euler angles
|
||||
* prepresent the next pose.
|
||||
*
|
||||
* @param rP Translation to which this scan will be set to
|
||||
* @param rPT Orientation as Euler angle to which this scan will be set
|
||||
* @param islum Is the transformation part of LUM?
|
||||
*/
|
||||
void Scan::transformToEuler(double rP[3], double rPT[3], const AlgoType type, int islum)
|
||||
{
|
||||
#ifdef WITH_METRICS
|
||||
// called in openmp context in lum6Deuler.cc:422
|
||||
ClientMetric::transform_time.set_threadsafety(true);
|
||||
ClientMetric::add_frames_time.set_threadsafety(true);
|
||||
#endif //WITH_METRICS
|
||||
|
||||
double tinv[16];
|
||||
double alignxf[16];
|
||||
M4inv(transMat, tinv);
|
||||
transform(tinv, INVALID);
|
||||
EulerToMatrix4(rP, rPT, alignxf);
|
||||
transform(alignxf, type, islum);
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::transform_time.set_threadsafety(false);
|
||||
ClientMetric::add_frames_time.set_threadsafety(false);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the scan, so that the given Euler angles
|
||||
* prepresent the next pose.
|
||||
*
|
||||
* @param rP Translation to which this scan will be set to
|
||||
* @param rPQ Orientation as Quaternion to which this scan will be set
|
||||
* @param islum Is the transformation part of LUM?
|
||||
*/
|
||||
void Scan::transformToQuat(double rP[3], double rPQ[4], const AlgoType type, int islum)
|
||||
{
|
||||
double tinv[16];
|
||||
double alignxf[16];
|
||||
M4inv(transMat, tinv);
|
||||
transform(tinv, INVALID);
|
||||
QuatToMatrix4(rPQ, rP, alignxf);
|
||||
transform(alignxf, type, islum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates Source\Target
|
||||
* Calculates a set of corresponding point pairs and returns them. It
|
||||
* computes the k-d trees and deletes them after the pairs have been
|
||||
* found. This slow function should be used only for testing
|
||||
*
|
||||
* @param pairs The resulting point pairs (vector will be filled)
|
||||
* @param Target The scan to whiche the points are matched
|
||||
* @param thread_num number of the thread (for parallelization)
|
||||
* @param rnd randomized point selection
|
||||
* @param max_dist_match2 maximal allowed distance for matching
|
||||
*/
|
||||
|
||||
void Scan::getNoPairsSimple(vector <double*> &diff,
|
||||
Scan* Source, Scan* Target,
|
||||
int thread_num,
|
||||
double max_dist_match2)
|
||||
{
|
||||
DataXYZ xyz_r(Source->get("xyz reduced"));
|
||||
KDtree* kd = new KDtree(PointerArray<double>(Target->get("xyz reduced")).get(), Target->size<DataXYZ>("xyz reduced"));
|
||||
|
||||
cout << "Max: " << max_dist_match2 << endl;
|
||||
for (unsigned int i = 0; i < xyz_r.size(); i++) {
|
||||
|
||||
double p[3];
|
||||
p[0] = xyz_r[i][0];
|
||||
p[1] = xyz_r[i][1];
|
||||
p[2] = xyz_r[i][2];
|
||||
|
||||
|
||||
double *closest = kd->FindClosest(p, max_dist_match2, thread_num);
|
||||
if (!closest) {
|
||||
diff.push_back(xyz_r[i]);
|
||||
//diff.push_back(closest);
|
||||
}
|
||||
}
|
||||
|
||||
delete kd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a set of corresponding point pairs and returns them. It
|
||||
* computes the k-d trees and deletes them after the pairs have been
|
||||
* found. This slow function should be used only for testing
|
||||
*
|
||||
* @param pairs The resulting point pairs (vector will be filled)
|
||||
* @param Source The scan whose points are matched to Targets' points
|
||||
* @param Target The scan to whiche the points are matched
|
||||
* @param thread_num number of the thread (for parallelization)
|
||||
* @param rnd randomized point selection
|
||||
* @param max_dist_match2 maximal allowed distance for matching
|
||||
*/
|
||||
void Scan::getPtPairsSimple(vector <PtPair> *pairs,
|
||||
Scan* Source, Scan* Target,
|
||||
int thread_num,
|
||||
int rnd, double max_dist_match2,
|
||||
double *centroid_m, double *centroid_d)
|
||||
{
|
||||
KDtree* kd = new KDtree(PointerArray<double>(Source->get("xyz reduced")).get(), Source->size<DataXYZ>("xyz reduced"));
|
||||
DataXYZ xyz_r(Target->get("xyz reduced"));
|
||||
|
||||
for (unsigned int i = 0; i < xyz_r.size(); i++) {
|
||||
if (rnd > 1 && rand(rnd) != 0) continue; // take about 1/rnd-th of the numbers only
|
||||
|
||||
double p[3];
|
||||
p[0] = xyz_r[i][0];
|
||||
p[1] = xyz_r[i][1];
|
||||
p[2] = xyz_r[i][2];
|
||||
|
||||
double *closest = kd->FindClosest(p, max_dist_match2, thread_num);
|
||||
if (closest) {
|
||||
centroid_m[0] += closest[0];
|
||||
centroid_m[1] += closest[1];
|
||||
centroid_m[2] += closest[2];
|
||||
centroid_d[0] += p[0];
|
||||
centroid_d[1] += p[1];
|
||||
centroid_d[2] += p[2];
|
||||
PtPair myPair(closest, p);
|
||||
pairs->push_back(myPair);
|
||||
}
|
||||
}
|
||||
centroid_m[0] /= pairs[thread_num].size();
|
||||
centroid_m[1] /= pairs[thread_num].size();
|
||||
centroid_m[2] /= pairs[thread_num].size();
|
||||
centroid_d[0] /= pairs[thread_num].size();
|
||||
centroid_d[1] /= pairs[thread_num].size();
|
||||
centroid_d[2] /= pairs[thread_num].size();
|
||||
|
||||
delete kd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates a set of corresponding point pairs and returns them.
|
||||
* The function uses the k-d trees stored the the scan class, thus
|
||||
* the function createTrees and deletTrees have to be called before
|
||||
* resp. afterwards.
|
||||
* Here we implement the so called "fast corresponding points"; k-d
|
||||
* trees are not recomputed, instead the apply the inverse transformation
|
||||
* to to the given point set.
|
||||
*
|
||||
* @param pairs The resulting point pairs (vector will be filled)
|
||||
* @param Source The scan whose points are matched to Targets' points
|
||||
* @param Target The scan to whiche the points are matched
|
||||
* @param thread_num number of the thread (for parallelization)
|
||||
* @param rnd randomized point selection
|
||||
* @param max_dist_match2 maximal allowed distance for matching
|
||||
* @return a set of corresponding point pairs
|
||||
*/
|
||||
void Scan::getPtPairs(vector <PtPair> *pairs,
|
||||
Scan* Source, Scan* Target,
|
||||
int thread_num,
|
||||
int rnd, double max_dist_match2, double &sum,
|
||||
double *centroid_m, double *centroid_d)
|
||||
{
|
||||
// initialize centroids
|
||||
for(unsigned int i = 0; i < 3; ++i) {
|
||||
centroid_m[i] = 0;
|
||||
centroid_d[i] = 0;
|
||||
}
|
||||
|
||||
// get point pairs
|
||||
DataXYZ xyz_r(Target->get("xyz reduced"));
|
||||
Source->getSearchTree()->getPtPairs(pairs, Source->dalignxf,
|
||||
xyz_r, 0, xyz_r.size(),
|
||||
thread_num,
|
||||
rnd, max_dist_match2, sum, centroid_m, centroid_d);
|
||||
|
||||
// normalize centroids
|
||||
unsigned int size = pairs->size();
|
||||
if(size != 0) {
|
||||
for(unsigned int i = 0; i < 3; ++i) {
|
||||
centroid_m[i] /= size;
|
||||
centroid_d[i] /= size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates a set of corresponding point pairs and returns them.
|
||||
* The function uses the k-d trees stored the the scan class, thus
|
||||
* the function createTrees and delteTrees have to be called before
|
||||
* resp. afterwards.
|
||||
*
|
||||
* @param pairs The resulting point pairs (vector will be filled)
|
||||
* @param Source The scan whose points are matched to Targets' points
|
||||
* @param Target The scan to whiche the points are matched
|
||||
* @param thread_num The number of the thread that is computing ptPairs in parallel
|
||||
* @param step The number of steps for parallelization
|
||||
* @param rnd randomized point selection
|
||||
* @param max_dist_match2 maximal allowed distance for matching
|
||||
* @param sum The sum of distances of the points
|
||||
*
|
||||
* These intermediate values are for the parallel ICP algorithm
|
||||
* introduced in the paper
|
||||
* "The Parallel Iterative Closest Point Algorithm"
|
||||
* by Langis / Greenspan / Godin, IEEE 3DIM 2001
|
||||
*
|
||||
*/
|
||||
void Scan::getPtPairsParallel(vector <PtPair> *pairs, Scan* Source, Scan* Target,
|
||||
int thread_num, int step,
|
||||
int rnd, double max_dist_match2,
|
||||
double *sum,
|
||||
double centroid_m[OPENMP_NUM_THREADS][3], double centroid_d[OPENMP_NUM_THREADS][3])
|
||||
{
|
||||
// initialize centroids
|
||||
for(unsigned int i = 0; i < 3; ++i) {
|
||||
centroid_m[thread_num][i] = 0;
|
||||
centroid_d[thread_num][i] = 0;
|
||||
}
|
||||
|
||||
// get point pairs
|
||||
SearchTree* search = Source->getSearchTree();
|
||||
// differentiate between a meta scan (which has no reduced points) and a normal scan
|
||||
// if Source is also a meta scan it already has a special meta-kd-tree
|
||||
MetaScan* meta = dynamic_cast<MetaScan*>(Target);
|
||||
if(meta) {
|
||||
for(unsigned int i = 0; i < meta->size(); ++i) {
|
||||
// determine step for each scan individually
|
||||
DataXYZ xyz_r(meta->getScan(i)->get("xyz reduced"));
|
||||
unsigned int max = xyz_r.size();
|
||||
unsigned int step = max / OPENMP_NUM_THREADS;
|
||||
// call ptpairs for each scan and accumulate ptpairs, centroids and sum
|
||||
search->getPtPairs(&pairs[thread_num], Source->dalignxf,
|
||||
xyz_r, step * thread_num, step * thread_num + step,
|
||||
thread_num,
|
||||
rnd, max_dist_match2, sum[thread_num],
|
||||
centroid_m[thread_num], centroid_d[thread_num]);
|
||||
}
|
||||
} else {
|
||||
DataXYZ xyz_r(Target->get("xyz reduced"));
|
||||
search->getPtPairs(&pairs[thread_num], Source->dalignxf,
|
||||
xyz_r, thread_num * step, thread_num * step + step,
|
||||
thread_num,
|
||||
rnd, max_dist_match2, sum[thread_num],
|
||||
centroid_m[thread_num], centroid_d[thread_num]);
|
||||
}
|
||||
|
||||
// normalize centroids
|
||||
unsigned int size = pairs[thread_num].size();
|
||||
if(size != 0) {
|
||||
for(unsigned int i = 0; i < 3; ++i) {
|
||||
centroid_m[thread_num][i] /= size;
|
||||
centroid_d[thread_num][i] /= size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Scan::getMaxCountReduced(ScanVector& scans)
|
||||
{
|
||||
unsigned int max = 0;
|
||||
for(std::vector<Scan*>::iterator it = scans.begin(); it != scans.end(); ++it) {
|
||||
unsigned int count = (*it)->size<DataXYZ>("xyz reduced");
|
||||
if(count > max)
|
||||
max = count;
|
||||
}
|
||||
return max;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
Project admins
|
||||
|
||||
Andreas Nuechter andreas@nuechti.de
|
||||
Kai Lingemann kai.lingemann@gmx.de
|
||||
Dorit Borrmann d.borrmann@jacobs-university.de
|
||||
|
||||
List of contributors
|
||||
|
||||
Andreas Nuechter andreas@nuechti.de
|
||||
Kai Lingemann kai.lingemann@gmx.de
|
||||
Dorit Borrmann d.borrmann@jacobs-university.de
|
||||
Jan Elseberg j.elseberg@jacobs-university.de
|
||||
Jochen Sprickerhof jochen@sprickerhof.de
|
||||
HamidReza Houshiar h.houshiar@jacobs-university.de
|
||||
Sven Albrecht sven.albrecht@uni-osnabrueck.de
|
||||
Stan Serebryakov cfr.ssv@gmail.com
|
||||
Thomas Escher tescher@uni-osnabrueck.de
|
||||
Thomas Wiemann twiemann@uni-osnabrueck.de
|
||||
Alexandru Tandrau alexandru@tandrau.com
|
||||
Alexandru Eugen Ichim eugen@alexichim.com
|
||||
Flavia Grosan me@flaviagrosan.com
|
||||
Deyuan Qiu deyuan.qiu@googlemail.com
|
||||
Darko Makreshanski d.makreshanski@jacobs-university.de
|
||||
Mohammad Faisal Abdullah m.faisal@jacobs-university.de
|
||||
Li Ming liming751218@whu.edu.cn
|
||||
Li Wei xpaulee@gmail.com
|
||||
Shams Feyzabadi sh.feyzabadi@gmail.co
|
||||
Vladislav Perelmann v.perelman@jacobs-university.de
|
||||
Chen Long lchen.whu@gmail.com
|
||||
Remus Dumitru r.dumitru@jaocbs-university.de
|
||||
Billy Okal okal.billy@googlemail.com
|
||||
Razvan-George Mihalyi r.mihalyi@jacobs-university.de
|
||||
Johannes Schauer j.schauer@jacobs-university.de
|
||||
Corneliu-Claudiu Prodescu c.prodescu@jacobs-university.de
|
||||
|
||||
Further contributors
|
||||
|
||||
Uwe Hebbelmann, Sebastian Stock, Andre Schemschat
|
||||
Hartmut Surmann
|
||||
Amuz Tamrakars, Ulugbek Makhmudov
|
||||
Christof Soeger, Marcel Junker, Anton Fluegge, Hannes Schulz
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Point Cloud Segmentation using Felzenszwalb-Huttenlocher Algorithm
|
||||
*
|
||||
* Copyright (C) Jacobs University Bremen
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
* @author Mihai-Cotizo Sima
|
||||
*/
|
||||
|
||||
#include <segmentation/segment-graph.h>
|
||||
|
||||
bool operator<(const edge &a, const edge &b) {
|
||||
return a.w < b.w;
|
||||
}
|
||||
|
||||
universe *segment_graph(int num_vertices, int num_edges, edge *edges,
|
||||
float c) {
|
||||
// sort edges by weight
|
||||
std::sort(edges, edges + num_edges);
|
||||
|
||||
// make a disjoint-set forest
|
||||
universe *u = new universe(num_vertices);
|
||||
|
||||
// init thresholds
|
||||
float *threshold = new float[num_vertices];
|
||||
for (int i = 0; i < num_vertices; i++)
|
||||
threshold[i] = THRESHOLD(1,c);
|
||||
|
||||
// for each edge, in non-decreasing weight order...
|
||||
for (int i = 0; i < num_edges; i++) {
|
||||
edge *pedge = &edges[i];
|
||||
|
||||
// components conected by this edge
|
||||
int a = u->find(pedge->a);
|
||||
int b = u->find(pedge->b);
|
||||
if (a != b) {
|
||||
if ((pedge->w <= threshold[a]) &&
|
||||
(pedge->w <= threshold[b])) {
|
||||
u->join(a, b);
|
||||
a = u->find(a);
|
||||
threshold[a] = pedge->w + THRESHOLD(u->size(a), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free up
|
||||
delete threshold;
|
||||
return u;
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Inline helper functions for show program
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
#ifndef __SHOW1_ICC__
|
||||
#define __SHOW1_ICC__
|
||||
|
||||
#include "slam6d/globals.icc"
|
||||
|
||||
/**
|
||||
* converts a quaterion to a 4x4 matrix
|
||||
* in OpenGL style
|
||||
*/
|
||||
template <class T>
|
||||
inline void QuaternionToMatrix4(const double *quat, T *mat)
|
||||
{
|
||||
double xy = quat[0] * quat[1] * -1.0;
|
||||
double xz = quat[0] * quat[2];
|
||||
double yz = quat[1] * quat[2] * -1.0;
|
||||
double wx = quat[3] * quat[0];
|
||||
double wy = quat[3] * quat[1] * -1.0;
|
||||
double wz = quat[3] * quat[2];
|
||||
double x2 = sqr(quat[0]);
|
||||
double y2 = sqr(quat[1]);
|
||||
double z2 = sqr(quat[2]);
|
||||
|
||||
mat[0] = 1.0 - 2.0 * (y2 + z2);
|
||||
mat[4] = 2.0 * (xy - wz);
|
||||
mat[8] = 2.0 * (xz + wy);
|
||||
|
||||
mat[1] = 2.0 * (xy + wz);
|
||||
mat[5] = 1.0 - 2.0 * (x2 + z2);
|
||||
mat[9] = 2.0 * (yz - wx);
|
||||
|
||||
mat[2] = 2.0 * (xz - wy);
|
||||
mat[6] = 2.0 * (yz + wx);
|
||||
mat[10] = 1.0 - 2.0 * (x2 + y2);
|
||||
|
||||
mat[11] = mat[7] = mat[3] = mat[12] = mat[13] = mat[14] = 0.0;
|
||||
mat[15] = 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts a 4x4 matrix to a quaternion
|
||||
*/
|
||||
template <class T>
|
||||
inline void Matrix4ToQuaternion(const T *mat, double *quat)
|
||||
{
|
||||
double S;
|
||||
double Trace = 1 + mat[0] + mat[5] + mat[10];
|
||||
if ( Trace > COMPARE_EPSILON ) {
|
||||
S = sqrt(Trace) * 2;
|
||||
quat[0] = -1.0 * ( mat[9] - mat[6] ) / S; // q_x
|
||||
quat[1] = -1.0 * ( mat[2] - mat[8] ) / S; // q_y
|
||||
quat[2] = -1.0 * ( mat[4] - mat[1] ) / S; // q_z
|
||||
quat[3] = 0.25 * S; // q_0
|
||||
} else if ( mat[0] > mat[5] && mat[0] > mat[10] ) { // Column 0:
|
||||
S = sqrt( 1.0 + mat[0] - mat[5] - mat[10] ) * 2;
|
||||
quat[0] = -1.0 * 0.25 * S;
|
||||
quat[1] = -1.0 * (mat[4] + mat[1] ) / S;
|
||||
quat[2] = -1.0 * (mat[2] + mat[8] ) / S;
|
||||
quat[3] = (mat[9] - mat[6] ) / S;
|
||||
} else if ( mat[5] > mat[10] ) { // Column 1:
|
||||
S = sqrt( 1.0 + mat[5] - mat[0] - mat[10] ) * 2;
|
||||
quat[0] = -1.0 * (mat[4] + mat[1] ) / S;
|
||||
quat[1] = -1.0 * 0.25 * S;
|
||||
quat[2] = -1.0 * (mat[9] + mat[6] ) / S;
|
||||
quat[3] = (mat[2] - mat[8] ) / S;
|
||||
} else { // Column 2:
|
||||
S = sqrt( 1.0 + mat[10] - mat[0] - mat[5] ) * 2;
|
||||
quat[0] = -1.0 * (mat[2] + mat[8] ) / S;
|
||||
quat[1] = -1.0 * (mat[9] + mat[6] ) / S;
|
||||
quat[2] = -1.0 * 0.25 * S;
|
||||
quat[3] = (mat[4] - mat[1] ) / S;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* normalizes a quaternion to gain a unit quaternion
|
||||
*/
|
||||
template <class T>
|
||||
inline void QuatNormalize(T *q)
|
||||
{
|
||||
T norm = sqrt(sqr(q[0]) + sqr(q[1]) + sqr(q[2]) + sqr(q[3]));
|
||||
q[3] = q[3] / norm;
|
||||
q[2] = q[2] / norm;
|
||||
q[1] = q[1] / norm;
|
||||
q[0] = q[0] / norm;
|
||||
}
|
||||
|
||||
/**
|
||||
* multiplication of quaternions
|
||||
*/
|
||||
template <class T>
|
||||
inline void QuatMult(const T *q, const T *q_new, T *qtemp)
|
||||
{
|
||||
qtemp[3] = q_new[3] * q[3] - q_new[0] * q[0] - q_new[1] * q[1] - q_new[2] * q[2];
|
||||
qtemp[0] = q_new[3] * q[0] + q_new[0] * q[3] + q_new[1] * q[2] - q_new[2] * q[1];
|
||||
qtemp[1] = q_new[3] * q[1] + q_new[1] * q[3] + q_new[2] * q[0] - q_new[0] * q[2];
|
||||
qtemp[2] = q_new[3] * q[2] + q_new[2] * q[3] + q_new[0] * q[1] - q_new[1] * q[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* converts a quaternion to an axis angle
|
||||
*/
|
||||
inline void QuaternionToAxisAngle(const double *quat, double *axis, double &angle)
|
||||
{
|
||||
double quaternion_norm = sqrt( sqr(quat[0]) + sqr(quat[1]) + sqr(quat[2]) + sqr(quat[3]) );
|
||||
double normalized_quat[4];
|
||||
normalized_quat[0] = quat[0] / quaternion_norm;
|
||||
normalized_quat[1] = quat[1] / quaternion_norm;
|
||||
normalized_quat[2] = quat[2] / quaternion_norm;
|
||||
normalized_quat[3] = quat[3] / quaternion_norm;
|
||||
double cos_a = normalized_quat[3];
|
||||
angle = deg(acos( cos_a )) * 2.0;
|
||||
double sin_a = sqrt( 1.0 - cos_a * cos_a );
|
||||
if ( fabs( sin_a ) < DIV_EPSILON ) sin_a = 1;
|
||||
axis[0] = normalized_quat[0] / sin_a;
|
||||
axis[1] = normalized_quat[1] / sin_a;
|
||||
axis[2] = -1.0 * normalized_quat[2] / sin_a;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef __RANSAC_H__
|
||||
#define __RANSAC_H__
|
||||
|
||||
#include "shape.h"
|
||||
#include "slam6d/scan.h"
|
||||
#include "shapes/ransac_Boctree.h"
|
||||
|
||||
// TODO implement some parameters to modify ransac (maybe in CollisionShape?)
|
||||
template <class T>
|
||||
void Ransac(CollisionShape<T> &shape, Scan *scan, vector<T*> *best_points = 0) {
|
||||
int best_score = 0;
|
||||
CollisionShape<T> *best = shape.copy();
|
||||
|
||||
// stores 3 sample points
|
||||
vector<T *> ps;
|
||||
// create octree from the points
|
||||
DataXYZ xyz(scan->get("xyz reduced"));
|
||||
RansacOctTree<T> *oct = new RansacOctTree<T>(PointerArray<double>(xyz).get(), xyz.size(), 50.0 );
|
||||
cout << "start 5000 iterations" << endl;
|
||||
for(int i = 0; i < 5000; i++) {
|
||||
ps.clear();
|
||||
// randomly select points from the octree
|
||||
oct->DrawPoints(ps, shape.getNrPoints());
|
||||
// compute shape parameters from points
|
||||
if ( shape.hypothesize(ps) ) {
|
||||
// count number of points on the shape
|
||||
int r = oct->PointsOnShape(shape);
|
||||
if (r > best_score) {
|
||||
if (best) delete best;
|
||||
// remember this best fitted shape
|
||||
best_score = r;
|
||||
best = shape.copy();
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << "5000 iterations done" << endl;
|
||||
if (best_points) {
|
||||
best_points->clear();
|
||||
oct->PointsOnShape(*best, *best_points);
|
||||
cout << "Nr points before refinement " << best_points->size() << endl;
|
||||
best->refine(best_points);
|
||||
best_points->clear();
|
||||
oct->PointsOnShape(*best, *best_points);
|
||||
cout << "Nr points after refinement " << best_points->size() << endl;
|
||||
}
|
||||
shape = *best;
|
||||
delete best;
|
||||
|
||||
delete oct;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright (C) 2006 Pedro Felzenszwalb
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef DISJOINT_SET
|
||||
#define DISJOINT_SET
|
||||
|
||||
// disjoint-set forests using union-by-rank and path compression (sort of).
|
||||
|
||||
typedef struct {
|
||||
int rank;
|
||||
int p;
|
||||
int size;
|
||||
} uni_elt;
|
||||
|
||||
class universe {
|
||||
public:
|
||||
universe(int elements);
|
||||
~universe();
|
||||
int find(int x);
|
||||
void join(int x, int y);
|
||||
int size(int x) const {
|
||||
return elts[x].size;
|
||||
}
|
||||
int num_sets() const {
|
||||
return num;
|
||||
}
|
||||
|
||||
private:
|
||||
uni_elt *elts;
|
||||
int num;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,249 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Efficient representation of an octree for ransac
|
||||
* @author Jan Elsberg. Automation Group, Jacobs University Bremen gGmbH, Germany.
|
||||
*/
|
||||
|
||||
#ifndef RANSAC_OCTREE_H
|
||||
#define RANSAC_OCTREE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector>
|
||||
using std::vector;
|
||||
#include <deque>
|
||||
using std::deque;
|
||||
#include <set>
|
||||
using std::set;
|
||||
#include <list>
|
||||
using std::list;
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "shapes/geom_math.h"
|
||||
|
||||
#include "slam6d/globals.icc"
|
||||
#include "slam6d/Boctree.h"
|
||||
#include "shape.h"
|
||||
|
||||
/**
|
||||
* @brief Octree
|
||||
*
|
||||
* A cubic bounding box is calculated
|
||||
* from the given 3D points. Then it
|
||||
* is recusivly subdivided into smaller
|
||||
* subboxes
|
||||
*/
|
||||
template <class T>
|
||||
class RansacOctTree : public BOctTree<T> {
|
||||
|
||||
public:
|
||||
|
||||
template <class P>
|
||||
RansacOctTree(P* const* pts, int n, T _voxelSize, PointType _pointtype = PointType() ) : BOctTree<T>(pts, n, _voxelSize, _pointtype) {}
|
||||
|
||||
// RansacOctTree(vector<const T *> &pts, T voxelSize, PointType _pointtype = PointType() ) : BOctTree<T>(pts, voxelSize, _pointtype) {}
|
||||
|
||||
RansacOctTree(std::string filename) : BOctTree<T> (filename) {}
|
||||
|
||||
void DrawPoints(vector<T *> &p, unsigned char nrp) {
|
||||
DrawPoints(p, *BOctTree<T>::root, nrp);
|
||||
}
|
||||
|
||||
|
||||
unsigned long PointsOnShape(CollisionShape<T> &shape) {
|
||||
return PointsOnShape(*BOctTree<T>::root, BOctTree<T>::center, BOctTree<T>::size, shape);
|
||||
}
|
||||
|
||||
void PointsOnShape(CollisionShape<T> &shape, vector<T *> &points) {
|
||||
PointsOnShape(*BOctTree<T>::root, BOctTree<T>::center, BOctTree<T>::size, shape, points);
|
||||
// exit(0);
|
||||
}
|
||||
|
||||
protected:
|
||||
void showbits(char a)
|
||||
{
|
||||
int i , k , mask;
|
||||
|
||||
for( i =7 ; i >= 0 ; i--)
|
||||
{
|
||||
mask = 1 << i;
|
||||
k = a & mask;
|
||||
if( k == 0)
|
||||
cout<<"0 ";
|
||||
else
|
||||
cout<<"1 ";
|
||||
}
|
||||
}
|
||||
|
||||
long PointsOnShape(bitoct &node, T *center, T size, CollisionShape<T> &shape ) {
|
||||
if (! shape.isInCube(center[0], center[1], center[2], size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
/*
|
||||
printf("parent %p children: %p \n", &node, children);
|
||||
cout << " ";
|
||||
showbits(node.valid);
|
||||
cout << endl;
|
||||
cout << " ";
|
||||
showbits(node.leaf);
|
||||
cout << endl;
|
||||
*/
|
||||
long result = 0;
|
||||
|
||||
// int r = 0;
|
||||
|
||||
for (unsigned char i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
// printf("i: %u r: %d parent %p child[r]: %p \n", i, r, &node, children);
|
||||
// r++;
|
||||
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf contains shape
|
||||
if ( shape.isInCube(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if ( shape.containsPoint(point) )
|
||||
result++;
|
||||
point+= BOctTree<T>::POINTDIM;
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
result += PointsOnShape( children->node, ccenter, size/2.0, shape);
|
||||
}
|
||||
++children; // next child
|
||||
//r++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PointsOnShape(bitoct &node, T *center, T size, CollisionShape<T> &shape, vector<T*> &vpoints) {
|
||||
if (! shape.isInCube(center[0], center[1], center[2], size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (unsigned char i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf contains shape
|
||||
if ( shape.isInCube(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
// cerr << point[0] << " " << point[1] << " " << point[2] << endl;
|
||||
if ( shape.containsPoint(point) ) {
|
||||
T * p = new T[BOctTree<T>::POINTDIM];
|
||||
for (unsigned int iterator = 0; iterator < BOctTree<T>::POINTDIM; iterator++) {
|
||||
p[iterator] = point[iterator];
|
||||
}
|
||||
vpoints.push_back(p);
|
||||
}
|
||||
point+= BOctTree<T>::POINTDIM;
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
PointsOnShape( children->node, ccenter, size/2.0, shape, vpoints);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DrawPoints(vector<T *> &p, bitoct &node, unsigned char nrp) {
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
unsigned char n_children = POPCOUNT(node.valid);
|
||||
unsigned char r = randUC(n_children);
|
||||
if (r == n_children) r--;
|
||||
|
||||
/* cout << (unsigned int)r << " nc " << (unsigned int)n_children << endl;
|
||||
showbits(node.valid);
|
||||
cout << endl;
|
||||
showbits(node.leaf);
|
||||
cout << endl;
|
||||
*/
|
||||
bool leaf = false;
|
||||
unsigned char child_index = 0;
|
||||
/* if (r == 2) {
|
||||
for (unsigned char i = 0; i < 8; i++) {
|
||||
cout << "i " << (unsigned int)i << endl;
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
cout << "valid " << endl;
|
||||
if (child_index == r) {
|
||||
cout << "ci == r" << endl;
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node exists
|
||||
cout << "leaf" << endl;
|
||||
leaf = true;
|
||||
}
|
||||
cout << "no leaf" << endl;
|
||||
break;
|
||||
}
|
||||
child_index++;
|
||||
}
|
||||
}
|
||||
} else {*/
|
||||
for (unsigned char i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if (child_index == r) {
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node exists
|
||||
leaf = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
child_index++;
|
||||
}
|
||||
}
|
||||
// }
|
||||
// cout << (unsigned int)r << " nc " << (unsigned int)n_children << " " << (unsigned int)child_index << endl;
|
||||
if (child_index != r) return; // bitmask valid might be all zero
|
||||
|
||||
if (leaf) {
|
||||
/* cout << "STOPPED" << endl;
|
||||
return;*/
|
||||
|
||||
pointrep *points = children[r].getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
if (length < nrp) return;
|
||||
if (length == nrp) {
|
||||
for (char c = 0; c < nrp; c++) {
|
||||
p.push_back(&(points[BOctTree<T>::POINTDIM*c+1].v));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// randomly get nrp points, we will not check if this succeeds in getting nrp distinct points
|
||||
for (char c = 0; c < nrp; c++) {
|
||||
int tmp = rand(points[0].length);
|
||||
p.push_back(&(points[BOctTree<T>::POINTDIM*tmp+1].v));
|
||||
}
|
||||
} else {
|
||||
/* printf("r: %d parent %p children %p child[r]: %p \n", r, &node, children, &(children[r].node));
|
||||
showbits(node.valid);
|
||||
cout << endl;
|
||||
showbits(node.leaf);
|
||||
cout << endl;
|
||||
cout << "RECURSED" << endl;*/
|
||||
DrawPoints(p, children[r].node, nrp);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* kdManaged implementation
|
||||
*
|
||||
* Copyright (C) Andreas Nuechter, Kai Lingemann, Thomas Escher
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief An optimized k-d tree implementation
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Thomas Escher. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include "slam6d/kdManaged.h"
|
||||
#include "slam6d/scan.h"
|
||||
#include "slam6d/globals.icc"
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
#include <algorithm>
|
||||
using std::swap;
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
// KDtree class static variables
|
||||
template<class PointData, class AccessorData, class AccessorFunc>
|
||||
KDParams KDTreeImpl<PointData, AccessorData, AccessorFunc>::params[MAX_OPENMP_NUM_THREADS];
|
||||
|
||||
KDtreeManaged::KDtreeManaged(Scan* scan) :
|
||||
m_scan(scan), m_data(0), m_count_locking(0)
|
||||
{
|
||||
create(scan->get("xyz reduced original"), prepareTempIndices(scan->size<DataXYZ>("xyz reduced original")), scan->size<DataXYZ>("xyz reduced original"));
|
||||
// allocate in prepareTempIndices, deleted here
|
||||
delete[] m_temp_indices;
|
||||
}
|
||||
|
||||
unsigned int* KDtreeManaged::prepareTempIndices(unsigned int n)
|
||||
{
|
||||
m_temp_indices = new unsigned int[n];
|
||||
for(unsigned int i = 0; i < n; ++i)
|
||||
m_temp_indices[i] = i;
|
||||
return m_temp_indices;
|
||||
}
|
||||
|
||||
double* KDtreeManaged::FindClosest(double *_p, double maxdist2, int threadNum) const
|
||||
{
|
||||
params[threadNum].closest = 0;
|
||||
params[threadNum].closest_d2 = maxdist2;
|
||||
params[threadNum].p = _p;
|
||||
_FindClosest(*m_data, threadNum);
|
||||
return params[threadNum].closest;
|
||||
}
|
||||
|
||||
void KDtreeManaged::lock()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(m_mutex_locking);
|
||||
++m_count_locking;
|
||||
if(m_data == 0) {
|
||||
// aquire an array lock from the scan and hold it while the tree is in use
|
||||
m_data = new DataXYZ(m_scan->get("xyz reduced original"));
|
||||
}
|
||||
}
|
||||
|
||||
void KDtreeManaged::unlock()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(m_mutex_locking);
|
||||
--m_count_locking;
|
||||
if(m_count_locking == 0 && m_data != 0) {
|
||||
delete m_data;
|
||||
m_data = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,415 @@
|
|||
#ifndef SCAN_H
|
||||
#define SCAN_H
|
||||
|
||||
#include "io_types.h"
|
||||
#include "data_types.h"
|
||||
#include "point_type.h"
|
||||
#include "ptpair.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
//! SearchTree types
|
||||
enum nns_type {
|
||||
simpleKD, ANNTree, BOCTree
|
||||
};
|
||||
|
||||
class Scan;
|
||||
typedef std::vector<Scan*> ScanVector;
|
||||
|
||||
class SearchTree;
|
||||
class ANNkd_tree;
|
||||
|
||||
/** HOWTO scan
|
||||
First: Load scans (if you want to use the scanmanager, use ManagedScan)
|
||||
|
||||
BasicScan/ManagedScan::openDirectory(path, type, start, end);
|
||||
|
||||
Pass it to functions (by reference to link it to the same instance) or store it in a global variable
|
||||
|
||||
After loading you might want to set parameters
|
||||
|
||||
for(ScanVector::iterator it = Scan::allScans.begin(); it != Scan::allScans.end(); ++it) {
|
||||
Scan* scan = *it;
|
||||
scan->setRangeFilter(maxDist, minDist);
|
||||
scan->setHeightFilter(top, bottom); // thermo
|
||||
scan->setReductionParameter(voxelSize, nrpts[, pointtype]);
|
||||
scan->setSearchTreeParameter(nns_method, use_cuda);
|
||||
}
|
||||
|
||||
Access the contained data, will be loaded and calculated on demand
|
||||
|
||||
DataXYZ xyz = scan->get("xyz");
|
||||
DataXYZ reduced = scan->get("xyz reduced");
|
||||
DataRGB rgb = scan->get("rgb");
|
||||
|
||||
xyz[i][0..2]
|
||||
reflectance[i]
|
||||
|
||||
unsigned int size = scan->size("xyz reduced");
|
||||
|
||||
In order to use the prefetching of all requested data field in the scanserver, mark them for use. This is relevant for efficiency, which would otherwise cause loading the files each time another data field is requested.
|
||||
|
||||
scan->get(DATA_XYZ | DATA_RGB | ...);
|
||||
|
||||
Under circumstances the data fields are not available (e.g. no color in uos-type scans)
|
||||
|
||||
DataRGB rgb = scan->get("rgb");
|
||||
if(rgb.valid()) { ok, do something }
|
||||
|
||||
If backward-compability to pointer arrays is needed, the PointerArray class can adapt
|
||||
|
||||
BOctTree(PointerArray(scan->get("xyz")).get(), scan->size("xyz"), ...);
|
||||
|
||||
If data isn't needed anymore, flag it for removal
|
||||
|
||||
scan->clear("xyz");
|
||||
scan->clear(DATA_XYZ | DATA_RGB | ...);
|
||||
|
||||
Creating data fields with the correct byte size
|
||||
|
||||
scan->create("xyz somethingelse", sizeof(double)*3*N);
|
||||
|
||||
Reading frames in show:
|
||||
|
||||
unsigned int size = scan->readFrames();
|
||||
|
||||
const double* pose;
|
||||
AlgoType type;
|
||||
scan->getFrame(i, pose, type);
|
||||
|
||||
Last, if program ends, clean up
|
||||
|
||||
Scan::closeDirectory(scans);
|
||||
|
||||
**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This class bundles common features of different scan implementations by
|
||||
* abstraction. It handles the algorithmic parts and leaves IO and other
|
||||
* features to the deriving classes.
|
||||
*/
|
||||
class Scan {
|
||||
//friend class SearchTree; // TODO: is this neccessary?
|
||||
public:
|
||||
enum AlgoType {
|
||||
INVALID, ICP, ICPINACTIVE, LUM, ELCH, LOOPTORO, LOOPHOGMAN, GRAPHTORO,
|
||||
GRAPHHOGMAN
|
||||
};
|
||||
|
||||
// delete copy-ctor and assignment, scans shouldn't be copied by basic class
|
||||
Scan(const Scan& other) = delete;
|
||||
Scan& operator=(const Scan& other) = delete;
|
||||
|
||||
virtual ~Scan();
|
||||
|
||||
//! Holder of all scans - also used in transform for adding frames for each scan at the same time
|
||||
static std::vector<Scan*> allScans;
|
||||
|
||||
/**
|
||||
* Attempt to read a directory under \a path and return its read scans.
|
||||
* No scans are loaded at this point, only checked if all exist.
|
||||
*
|
||||
* @param scanserver whether to use managed scans in the scanserver or not
|
||||
* @param path to the directory containing the scans
|
||||
* @param type determining which ScanIO to use
|
||||
* @param start first scan to use
|
||||
* @param end last scan to use, -1 means from start to last available
|
||||
*/
|
||||
static void openDirectory(bool scanserver, const std::string& path, IOType type,
|
||||
int start, int end = -1);
|
||||
|
||||
/**
|
||||
* "Close" a directory by deleting all its scans and emptying the
|
||||
* Scan::allScans vector.
|
||||
*/
|
||||
static void closeDirectory();
|
||||
|
||||
|
||||
/* Input filtering and parameter functions */
|
||||
|
||||
|
||||
//! Input filtering for all points based on their euclidean length
|
||||
virtual void setRangeFilter(double max, double min) = 0;
|
||||
|
||||
//! Input filtering for all points based on their height
|
||||
virtual void setHeightFilter(double top, double bottom) = 0;
|
||||
|
||||
//! Input mutation to set range of all points to a constant value;
|
||||
virtual void setRangeMutation(double range) { }
|
||||
|
||||
//! Set reduction parameters, but don't reduce yet
|
||||
virtual void setReductionParameter(double voxelSize, int nrpts = 0,
|
||||
PointType pointtype = PointType());
|
||||
|
||||
//! Set SearchTree type, but don't create it yet
|
||||
void setSearchTreeParameter(int nns_method, bool cuda_enabled);
|
||||
|
||||
/**
|
||||
* Set octtree parameters for show
|
||||
* @param loadOct will load the serialized octtree from disk regardless
|
||||
* @param saveOct serialize octtree if not loaded by loadOct after creation
|
||||
*/
|
||||
virtual void setOcttreeParameter(double reduction_voxelSize,
|
||||
double octtree_voxelSize, PointType pointtype,
|
||||
bool loadOct, bool saveOct);
|
||||
|
||||
|
||||
/* Basic getter functions */
|
||||
|
||||
|
||||
inline const double* get_rPos() const;
|
||||
inline const double* get_rPosTheta() const;
|
||||
inline const double* get_rPosQuat() const;
|
||||
//! Pose matrix after initial and match transformations (org+dalign)
|
||||
inline const double* get_transMat() const;
|
||||
//! Original pose matrix after initial transform
|
||||
inline const double* get_transMatOrg() const;
|
||||
//! Accumulated delta transformation matrix
|
||||
inline const double* getDAlign() const;
|
||||
|
||||
inline SearchTree* getSearchTree();
|
||||
inline ANNkd_tree* getANNTree() const;
|
||||
|
||||
virtual const char* getIdentifier() const = 0;
|
||||
|
||||
//! Determine the maximum number of reduced points in \a scans
|
||||
static unsigned int getMaxCountReduced(ScanVector& scans);
|
||||
|
||||
|
||||
/* Functions for altering data fields, implementation specific */
|
||||
|
||||
|
||||
/**
|
||||
* Get the data field \a identifier, calculate it on demand if neccessary.
|
||||
*
|
||||
* If "xyz reduced" or "xyz reduced original" is requested, the reduction is
|
||||
* started with "xyz" as input.
|
||||
*/
|
||||
virtual DataPointer get(const std::string& identifier) = 0;
|
||||
|
||||
/**
|
||||
* Load the requested IODataTypes, joined by |, from the scan file.
|
||||
*
|
||||
* This feature is neccessary to load multiple data fields at once, not all
|
||||
* one by one with each get("...") access.
|
||||
*/
|
||||
virtual void get(unsigned int types) = 0;
|
||||
|
||||
/**
|
||||
* Creates a data field \a identifier with \a size bytes.
|
||||
*/
|
||||
virtual DataPointer create(const std::string& identifier, unsigned int size) = 0;
|
||||
|
||||
/**
|
||||
* Clear the data field \a identifier, removing its allocated memory if
|
||||
* possible or marking it for prioritized removal.
|
||||
*/
|
||||
virtual void clear(const std::string& identifier) = 0;
|
||||
|
||||
//! Extension to clear for more than one identifier, e.g. clear(DATA_XYZ | DATA_RGB);
|
||||
void clear(unsigned int types);
|
||||
|
||||
/**
|
||||
* Get the size of \a identifier as if it were requested and size() called
|
||||
* upon its type specialized DataPointer class.
|
||||
* e.g size<DataXYZ>("xyz reduced")
|
||||
*/
|
||||
template<typename T>
|
||||
unsigned int size(const std::string& identifier) {
|
||||
return (T(get(identifier))).size();
|
||||
}
|
||||
|
||||
|
||||
/* Frame handling functions */
|
||||
|
||||
|
||||
/**
|
||||
* Open the .frames-file and read its contents. If not read, the frame list
|
||||
* will be empty.
|
||||
* @return count of frames if file has been read, zero otherwise
|
||||
*/
|
||||
virtual unsigned int readFrames() = 0;
|
||||
|
||||
/**
|
||||
* Write the accumulated frames into a .frames-file.
|
||||
*/
|
||||
virtual void saveFrames() = 0;
|
||||
|
||||
//! Count of frames
|
||||
virtual unsigned int getFrameCount() = 0;
|
||||
|
||||
//! Get contents of a frame, pass matrix pointer and type by reference
|
||||
virtual void getFrame(unsigned int i, const double*& pose_matrix, AlgoType& type) = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Called from transform, this will add its current transMat pose with
|
||||
* the given type as a frame into the list of frames
|
||||
*/
|
||||
virtual void addFrame(AlgoType type) = 0;
|
||||
|
||||
public:
|
||||
|
||||
/* Direct creation of reduced points and search tree */
|
||||
|
||||
//! Apply reduction and initial transMatOrg transformation
|
||||
void toGlobal();
|
||||
|
||||
//! Copy reduced points to original and create search tree on it
|
||||
void createSearchTree();
|
||||
|
||||
|
||||
/* Common transformation and matching functions */
|
||||
void mergeCoordinatesWithRoboterPosition(Scan* prevScan);
|
||||
void transformAll(const double alignxf[16]);
|
||||
void transformAll(const double alignQuat[4], const double alignt[3]);
|
||||
|
||||
void transform(const double alignxf[16],
|
||||
const AlgoType type, int islum = 0);
|
||||
void transform(const double alignQuat[4],
|
||||
const double alignt[3], const AlgoType type, int islum = 0);
|
||||
void transformToMatrix(double alignxf[16],
|
||||
const AlgoType type, int islum = 0);
|
||||
void transformToEuler(double rP[3], double rPT[3],
|
||||
const AlgoType type, int islum = 0);
|
||||
void transformToQuat(double rP[3], double rPQ[4],
|
||||
const AlgoType type, int islum = 0);
|
||||
|
||||
// Scan matching functions
|
||||
static void getPtPairs(std::vector<PtPair> *pairs,
|
||||
Scan* Source, Scan* Target,
|
||||
int thread_num,
|
||||
int rnd, double max_dist_match2, double &sum,
|
||||
double *centroid_m, double *centroid_d);
|
||||
static void getNoPairsSimple(std::vector<double*> &diff,
|
||||
Scan* Source, Scan* Target,
|
||||
int thread_num,
|
||||
double max_dist_match2);
|
||||
static void getPtPairsSimple(std::vector<PtPair> *pairs,
|
||||
Scan* Source, Scan* Target,
|
||||
int thread_num,
|
||||
int rnd, double max_dist_match2,
|
||||
double *centroid_m, double *centroid_d);
|
||||
static void getPtPairsParallel(std::vector<PtPair> *pairs,
|
||||
Scan* Source, Scan* Target,
|
||||
int thread_num, int step,
|
||||
int rnd, double max_dist_match2,
|
||||
double *sum,
|
||||
double centroid_m[OPENMP_NUM_THREADS][3],
|
||||
double centroid_d[OPENMP_NUM_THREADS][3]);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The pose of the scan
|
||||
* Note: rPos/rPosTheta and transMat _should_
|
||||
* always represent the same pose!!!
|
||||
*/
|
||||
double rPos[3], //!< 3D position
|
||||
rPosTheta[3], //!< 3D rotation in Euler representation
|
||||
rQuat[4], //!< 3D rotation in Quaternion representation
|
||||
transMat[16], //!< (4x4) transformation matrix
|
||||
transMatOrg[16]; //!< The original pose of the scan, e.g., from odometry
|
||||
|
||||
/**
|
||||
* The dalignxf transformation represents the delta transformation virtually applied
|
||||
* to the tree and is used to compute are actual corresponding points.
|
||||
*/
|
||||
double dalignxf[16];
|
||||
|
||||
//! Run ICP on GPU instead of CPU
|
||||
bool cuda_enabled;
|
||||
|
||||
//! Defines the method used for nearest neighbor search and which tree to use
|
||||
int nns_method;
|
||||
|
||||
//! SearchTree for point pair matching, works on the search points
|
||||
SearchTree* kd;
|
||||
|
||||
//! This KD tree is created only for the CUDA usages
|
||||
ANNkd_tree* ann_kd_tree;
|
||||
|
||||
//! Voxelsize of the octtree used for reduction
|
||||
double reduction_voxelSize;
|
||||
|
||||
//! Which point to take out of the reduction octtree, 0 for center
|
||||
int reduction_nrpts;
|
||||
|
||||
//! Pointtype used for the reduction octtree
|
||||
PointType reduction_pointtype;
|
||||
|
||||
//! Type of the searchtree to be created
|
||||
int searchtree_nnstype;
|
||||
|
||||
//! Use CUDA for searching
|
||||
bool searchtree_cuda_enabled;
|
||||
|
||||
//! Flag whether "xyz reduced" has been initialized for this Scan yet
|
||||
bool m_has_reduced;
|
||||
|
||||
//! Reduction value used for octtree input
|
||||
double octtree_reduction_voxelSize;
|
||||
|
||||
//! Voxelsize used in the octtree itself
|
||||
double octtree_voxelSize;
|
||||
|
||||
//! Pointtype for the Octtree
|
||||
PointType octtree_pointtype;
|
||||
|
||||
//! Flags to load or save the octtrees from/to storage
|
||||
bool octtree_loadOct, octtree_saveOct;
|
||||
|
||||
/**
|
||||
* Basic initializing constructor calling the initalization function.
|
||||
* Can only be called from deriving classes.
|
||||
*/
|
||||
Scan();
|
||||
|
||||
/**
|
||||
* This function handles the reduction of points. It builds a lock for
|
||||
* multithread-safety and calls caldReducedOnDemandPrivate.
|
||||
*
|
||||
* The intention is to reduce points, transforme them to the initial pose and
|
||||
* then copy them to original for the SearchTree.
|
||||
*/
|
||||
void calcReducedOnDemand();
|
||||
|
||||
//! Create specific SearchTree variants matching the capability of the Scan
|
||||
virtual void createSearchTreePrivate() = 0;
|
||||
|
||||
//! Create reduced points in a multithread-safe environment matching the capability of the Scan
|
||||
virtual void calcReducedOnDemandPrivate() = 0;
|
||||
|
||||
//! Internal function of transform which alters the reduced points
|
||||
void transformReduced(const double alignxf[16]);
|
||||
|
||||
//! Internal function of transform which handles the matrices
|
||||
void transformMatrix(const double alignxf[16]);
|
||||
|
||||
//! Creating reduced points
|
||||
void calcReducedPoints();
|
||||
|
||||
//! Copies reduced points to original points without any transformation.
|
||||
void copyReducedToOriginal();
|
||||
|
||||
//! Inverse functionality of copyReducedToOriginal.
|
||||
void copyOriginalToReduced();
|
||||
|
||||
private:
|
||||
//! flag for openDirectory and closeDirectory to distinguish the scans
|
||||
static bool scanserver;
|
||||
|
||||
public:
|
||||
//! Mutex for safely reducing points and creating the search tree just once in a multithreaded environment
|
||||
// it can not be compiled in win32 use boost 1.48, therefore we remeove it temporarily
|
||||
boost::mutex m_mutex_reduction, m_mutex_create_tree;
|
||||
};
|
||||
|
||||
#include "scan.icc"
|
||||
|
||||
#endif //SCAN_H
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* icp6D implementation
|
||||
*
|
||||
* Copyright (C) Andreas Nuechter, Kai Lingemann
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of 3D scan matching with ICP
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#include "slam6d/icp6D.h"
|
||||
|
||||
#include "slam6d/metaScan.h"
|
||||
#include "slam6d/globals.icc"
|
||||
|
||||
#include <iomanip>
|
||||
using std::cerr;
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if !defined _OPENMP && defined OPENMP
|
||||
#define _OPENMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param my_icp6Dminimizer Pointer to the ICP-minimizer
|
||||
* @param max_dist_match Maximum distance to which point pairs are collected
|
||||
* @param max_num_iterations Maximum number of iterations
|
||||
* @param quiet Whether to print to the standard output
|
||||
* @param meta Match against a meta scan?
|
||||
* @param rnd Randomized point selection
|
||||
* @param eP Extrapolate odometry?
|
||||
* @param anim Animate which frames?
|
||||
* @param epsilonICP Termination criterion
|
||||
* @param nns_method Selects NNS method to be used
|
||||
*/
|
||||
icp6D::icp6D(icp6Dminimizer *my_icp6Dminimizer, double max_dist_match,
|
||||
int max_num_iterations, bool quiet, bool meta, int rnd, bool eP,
|
||||
int anim, double epsilonICP, int nns_method, bool cuda_enabled,
|
||||
bool cad_matching)
|
||||
{
|
||||
this->my_icp6Dminimizer = my_icp6Dminimizer;
|
||||
this->anim = anim;
|
||||
this->cuda_enabled = cuda_enabled;
|
||||
this->nns_method = nns_method;
|
||||
|
||||
if (!quiet) {
|
||||
cout << "Maximal distance match : " << max_dist_match << endl
|
||||
<< "Maximal number of iterations: " << max_num_iterations << endl << endl;
|
||||
}
|
||||
|
||||
// checks
|
||||
if (max_dist_match < 0.0) {
|
||||
cerr << "ERROR [ICP6D]: first parameter (max_dist_match) has to be >= 0," << endl;
|
||||
exit(1);
|
||||
}
|
||||
if (max_num_iterations < 0) {
|
||||
cerr << "ERROR [ICP6D]: second parameter (max_num_iterations) has to be >= 0." << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
this->max_dist_match2 = sqr(max_dist_match);
|
||||
this->max_num_iterations = max_num_iterations;
|
||||
this->quiet = quiet;
|
||||
this->meta = meta;
|
||||
this->rnd = rnd;
|
||||
this->eP = eP;
|
||||
this->epsilonICP = epsilonICP;
|
||||
|
||||
// Set initial seed (for "real" random numbers)
|
||||
// srand( (unsigned)time( NULL ) );
|
||||
this->cad_matching = cad_matching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a 3D Scan against a 3D Scan
|
||||
* @param PreviousScan The scan or metascan forming the model
|
||||
* @param CurrentScan The current scan thas is to be matched
|
||||
* @return The number of iterations done in this matching run
|
||||
*/
|
||||
int icp6D::match(Scan* PreviousScan, Scan* CurrentScan)
|
||||
{
|
||||
// If ICP shall not be applied, then just write
|
||||
// the identity matrix
|
||||
if (max_num_iterations == 0) {
|
||||
double id[16];
|
||||
M4identity(id);
|
||||
CurrentScan->transform(id, Scan::ICP, 0); // write end pose
|
||||
return 0;
|
||||
}
|
||||
|
||||
// icp main loop
|
||||
double ret = 0.0, prev_ret = 0.0, prev_prev_ret = 0.0;
|
||||
int iter = 0;
|
||||
double alignxf[16];
|
||||
for (iter = 0; iter < max_num_iterations; iter++) {
|
||||
|
||||
prev_prev_ret = prev_ret;
|
||||
prev_ret = ret;
|
||||
|
||||
#ifdef _OPENMP
|
||||
// Implementation according to the paper
|
||||
// "The Parallel Iterative Closest Point Algorithm"
|
||||
// by Langis / Greenspan / Godin, IEEE 3DIM 2001
|
||||
//
|
||||
// The same information are given in (ecrm2007.pdf)
|
||||
// Andreas Nüchter. Parallelization of Scan Matching
|
||||
// for Robotic 3D Mapping. In Proceedings of the 3rd
|
||||
// European Conference on Mobile Robots (ECMR '07),
|
||||
// Freiburg, Germany, September 2007
|
||||
omp_set_num_threads(OPENMP_NUM_THREADS);
|
||||
|
||||
int max = (int)CurrentScan->size<DataXYZ>("xyz reduced");
|
||||
int step = max / OPENMP_NUM_THREADS;
|
||||
|
||||
vector<PtPair> pairs[OPENMP_NUM_THREADS];
|
||||
double sum[OPENMP_NUM_THREADS];
|
||||
double centroid_m[OPENMP_NUM_THREADS][3];
|
||||
double centroid_d[OPENMP_NUM_THREADS][3];
|
||||
double Si[OPENMP_NUM_THREADS][9];
|
||||
unsigned int n[OPENMP_NUM_THREADS];
|
||||
|
||||
for (int i = 0; i < OPENMP_NUM_THREADS; i++) {
|
||||
sum[i] = centroid_m[i][0] = centroid_m[i][1] = centroid_m[i][2] = 0.0;
|
||||
centroid_d[i][0] = centroid_d[i][1] = centroid_d[i][2] = 0.0;
|
||||
Si[i][0] = Si[i][1] = Si[i][2] = Si[i][3] = Si[i][4] = Si[i][5] = Si[i][6] = Si[i][7] = Si[i][8] = 0.0;
|
||||
n[i] = 0;
|
||||
}
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
int thread_num = omp_get_thread_num();
|
||||
|
||||
Scan::getPtPairsParallel(pairs, PreviousScan, CurrentScan,
|
||||
thread_num, step,
|
||||
rnd, max_dist_match2,
|
||||
sum, centroid_m, centroid_d);
|
||||
|
||||
n[thread_num] = (unsigned int)pairs[thread_num].size();
|
||||
|
||||
if ((my_icp6Dminimizer->getAlgorithmID() == 1) ||
|
||||
(my_icp6Dminimizer->getAlgorithmID() == 2)) {
|
||||
for (unsigned int i = 0; i < n[thread_num]; i++) {
|
||||
|
||||
double pp[3] = {pairs[thread_num][i].p1.x - centroid_m[thread_num][0],
|
||||
pairs[thread_num][i].p1.y - centroid_m[thread_num][1],
|
||||
pairs[thread_num][i].p1.z - centroid_m[thread_num][2]};
|
||||
double qq[3] = {pairs[thread_num][i].p2.x - centroid_d[thread_num][0],
|
||||
pairs[thread_num][i].p2.y - centroid_d[thread_num][1],
|
||||
pairs[thread_num][i].p2.z - centroid_d[thread_num][2]};
|
||||
/*
|
||||
double pp[3] = {pairs[thread_num][i].p1.x - centroid_d[thread_num][0],
|
||||
pairs[thread_num][i].p1.y - centroid_d[thread_num][1],
|
||||
pairs[thread_num][i].p1.z - centroid_d[thread_num][2]};
|
||||
double qq[3] = {pairs[thread_num][i].p2.x - centroid_m[thread_num][0],
|
||||
pairs[thread_num][i].p2.y - centroid_m[thread_num][1],
|
||||
pairs[thread_num][i].p2.z - centroid_m[thread_num][2]};
|
||||
*/
|
||||
// formula (6)
|
||||
Si[thread_num][0] += pp[0] * qq[0];
|
||||
Si[thread_num][1] += pp[0] * qq[1];
|
||||
Si[thread_num][2] += pp[0] * qq[2];
|
||||
Si[thread_num][3] += pp[1] * qq[0];
|
||||
Si[thread_num][4] += pp[1] * qq[1];
|
||||
Si[thread_num][5] += pp[1] * qq[2];
|
||||
Si[thread_num][6] += pp[2] * qq[0];
|
||||
Si[thread_num][7] += pp[2] * qq[1];
|
||||
Si[thread_num][8] += pp[2] * qq[2];
|
||||
}
|
||||
}
|
||||
} // end parallel
|
||||
|
||||
// do we have enough point pairs?
|
||||
unsigned int pairssize = 0;
|
||||
for (int i = 0; i < OPENMP_NUM_THREADS; i++) {
|
||||
pairssize += n[i];
|
||||
}
|
||||
if (pairssize > 3) {
|
||||
if ((my_icp6Dminimizer->getAlgorithmID() == 1) ||
|
||||
(my_icp6Dminimizer->getAlgorithmID() == 2) ) {
|
||||
ret = my_icp6Dminimizer->Point_Point_Align_Parallel(OPENMP_NUM_THREADS,
|
||||
n, sum, centroid_m, centroid_d, Si,
|
||||
alignxf);
|
||||
} else if (my_icp6Dminimizer->getAlgorithmID() == 6) {
|
||||
ret = my_icp6Dminimizer->Point_Point_Align_Parallel(OPENMP_NUM_THREADS,
|
||||
n, sum, centroid_m, centroid_d,
|
||||
pairs,
|
||||
alignxf);
|
||||
} else {
|
||||
cout << "This parallel minimization algorithm is not implemented !!!" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
//break;
|
||||
}
|
||||
#else
|
||||
|
||||
double centroid_m[3] = {0.0, 0.0, 0.0};
|
||||
double centroid_d[3] = {0.0, 0.0, 0.0};
|
||||
vector<PtPair> pairs;
|
||||
|
||||
Scan::getPtPairs(&pairs, PreviousScan, CurrentScan, 0, rnd,
|
||||
max_dist_match2, ret, centroid_m, centroid_d);
|
||||
|
||||
// do we have enough point pairs?
|
||||
if (pairs.size() > 3) {
|
||||
if (my_icp6Dminimizer->getAlgorithmID() == 3 || my_icp6Dminimizer->getAlgorithmID() == 8 ) {
|
||||
memcpy(alignxf, CurrentScan->get_transMat(), sizeof(alignxf));
|
||||
}
|
||||
ret = my_icp6Dminimizer->Point_Point_Align(pairs, alignxf, centroid_m, centroid_d);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ((iter == 0 && anim != -2) || ((anim > 0) && (iter % anim == 0))) {
|
||||
CurrentScan->transform(alignxf, Scan::ICP, 0); // transform the current scan
|
||||
} else {
|
||||
CurrentScan->transform(alignxf, Scan::ICP, -1); // transform the current scan
|
||||
}
|
||||
|
||||
if ((fabs(ret - prev_ret) < epsilonICP) && (fabs(ret - prev_prev_ret) < epsilonICP)) {
|
||||
double id[16];
|
||||
M4identity(id);
|
||||
if(anim == -2) {
|
||||
CurrentScan->transform(id, Scan::ICP, -1); // write end pose
|
||||
} else {
|
||||
CurrentScan->transform(id, Scan::ICP, 0); // write end pose
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Computes the point to point error between two scans
|
||||
*
|
||||
*
|
||||
*/
|
||||
double icp6D::Point_Point_Error(Scan* PreviousScan, Scan* CurrentScan, double max_dist_match, unsigned int *np) {
|
||||
double error = 0;
|
||||
unsigned int nr_ppairs = 0;
|
||||
|
||||
#ifdef _OPENMP
|
||||
omp_set_num_threads(OPENMP_NUM_THREADS);
|
||||
|
||||
int max = (int)CurrentScan->size<DataXYZ>("xyz reduced");
|
||||
int step = max / OPENMP_NUM_THREADS;
|
||||
|
||||
vector<PtPair> pairs[OPENMP_NUM_THREADS];
|
||||
double sum[OPENMP_NUM_THREADS];
|
||||
double centroid_m[OPENMP_NUM_THREADS][3];
|
||||
double centroid_d[OPENMP_NUM_THREADS][3];
|
||||
|
||||
for (int i = 0; i < OPENMP_NUM_THREADS; i++) {
|
||||
sum[i] = centroid_m[i][0] = centroid_m[i][1] = centroid_m[i][2] = 0.0;
|
||||
centroid_d[i][0] = centroid_d[i][1] = centroid_d[i][2] = 0.0;
|
||||
}
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
int thread_num = omp_get_thread_num();
|
||||
Scan::getPtPairsParallel(pairs, PreviousScan, CurrentScan,
|
||||
thread_num, step,
|
||||
rnd, sqr(max_dist_match),
|
||||
sum, centroid_m, centroid_d);
|
||||
|
||||
}
|
||||
|
||||
for (unsigned int thread_num = 0; thread_num < OPENMP_NUM_THREADS; thread_num++) {
|
||||
for (unsigned int i = 0; i < (unsigned int)pairs[thread_num].size(); i++) {
|
||||
error += sqr(pairs[thread_num][i].p1.x - pairs[thread_num][i].p2.x)
|
||||
+ sqr(pairs[thread_num][i].p1.y - pairs[thread_num][i].p2.y)
|
||||
+ sqr(pairs[thread_num][i].p1.z - pairs[thread_num][i].p2.z);
|
||||
}
|
||||
nr_ppairs += (unsigned int)pairs[thread_num].size();
|
||||
}
|
||||
#else
|
||||
|
||||
double centroid_m[3] = {0.0, 0.0, 0.0};
|
||||
double centroid_d[3] = {0.0, 0.0, 0.0};
|
||||
vector<PtPair> pairs;
|
||||
|
||||
Scan::getPtPairs(&pairs, PreviousScan, CurrentScan, 0, rnd, sqr(max_dist_match),error, centroid_m, centroid_d);
|
||||
|
||||
// getPtPairs computes error as sum of squared distances
|
||||
error = 0;
|
||||
|
||||
for (unsigned int i = 0; i < pairs.size(); i++) {
|
||||
error += sqrt(
|
||||
sqr(pairs[i].p1.x - pairs[i].p2.x)
|
||||
+ sqr(pairs[i].p1.y - pairs[i].p2.y)
|
||||
+ sqr(pairs[i].p1.z - pairs[i].p2.z) );
|
||||
}
|
||||
nr_ppairs = pairs.size();
|
||||
#endif
|
||||
|
||||
if (np) *np = nr_ppairs;
|
||||
// return sqrt(error/nr_ppairs);
|
||||
return error/nr_ppairs;
|
||||
}
|
||||
/**
|
||||
* This function matches the scans only with ICP
|
||||
*
|
||||
* @param allScans Contains all necessary scans.
|
||||
*/
|
||||
void icp6D::doICP(vector <Scan *> allScans)
|
||||
{
|
||||
double id[16];
|
||||
M4identity(id);
|
||||
|
||||
vector < Scan* > meta_scans;
|
||||
Scan* my_MetaScan = 0;
|
||||
|
||||
|
||||
for(unsigned int i = 0; i < allScans.size(); i++) {
|
||||
cout << i << "*" << endl;
|
||||
|
||||
Scan *CurrentScan = allScans[i];
|
||||
Scan *PreviousScan = 0;
|
||||
|
||||
if (i > 0) {
|
||||
PreviousScan = allScans[i-1];
|
||||
if (eP) { // extrapolate odometry
|
||||
CurrentScan->mergeCoordinatesWithRoboterPosition(PreviousScan);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
if (meta) {
|
||||
match(my_MetaScan, CurrentScan);
|
||||
} else
|
||||
if (cad_matching) {
|
||||
match(allScans[0], CurrentScan);
|
||||
} else {
|
||||
match(PreviousScan, CurrentScan);
|
||||
}
|
||||
}
|
||||
|
||||
// push processed scan
|
||||
if ( meta && i != allScans.size()-1 ) {
|
||||
meta_scans.push_back(CurrentScan);
|
||||
if (my_MetaScan) {
|
||||
delete my_MetaScan;
|
||||
}
|
||||
my_MetaScan = new MetaScan(meta_scans, nns_method, cuda_enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
### TOOLS
|
||||
|
||||
IF(WITH_TOOLS)
|
||||
FIND_PACKAGE(OpenCV REQUIRED)
|
||||
### SCAN_RED
|
||||
add_executable(scan_red scan_red.cc fbr/fbr_global.cc fbr/panorama.cc fbr/scan_cv.cc)
|
||||
|
||||
IF(UNIX)
|
||||
target_link_libraries(scan_red scan dl ANN fbr_cv_io fbr_panorama ${OpenCV_LIBS})
|
||||
ENDIF(UNIX)
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(scan_red scan ANN XGetopt)
|
||||
ENDIF(WIN32)
|
||||
|
||||
### SCAN_DIFF
|
||||
add_executable(scan_diff scan_diff.cc)
|
||||
# add_executable(scan_diff2d scan_diff2d.cc ../show/colormanager.cc)
|
||||
|
||||
IF(UNIX)
|
||||
target_link_libraries(scan_diff scan dl ANN)
|
||||
# target_link_libraries(scan_diff2d scan dl ANN)
|
||||
ENDIF(UNIX)
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(scan_diff scan ANN XGetopt)
|
||||
# target_link_libraries(scan_diff2d scan ANN XGetopt)
|
||||
ENDIF(WIN32)
|
||||
|
||||
add_executable(frame_to_graph frame_to_graph.cc)
|
||||
add_executable(convergence convergence.cc)
|
||||
add_executable(graph_balancer graph_balancer.cc)
|
||||
add_executable(exportPoints exportPoints.cc)
|
||||
add_executable(frames2riegl frames2riegl.cc)
|
||||
add_executable(frames2pose frames2pose.cc)
|
||||
add_executable(pose2frames pose2frames.cc)
|
||||
add_executable(riegl2frames riegl2frames.cc)
|
||||
add_executable(toGlobal toGlobal.cc)
|
||||
|
||||
IF(UNIX)
|
||||
target_link_libraries(graph_balancer scan ${Boost_GRAPH_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} ${Boost_REGEX_LIBRARY})
|
||||
target_link_libraries(exportPoints scan dl ANN)
|
||||
target_link_libraries(toGlobal scan)
|
||||
ENDIF(UNIX)
|
||||
|
||||
|
||||
IF (WIN32)
|
||||
target_link_libraries(frame_to_graph XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(convergence XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(graph_balancer scan XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(exportPoints scan ANN XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(frames2pose XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(pose2frames XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(frames2riegl XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(riegl2frames XGetopt ${Boost_LIBRARIES})
|
||||
target_link_libraries(toGlobal XGetopt ${Boost_LIBRARIES})
|
||||
ENDIF(WIN32)
|
||||
ENDIF(WITH_TOOLS)
|
||||
|
||||
### SCANLIB
|
||||
|
||||
SET(SCANLIB_SRCS
|
||||
kd.cc kdManaged.cc kdMeta.cc graphSlam6D.cc
|
||||
graph.cc icp6Dapx.cc icp6D.cc icp6Dsvd.cc
|
||||
icp6Dortho.cc icp6Dquat.cc icp6Dhelix.cc icp6Dlumeuler.cc
|
||||
icp6Dlumquat.cc icp6Ddual.cc lum6Deuler.cc lum6Dquat.cc
|
||||
ghelix6DQ2.cc gapx6D.cc graphToro.cc ann_kd.cc
|
||||
graphHOG-Man.cc elch6D.cc elch6Dquat.cc elch6DunitQuat.cc
|
||||
elch6Dslerp.cc elch6Deuler.cc loopToro.cc loopHOG-Man.cc
|
||||
point_type.cc icp6Dquatscale.cc searchTree.cc Boctree.cc
|
||||
allocator.cc
|
||||
scan.cc basicScan.cc managedScan.cc metaScan.cc
|
||||
io_types.cc io_utils.cc pointfilter.cc
|
||||
)
|
||||
|
||||
if(WITH_METRICS)
|
||||
set(SCANLIB_SRCS ${SCANLIB_SRCS} metrics.cc)
|
||||
endif(WITH_METRICS)
|
||||
|
||||
add_library(scan STATIC ${SCANLIB_SRCS})
|
||||
|
||||
target_link_libraries(scan scanclient scanio)
|
||||
|
||||
IF(UNIX)
|
||||
target_link_libraries(scan dl)
|
||||
ENDIF(UNIX)
|
||||
|
||||
### EXPORT SHARED LIBS
|
||||
|
||||
IF(EXPORT_SHARED_LIBS)
|
||||
add_library(scan_s SHARED ${SCANLIB_SRCS})
|
||||
#target_link_libraries(scan_s ${Boost_LIBRARIES} newmat)
|
||||
target_link_libraries(scan_s newmat sparse ANN scanclient pointfilter scanio)
|
||||
ENDIF(EXPORT_SHARED_LIBS)
|
||||
|
||||
### SLAM6D
|
||||
|
||||
IF(WITH_CUDA)
|
||||
CUDA_COMPILE(CUDA_FILES cuda/CIcpGpuCuda.cu )
|
||||
add_executable(slam6D slam6D.cc cuda/icp6Dcuda.cc ${CUDA_FILES})
|
||||
target_link_libraries(slam6D ${CUDA_LIBRARIES} ANN cudpp64)
|
||||
CUDA_ADD_CUBLAS_TO_TARGET(slam6D)
|
||||
CUDA_ADD_CUTIL_TO_TARGET(slam6D)
|
||||
ELSE(WITH_CUDA)
|
||||
add_executable(slam6D slam6D.cc)
|
||||
ENDIF(WITH_CUDA)
|
||||
|
||||
IF(UNIX)
|
||||
target_link_libraries(slam6D scan newmat sparse ANN)
|
||||
ENDIF(UNIX)
|
||||
|
||||
IF(WIN32)
|
||||
target_link_libraries(slam6D scan newmat sparse ANN XGetopt ${Boost_LIBRARIES})
|
||||
ENDIF(WIN32)
|
||||
|
||||
#IF(MSVC)
|
||||
# INSTALL(TARGETS slam6D RUNTIME DESTINATION ${CMAKE_SOURCE_DIR}/windows)
|
||||
#ENDIF(MSVC)
|
|
@ -0,0 +1,929 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Representation of an octree for show
|
||||
* @author Jan Elseberg. Jacobs University Bremen gGmbH, Germany
|
||||
* @author Andreas Nuechter. Jacobs University Bremen gGmbH, Germany
|
||||
*/
|
||||
|
||||
#ifndef SHOWBOCTREE_H
|
||||
#define SHOWBOCTREE_H
|
||||
|
||||
#include "slam6d/Boctree.h"
|
||||
#include "show/colormanager.h"
|
||||
#include "show/scancolormanager.h"
|
||||
#include "show/viewcull.h"
|
||||
#include "show/colordisplay.h"
|
||||
#include "slam6d/scan.h"
|
||||
|
||||
using namespace show;
|
||||
|
||||
/**
|
||||
* @brief Octree for show
|
||||
*
|
||||
* A cubic bounding box is calculated
|
||||
* from the given 3D points. Then it
|
||||
* is recusivly subdivided into smaller
|
||||
* subboxes
|
||||
*
|
||||
* It contains software culling functionalities
|
||||
*/
|
||||
template <class T>
|
||||
class Show_BOctTree : public colordisplay
|
||||
{
|
||||
protected:
|
||||
BOctTree<T>* m_tree;
|
||||
|
||||
unsigned long maxtargetpoints;
|
||||
|
||||
unsigned int current_lod_mode;
|
||||
|
||||
//! A copy of pointdim of the tree initialized from
|
||||
unsigned int POINTDIM;
|
||||
|
||||
DataOcttree* m_cache_access;
|
||||
Scan* m_scan;
|
||||
|
||||
void init(ScanColorManager* scm) {
|
||||
setColorManager(0);
|
||||
if (scm) {
|
||||
scm->registerTree(this);
|
||||
scm->updateRanges(m_tree->getMins());
|
||||
scm->updateRanges(m_tree->getMaxs());
|
||||
}
|
||||
POINTDIM = m_tree->getPointdim();
|
||||
maxtargetpoints = maxTargetPoints(m_tree->getRoot());
|
||||
current_lod_mode = 0;
|
||||
m_cache_access = 0;
|
||||
m_scan = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
//! Create with tree held in cache, lock indefinitely
|
||||
Show_BOctTree(Scan* scan, DataOcttree* cache_access, ScanColorManager* scm = 0)
|
||||
{
|
||||
m_tree = &cache_access->get();
|
||||
init(scm);
|
||||
// save cache access and hold it until an unlock
|
||||
m_cache_access = cache_access;
|
||||
m_scan = scan;
|
||||
}
|
||||
|
||||
//! Retrieve a cache access object and update the tree pointer
|
||||
void lockCachedTree() {
|
||||
if(m_scan != 0 && m_cache_access == 0) {
|
||||
m_cache_access = new DataOcttree(m_scan->get("octtree"));
|
||||
m_tree = &(m_cache_access->get());
|
||||
}
|
||||
}
|
||||
|
||||
//! Remove the data access
|
||||
void unlockCachedTree() {
|
||||
if(m_scan != 0 && m_cache_access != 0) {
|
||||
delete m_cache_access; m_cache_access = 0;
|
||||
//m_tree = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//! Create with already constructed tree and take ownership
|
||||
Show_BOctTree(BOctTree<T>* tree, ScanColorManager* scm = 0) :
|
||||
m_tree(tree)
|
||||
{
|
||||
init(scm);
|
||||
}
|
||||
|
||||
//! Create tree by points
|
||||
template <class P>
|
||||
Show_BOctTree(P * const* pts, int n, T voxelSize, PointType pointtype = PointType(), ScanColorManager *scm = 0)
|
||||
{
|
||||
m_tree = new BOctTree<T>(pts, n, voxelSize, pointtype, true);
|
||||
init(scm);
|
||||
}
|
||||
|
||||
//! Create tree by deserializing from file
|
||||
Show_BOctTree(std::string filename, ScanColorManager *scm = 0)
|
||||
{
|
||||
m_tree = new BOctTree<T>(filename);
|
||||
init(scm);
|
||||
}
|
||||
|
||||
virtual ~Show_BOctTree() {
|
||||
// only delete cache access if created via this method
|
||||
if(m_cache_access) {
|
||||
delete m_cache_access;
|
||||
}
|
||||
// if not constructed by a cache-located tree, delete the owned tree
|
||||
if(!m_scan)
|
||||
delete m_tree;
|
||||
}
|
||||
|
||||
BOctTree<T>* getTree() const { return m_tree; }
|
||||
|
||||
void serialize(const std::string& filename) const { m_tree->serialize(filename); }
|
||||
|
||||
unsigned int getMemorySize() const { return m_tree->getMemorySize(); }
|
||||
|
||||
// virtual functions from colordisplay
|
||||
|
||||
void selectRayBrushSize(set<T *> &points, int brushsize) {
|
||||
selectRayBS(points, m_tree->getRoot(), m_tree->getCenter(), m_tree->getSize(), brushsize);
|
||||
}
|
||||
|
||||
void selectRay(set<T *> &points, int depth = INT_MAX) {
|
||||
selectRay(points, m_tree->getRoot(), m_tree->getCenter(), m_tree->getSize(), depth);
|
||||
}
|
||||
|
||||
void selectRay(T * &point) {
|
||||
selectRay(point, m_tree->getRoot(), m_tree->getCenter(), m_tree->getSize(), FLT_MAX);
|
||||
}
|
||||
|
||||
void cycleLOD() {
|
||||
current_lod_mode = (current_lod_mode+1)%3;
|
||||
}
|
||||
|
||||
void drawLOD(float ratio) {
|
||||
switch (current_lod_mode) {
|
||||
case 0:
|
||||
glBegin(GL_POINTS);
|
||||
displayOctTreeCulledLOD(maxtargetpoints * ratio, m_tree->getRoot(), m_tree->getCenter(), m_tree->getSize());
|
||||
glEnd();
|
||||
break;
|
||||
case 1:
|
||||
glBegin(GL_POINTS);
|
||||
displayOctTreeCulledLOD2(ratio, m_tree->getRoot(), m_tree->getCenter(), m_tree->getSize());
|
||||
glEnd();
|
||||
break;
|
||||
case 2:
|
||||
#ifdef WITH_GLEE
|
||||
if (GLEE_ARB_point_parameters) {
|
||||
glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1.0);
|
||||
glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, 100000.0);
|
||||
GLfloat p[3] = {0.0, 0.0000, 0.0000005};
|
||||
glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, p);
|
||||
displayOctTreeCPAllCulled(m_tree->getRoot(), m_tree->getCenter(), m_tree->getSize(),
|
||||
m_tree->getSize() / pow(2, min( (int)(ratio * m_tree->getMaxDepth()), (int)(m_tree->getMaxDepth() - 3))));
|
||||
p[0] = 1.0;
|
||||
p[2] = 0.0;
|
||||
glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, p);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
glBegin(GL_POINTS);
|
||||
displayOctTreeAllCulled(m_tree->getRoot(), m_tree->getCenter(), m_tree->getSize());
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// reroute center call (for recast from colordisplay to show_bocttree)
|
||||
void getCenter(double _center[3]) const {
|
||||
m_tree->getCenter(_center);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! ?
|
||||
unsigned long maxTargetPoints(const bitoct &node) {
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
unsigned long max = 0;
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned long length = points[0].length;
|
||||
if (length > max) max = length;
|
||||
} else { // recurse
|
||||
unsigned long tp = maxTargetPoints(children->node);
|
||||
if (tp > max) max = tp;
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
|
||||
return max*POPCOUNT(node.valid);
|
||||
}
|
||||
|
||||
void displayOctTreeAll(const bitoct &node) {
|
||||
// T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeAll( children->node);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeAllCulled(const bitoct &node, const T* center, T size ) {
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeAll(node);
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
// if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
//}
|
||||
} else { // recurse
|
||||
displayOctTreeAllCulled( children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeLOD2(float ratio, const bitoct &node, const T* center, T size ) {
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
l = max((int)(l*l*ratio), 0);
|
||||
if (l > 1) {
|
||||
if ((int)length > l ) {
|
||||
T each = (T)POINTDIM * (T)((T)length/(T)l);
|
||||
T *p;
|
||||
int index;
|
||||
for(int iterator = 0; iterator < l; iterator++ ) {
|
||||
index = (T)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
glVertex3f( p[0], p[1], p[2]);
|
||||
}
|
||||
} else if ((int)length <= l) {
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} /* else if (l == 1) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
}*/
|
||||
} else {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
}
|
||||
} else { // recurse
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
l = max((int)(l*l*ratio), 0);
|
||||
if (l > 0) {
|
||||
displayOctTreeCulledLOD2(ratio, children->node, ccenter, size/2.0);
|
||||
}
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeCulledLOD2(float ratio, const bitoct &node, const T* center, T size ) {
|
||||
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeLOD2(ratio, node, center, size);
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
l = max((int)(l*l*ratio), 0);
|
||||
if (l != 0) {
|
||||
if ((int)length > l ) {
|
||||
T each = (T)POINTDIM * (T)((T)length/(T)l);
|
||||
T *p;
|
||||
int index;
|
||||
for(int iterator = 0; iterator < l; iterator++ ) {
|
||||
index = (T)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
glVertex3f( p[0], p[1], p[2]);
|
||||
}
|
||||
} else if ((int)length <= l) {
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else if (l == 1) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
//int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
//l = max((int)(l*l*ratio), 0);
|
||||
//if (l > 0) {
|
||||
displayOctTreeCulledLOD2(ratio, children->node, ccenter, size/2.0);
|
||||
//}
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeLOD3(long targetpts, const bitoct &node, const T* center, T size ) {
|
||||
if (targetpts <= 0) return; // no need to display anything
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
|
||||
if ( l <= targetpts) { // only a single pixel on screen only paint one point
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
} else {
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeLOD3(targetpts, children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeCulledLOD3(long targetpts, const bitoct &node, const T* center, T size ) {
|
||||
if (targetpts <= 0) return; // no need to display anything
|
||||
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeLOD3(targetpts, node, center, size);
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
//l = std::min( max((int)(l*l*ratio), 1), targetpts);
|
||||
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
|
||||
int l = LOD2(ccenter[0], ccenter[1], ccenter[2], size/2.0); // only a single pixel on screen only paint one point
|
||||
if (targetpts <= 0 ) cout << l << " " << targetpts << endl;
|
||||
if ( l <= targetpts) { // only a single pixel on screen only paint one point
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
} else {
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else { // recurse
|
||||
displayOctTreeCulledLOD3(targetpts, children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeCulledLOD(long targetpts, const bitoct &node, const T* center, T size ) {
|
||||
if (targetpts <= 0) return; // no need to display anything
|
||||
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeLOD(targetpts, node, center, size);
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
unsigned short nc = POPCOUNT(node.valid);
|
||||
long newtargetpts = targetpts;
|
||||
if (nc > 0) {
|
||||
newtargetpts = newtargetpts/nc;
|
||||
if (newtargetpts <= 0 ) return;
|
||||
}
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
|
||||
if (length > 10 && !LOD(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) { // only a single pixel on screen only paint one point
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
} else if (length <= newtargetpts) { // more points requested than possible, plot all
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else { // select points to show
|
||||
// TODO smarter subselection of points here
|
||||
T each = (T)POINTDIM * (T)((T)length/(T)newtargetpts);
|
||||
T *p;
|
||||
int index;
|
||||
for(unsigned int iterator = 0; iterator < newtargetpts; iterator++ ) {
|
||||
index = (T)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
glVertex3f( p[0], p[1], p[2]);
|
||||
//point += each;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else { // recurse
|
||||
displayOctTreeCulledLOD(newtargetpts, children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeLOD(long targetpts, const bitoct &node, const T* center, T size ) {
|
||||
if (targetpts <= 0) return; // no need to display anything
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
unsigned short nc = POPCOUNT(node.valid);
|
||||
long newtargetpts = targetpts;
|
||||
if (nc > 0) {
|
||||
newtargetpts = newtargetpts/nc;
|
||||
if (newtargetpts <= 0 ) return;
|
||||
}
|
||||
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
if (length > 10 && !LOD(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) { // only a single pixel on screen only paint one point
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
} else if (length <= newtargetpts) { // more points requested than possible, plot all
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else { // select points to show
|
||||
// TODO smarter subselection of points here
|
||||
T each = (T)POINTDIM * (T)((T)length/(T)newtargetpts);
|
||||
T *p;
|
||||
int index;
|
||||
for(unsigned int iterator = 0; iterator < newtargetpts; iterator++ ) {
|
||||
index = (T)iterator * each;
|
||||
p = point + index - index%POINTDIM;
|
||||
if(cm) cm->setColor(p);
|
||||
glVertex3f( p[0], p[1], p[2]);
|
||||
//point += each;
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeLOD(newtargetpts, children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
void selectRay(set<T *> &selpoints, const bitoct &node, const T* center, T size, int max_depth, int depth = 0) {
|
||||
if (depth < max_depth && !HitBoundingBox(center, size ))return;
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( !(depth+1 < max_depth) || HitBoundingBox(ccenter, size) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
selpoints.insert(point);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
selectRay( selpoints, children->node, ccenter, size/2.0, max_depth, depth+1);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void selectRayBS(set<T *> &selpoints, const bitoct &node, const T* center, T size, int brushsize) {
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( HitBoundingBox(ccenter, size) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if (ScreenDist(point) < brushsize && RayDist(point) > 100.0)
|
||||
selpoints.insert(point);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
selectRayBS( selpoints, children->node, ccenter, size/2.0, brushsize);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void selectRay(T * &selpoint, const bitoct &node, const T* center, T size, float min) {
|
||||
if (!HitBoundingBox(center, size ))return;
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( HitBoundingBox(ccenter, size) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
T dist = RayDist(point);
|
||||
if (min > dist && ScreenDist(point) < 5 && dist > 100.0) {
|
||||
selpoint = point;
|
||||
min = dist;
|
||||
}
|
||||
point+=POINTDIM;
|
||||
}
|
||||
}
|
||||
} else { // recurse
|
||||
selectRay( selpoint, children->node, ccenter, size/2.0, min);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeCAllCulled(const bitoct &node, const T* center, T size, T minsize ) {
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeCAll(node, center, size, minsize);
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf || minsize > size ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
showCube(ccenter, size/2.0);
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeCAllCulled( children->node, ccenter, size/2.0, minsize);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeCAll(const bitoct &node, const T* center, T size, T minsize ) {
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf || minsize > size ) { // if ith node is leaf get center
|
||||
showCube(ccenter, size/2.0);
|
||||
} else { // recurse
|
||||
displayOctTreeCAll( children->node, ccenter, size/2.0, minsize);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void displayOctTreeCPAllCulled(const bitoct &node, const T* center, T size, T minsize ) {
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return; // culled do not continue with this branch of the tree
|
||||
|
||||
if (res == 2) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeCPAll(node, center, size, minsize);
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( minsize > size ) {
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
if(cm) {
|
||||
if (( 1 << i ) & node.leaf )
|
||||
cm->setColor( &(children->getPoints()[1]) );
|
||||
else
|
||||
cm->setColor( m_tree->pickPoint(children->node) );
|
||||
}
|
||||
|
||||
glPointSize(size/2.0);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3f( ccenter[0], ccenter[1], ccenter[2] );
|
||||
glEnd();
|
||||
}
|
||||
}else if ( ( 1 << i ) & node.leaf ) {
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
glPointSize(1.0);
|
||||
glBegin(GL_POINTS);
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeCPAllCulled( children->node, ccenter, size/2.0, minsize);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayOctTreeCPAll(const bitoct &node, const T* center, T size, T minsize ) {
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( minsize > size ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
if(cm) {
|
||||
if (( 1 << i ) & node.leaf )
|
||||
cm->setColor( &(children->getPoints()[1]) );
|
||||
else
|
||||
cm->setColor( m_tree->pickPoint(children->node) );
|
||||
}
|
||||
|
||||
glPointSize(size/2.0);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3f( ccenter[0], ccenter[1], ccenter[2] );
|
||||
glEnd();
|
||||
}
|
||||
}else if ( ( 1 << i ) & node.leaf ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
glPointSize(1.0);
|
||||
glBegin(GL_POINTS);
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
glEnd();
|
||||
} else { // recurse
|
||||
displayOctTreeCPAll( children->node, ccenter, size/2.0, minsize);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showCube(const T* center, T size) {
|
||||
glLineWidth(1.0);
|
||||
glBegin(GL_QUADS); // draw a cube with 6 quads
|
||||
glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] + size);
|
||||
glColor3f(1.0f,0.5f,0.0f); // Set The Color To Orange
|
||||
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] - size);
|
||||
|
||||
glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] + size);
|
||||
|
||||
glColor3f(1.0f,1.0f,0.0f); // Set The Color To Yellow
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] - size);
|
||||
|
||||
glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] - size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] - size);
|
||||
glVertex3f(center[0] - size, center[1] - size, center[2] + size);
|
||||
|
||||
glColor3f(1.0f,0.0f,1.0f); // Set The Color To Violet
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] - size);
|
||||
glVertex3f(center[0] + size, center[1] + size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] + size);
|
||||
glVertex3f(center[0] + size, center[1] - size, center[2] - size);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
void displayOctTreeAllCulled(const bitoct &node, const T* center, T size, float *frustum[6], unsigned char frustsize ) {
|
||||
float *new_frustum[6]; unsigned char counter = 0;
|
||||
for (unsigned char p = 0; p < frustsize; p++ ) {
|
||||
char res = PlaneAABB(center[0], center[1], center[2], size, frustum[p]);
|
||||
if (res == 0) { // cube is on the wrong side of the plane (not visible)
|
||||
return;
|
||||
} else if ( res == 1 ) { // plane intersects this volume continue culling with this plane
|
||||
new_frustum[counter++] = frustum[p];
|
||||
} // other case is simply not to continue culling with the respective plane
|
||||
}
|
||||
if (counter == 0) { // if entirely within frustrum discontinue culling
|
||||
displayOctTreeAll(node);
|
||||
return;
|
||||
}
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
T *point = &(points[1].v); // first point
|
||||
for(unsigned int iterator = 0; iterator < length; iterator++ ) {
|
||||
if(cm) cm->setColor(point);
|
||||
glVertex3f( point[0], point[1], point[2]);
|
||||
point+=POINTDIM;
|
||||
}
|
||||
} else { // recurse
|
||||
displayOctTreeAllCulled( children->node, ccenter, size/2.0, new_frustum, counter);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long int countVisiblePoints(const bitoct &node, const T* center, T size ) {
|
||||
unsigned long int result = 0;
|
||||
int res = CubeInFrustum2(center[0], center[1], center[2], size);
|
||||
if (res==0) return 0; // culled do not continue with this branch of the tree
|
||||
|
||||
T ccenter[3];
|
||||
bitunion<T> *children;
|
||||
bitoct::getChildren(node, children);
|
||||
|
||||
for (short i = 0; i < 8; i++) {
|
||||
if ( ( 1 << i ) & node.valid ) { // if ith node exists
|
||||
BOctTree<T>::childcenter(center, ccenter, size, i); // childrens center
|
||||
if ( ( 1 << i ) & node.leaf ) { // if ith node is leaf get center
|
||||
// check if leaf is visible
|
||||
if ( CubeInFrustum(ccenter[0], ccenter[1], ccenter[2], size/2.0) ) {
|
||||
pointrep *points = children->getPointreps();
|
||||
unsigned int length = points[0].length;
|
||||
result += length;
|
||||
}
|
||||
} else { // recurse
|
||||
result += countVisiblePoints( children->node, ccenter, size/2.0);
|
||||
}
|
||||
++children; // next child
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef __THERMO_H__
|
||||
#define __THERMO_H__
|
||||
|
||||
#include <opencv/cv.h>
|
||||
#include <opencv/highgui.h>
|
||||
#include <string>
|
||||
#include <slam6d/scan.h>
|
||||
using namespace std;
|
||||
//typedef vector<vector<float> > Float2D[1200][1600];
|
||||
typedef vector<vector<float> > Float2D[2592][3888];
|
||||
|
||||
void calcBoard(double point_array[][2], int board_n, double &x, double &y, double &cx, double &cy, bool pc);
|
||||
void sortBlobs(double point_array[][2], int board_n, int board_h, int board_w, bool quiet);
|
||||
IplImage* detectBlobs(IplImage *org_image, int &corner_exp, int board_h, int board_w, bool quiet, double point_array2[][2]);
|
||||
void drawLines(double point_array2[][2], int corner_exp, IplImage *image, bool color=false);
|
||||
IplImage* resizeImage(IplImage *source, int scale);
|
||||
IplImage* detectCorners(IplImage *orgimage, int &corner_exp, int board_h, int board_w, bool quiet, double point_array2[][2], int scale=1);
|
||||
void CalibFunc(int board_w, int board_h, int start, int end, bool optical, bool chess, bool quiet, string dir, int scale=1);
|
||||
void writeCalibParam(int images, int corner_exp, int board_w, CvMat* image_points, CvSize size, string dir);
|
||||
|
||||
void ProjectAndMap(int start, int end, bool optical, bool quiet, string dir,
|
||||
IOType type, int scale, double rot_angle, double minDist, double maxDist,
|
||||
bool correction, int neighborhood, int method=0);
|
||||
|
||||
bool readPoints(string filename, CvPoint3D32f *corners, int size) ;
|
||||
void sortElementByElement(CvMat * vectors, int nr_elems, int nr_vectors);
|
||||
void calculateExtrinsicsWithReprojectionCheck(CvMat * points2D, CvMat *
|
||||
points3D, CvMat * rotation_vectors_temp, CvMat * translation_vectors_temp, CvMat
|
||||
* distortions, CvMat * instrinsics, int corners, int successes, string dir, bool quiet=true, string substring = "") ;
|
||||
void calculateExtrinsics(CvMat * rotation_vectors_temp, CvMat * translation_vectors_temp, int successes, string dir, bool quiet=true, string substring = "") ;
|
||||
void CorrectErrorAndWrite(Float2D &data, fstream &outfile, CvSize size, bool optical);
|
||||
void clusterSearch(float ** points, int size, double thresh1, double thresh2, fstream &outfile, bool optical);
|
||||
void sortDistances(float ** points, int size);
|
||||
void ExtrCalibFunc(int board_w, int board_h, int start, int end, bool optical, bool chess, bool quiet, string dir, int scale=1);
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,33 @@
|
|||
SET(SHOW_LIBS glui scan ANN ${OPENGL_LIBRARIES})
|
||||
IF(WIN32)
|
||||
IF( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
SET(SHOW_LIBS ${SHOW_LIBS} ${CMAKE_SOURCE_DIR}/3rdparty/windows/x64/freeglut.lib XGetopt)
|
||||
ELSE( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
SET(SHOW_LIBS ${SHOW_LIBS} ${CMAKE_SOURCE_DIR}/3rdparty/windows/freeglut.lib XGetopt)
|
||||
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
ENDIF(WIN32)
|
||||
IF (UNIX)
|
||||
SET(SHOW_LIBS newmat dl ${SHOW_LIBS} ${GLUT_LIBRARIES})
|
||||
ENDIF(UNIX)
|
||||
|
||||
IF(WITH_GLEE)
|
||||
SET(SHOW_LIBS ${SHOW_LIBS} glee)
|
||||
ENDIF(WITH_GLEE)
|
||||
|
||||
SET(SHOW_SRCS NurbsPath.cc PathGraph.cc vertexarray.cc viewcull.cc colormanager.cc compacttree.cc scancolormanager.cc display.cc)
|
||||
|
||||
IF (WITH_SHOW)
|
||||
add_executable(show show.cc ${SHOW_SRCS})
|
||||
target_link_libraries(show ${SHOW_LIBS})
|
||||
ENDIF(WITH_SHOW)
|
||||
|
||||
IF(WITH_WXSHOW)
|
||||
add_executable(wxshow wxshow.cc selectionframe.cc ${SHOW_SRCS})
|
||||
target_link_libraries(wxshow ${wxWidgets_LIBRARIES} wxthings ${SHOW_LIBS})
|
||||
ENDIF(WITH_WXSHOW)
|
||||
|
||||
### EXPORT SHARED LIBS
|
||||
IF(EXPORT_SHARED_LIBS)
|
||||
add_library(show_s SHARED ${SHOW_SRCS})
|
||||
target_link_libraries(show_s ${SHOW_LIBS})
|
||||
ENDIF(EXPORT_SHARED_LIBS)
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* ann_kd implementation
|
||||
*
|
||||
* Copyright (C) Andreas Nuechter, Ulugbek Makhmudov
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Encapsules the implementation of ANN k-d trees.
|
||||
* @author Ulugbek Makhmudov, Jacobs University Bremen, Bremen, Germany.
|
||||
* @author Andreas Nuechter, Jacobs University Bremen, Bremen, Germany.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include "slam6d/ann_kd.h"
|
||||
#include "slam6d/globals.icc"
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
#include <algorithm>
|
||||
using std::swap;
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Create ANN KD tree from the points pointed to by the array pts
|
||||
*
|
||||
* @param pts 3D array of points
|
||||
* @param n number of points
|
||||
*/
|
||||
ANNtree::ANNtree(PointerArray<double>&_pts, int n)
|
||||
{
|
||||
/*
|
||||
pts = new double*[n];
|
||||
for(unsigned int i = 0; i < n; i++) {
|
||||
pts[i] = new double[3];
|
||||
pts[i][0] = _pts.get()[i][0];
|
||||
pts[i][1] = _pts.get()[i][1];
|
||||
pts[i][2] = _pts.get()[i][2];
|
||||
}
|
||||
*/
|
||||
pts = new double*[n];
|
||||
double* tpts = new double[3*n];
|
||||
for(unsigned int i = 0, j = 0; i < n; i++) {
|
||||
pts[i] = &tpts[j];
|
||||
tpts[j++] = _pts.get()[i][0];
|
||||
tpts[j++] = _pts.get()[i][1];
|
||||
tpts[j++] = _pts.get()[i][2];
|
||||
}
|
||||
|
||||
annkd = new ANNkd_tree(pts, n, 3, 1, ANN_KD_SUGGEST); // links to the constructor of ANNkd_tree
|
||||
cout << "ANNkd_tree was generated with " << n << " points" << endl;
|
||||
nn = new ANNdist[1];
|
||||
nn_idx = new ANNidx[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* Cleans up the instance of ANN KD tree
|
||||
*
|
||||
*
|
||||
*/
|
||||
ANNtree::~ANNtree()
|
||||
{
|
||||
delete annkd; //links to the destructor of ANNkd_tree
|
||||
delete [] nn;
|
||||
delete [] nn_idx;
|
||||
delete [] pts[0];
|
||||
delete [] pts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the closest point within the tree,
|
||||
* wrt. the point given as first parameter.
|
||||
* @param _p point
|
||||
* @param maxdist2 maximal search distance.
|
||||
* @param threadNum Thread number, for parallelization
|
||||
* @return Pointer to the closest point
|
||||
*/
|
||||
double *ANNtree::FindClosest(double *_p, double maxdist2, int threadNum) const
|
||||
{
|
||||
|
||||
#pragma omp critical
|
||||
annkd->annkSearch(_p, 1, nn_idx, nn, 0.0);
|
||||
|
||||
int idx = nn_idx[0];
|
||||
|
||||
if (Dist2(_p, pts[idx]) > maxdist2) return 0;
|
||||
|
||||
return pts[idx];
|
||||
}
|
||||
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* basicScan implementation
|
||||
*
|
||||
* Copyright (C) Thomas Escher, Kai Lingemann
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "slam6d/basicScan.h"
|
||||
|
||||
#include "scanio/scan_io.h"
|
||||
#include "slam6d/kd.h"
|
||||
#include "slam6d/Boctree.h"
|
||||
#include "slam6d/ann_kd.h"
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
#include "slam6d/metrics.h"
|
||||
#endif //WITH_METRICS
|
||||
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <fstream>
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
using std::flush;
|
||||
using std::string;
|
||||
using std::map;
|
||||
using std::pair;
|
||||
using std::vector;
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
using namespace boost::filesystem;
|
||||
|
||||
|
||||
|
||||
void BasicScan::openDirectory(const std::string& path, IOType type, int start, int end)
|
||||
{
|
||||
#ifdef WITH_METRICS
|
||||
Timer t = ClientMetric::read_scan_time.start();
|
||||
#endif //WITH_METRICS
|
||||
|
||||
// create an instance of ScanIO
|
||||
ScanIO* sio = ScanIO::getScanIO(type);
|
||||
|
||||
// query available scans in the directory from the ScanIO
|
||||
std::list<std::string> identifiers(sio->readDirectory(path.c_str(), start, end));
|
||||
|
||||
Scan::allScans.reserve(identifiers.size());
|
||||
|
||||
// for each identifier, create a scan
|
||||
for(std::list<std::string>::iterator it = identifiers.begin(); it != identifiers.end(); ++it) {
|
||||
Scan::allScans.push_back(new BasicScan(path, *it, type));
|
||||
}
|
||||
|
||||
#ifdef WITH_METRICS
|
||||
ClientMetric::read_scan_time.end(t);
|
||||
#endif //WITH_METRICS
|
||||
}
|
||||
|
||||
void BasicScan::closeDirectory()
|
||||
{
|
||||
// clean up the scan vector
|
||||
for(ScanVector::iterator it = Scan::allScans.begin(); it != Scan::allScans.end(); ++it)
|
||||
delete *it;
|
||||
Scan::allScans.clear();
|
||||
}
|
||||
|
||||
BasicScan::BasicScan(double *_rPos, double *_rPosTheta, vector<double*> points) {
|
||||
init();
|
||||
for(int i = 0; i < 3; i++) {
|
||||
rPos[i] = _rPos[i];
|
||||
rPosTheta[i] = _rPosTheta[i];
|
||||
}
|
||||
// write original pose matrix
|
||||
EulerToMatrix4(rPos, rPosTheta, transMatOrg);
|
||||
|
||||
// initialize transform matrices from the original one, could just copy transMatOrg to transMat instead
|
||||
transformMatrix(transMatOrg);
|
||||
|
||||
// reset the delta align matrix to represent only the transformations after local-to-global (transMatOrg) one
|
||||
M4identity(dalignxf);
|
||||
PointFilter filter;
|
||||
if(m_filter_range_set)
|
||||
filter.setRange(m_filter_max, m_filter_min);
|
||||
if(m_filter_height_set)
|
||||
filter.setHeight(m_filter_top, m_filter_bottom);
|
||||
if(m_range_mutation_set)
|
||||
filter.setRangeMutator(m_range_mutation);
|
||||
|
||||
|
||||
double* data = reinterpret_cast<double*>(create("xyz", sizeof(double) * 3 * points.size()).get_raw_pointer());
|
||||
int tmp = 0;
|
||||
for(unsigned int i = 0; i < points.size(); ++i) {
|
||||
for(unsigned int j = 0; j < 3; j++) {
|
||||
data[tmp++] = points[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicScan::BasicScan(const std::string& path, const std::string& identifier, IOType type) :
|
||||
m_path(path), m_identifier(identifier), m_type(type)
|
||||
{
|
||||
init();
|
||||
|
||||
// request pose from file
|
||||
double euler[6];
|
||||
ScanIO* sio = ScanIO::getScanIO(m_type);
|
||||
sio->readPose(m_path.c_str(), m_identifier.c_str(), euler);
|
||||
rPos[0] = euler[0];
|
||||
rPos[1] = euler[1];
|
||||
rPos[2] = euler[2];
|
||||
rPosTheta[0] = euler[3];
|
||||
rPosTheta[1] = euler[4];
|
||||
rPosTheta[2] = euler[5];
|
||||
|
||||
// write original pose matrix
|
||||
EulerToMatrix4(euler, &euler[3], transMatOrg);
|
||||
|
||||
// initialize transform matrices from the original one, could just copy transMatOrg to transMat instead
|
||||
transformMatrix(transMatOrg);
|
||||
|
||||
// reset the delta align matrix to represent only the transformations after local-to-global (transMatOrg) one
|
||||
M4identity(dalignxf);
|
||||
}
|
||||
|
||||
BasicScan::~BasicScan()
|
||||
{
|
||||
// TODO: clean m_data up
|
||||
}
|
||||
|
||||
void BasicScan::init()
|
||||
{
|
||||
m_filter_max = 0.0;
|
||||
m_filter_min = 0.0;
|
||||
m_filter_top = 0.0;
|
||||
m_filter_bottom = 0.0;
|
||||
m_range_mutation = 0.0;
|
||||
m_filter_range_set = false;
|
||||
m_filter_height_set = false;
|
||||
m_range_mutation_set = false;
|
||||
}
|
||||
|
||||
|
||||
void BasicScan::setRangeFilter(double max, double min)
|
||||
{
|
||||
m_filter_max = max;
|
||||
m_filter_min = min;
|
||||
m_filter_range_set = true;
|
||||
}
|
||||
|
||||
void BasicScan::setHeightFilter(double top, double bottom)
|
||||
{
|
||||
m_filter_top = top;
|
||||
m_filter_bottom = bottom;
|
||||
m_filter_height_set = true;
|
||||
}
|
||||
|
||||
void BasicScan::setRangeMutation(double range)
|
||||
{
|
||||
m_range_mutation_set = true;
|
||||
m_range_mutation = range;
|
||||
}
|
||||
|
||||
void BasicScan::get(unsigned int types)
|
||||
{
|
||||
ScanIO* sio = ScanIO::getScanIO(m_type);
|
||||
|
||||
vector<double> xyz;
|
||||
vector<unsigned char> rgb;
|
||||
vector<float> reflectance;
|
||||
vector<float> temperature;
|
||||
vector<float> amplitude;
|
||||
vector<int> type;
|
||||
vector<float> deviation;
|
||||
|
||||
PointFilter filter;
|
||||
if(m_filter_range_set)
|
||||
filter.setRange(m_filter_max, m_filter_min);
|
||||
if(m_filter_height_set)
|
||||
filter.setHeight(m_filter_top, m_filter_bottom);
|
||||
if(m_range_mutation_set)
|
||||
filter.setRangeMutator(m_range_mutation);
|
||||
|
||||
sio->readScan(m_path.c_str(),
|
||||
m_identifier.c_str(),
|
||||
filter,
|
||||
&xyz,
|
||||
&rgb,
|
||||
&reflectance,
|
||||
&temperature,
|
||||
&litude,
|
||||
&type,
|
||||
&deviation);
|
||||
|
||||
// for each requested and filled data vector, allocate and write contents to their new data fields
|
||||
if(types & DATA_XYZ && !xyz.empty()) {
|
||||
double* data = reinterpret_cast<double*>(create("xyz", sizeof(double) * xyz.size()).get_raw_pointer());
|
||||
for(unsigned int i = 0; i < xyz.size(); ++i) data[i] = xyz[i];
|
||||
}
|
||||
if(types & DATA_RGB && !rgb.empty()) {
|
||||
unsigned char* data = reinterpret_cast<unsigned char*>(create("rgb", sizeof(unsigned char) * rgb.size()).get_raw_pointer());
|
||||
for(unsigned int i = 0; i < rgb.size(); ++i) data[i] = rgb[i];
|
||||
}
|
||||
if(types & DATA_REFLECTANCE && !reflectance.empty()) {
|
||||
float* data = reinterpret_cast<float*>(create("reflectance", sizeof(float) * reflectance.size()).get_raw_pointer());
|
||||
for(unsigned int i = 0; i < reflectance.size(); ++i) data[i] = reflectance[i];
|
||||
}
|
||||
if(types & DATA_TEMPERATURE && !temperature.empty()) {
|
||||
float* data = reinterpret_cast<float*>(create("temperature", sizeof(float) * temperature.size()).get_raw_pointer());
|
||||
for(unsigned int i = 0; i < temperature.size(); ++i) data[i] = temperature[i];
|
||||
}
|
||||
if(types & DATA_AMPLITUDE && !amplitude.empty()) {
|
||||
int* data = reinterpret_cast<int*>(create("amplitude", sizeof(int) * amplitude.size()).get_raw_pointer());
|
||||
for(unsigned int i = 0; i < amplitude.size(); ++i) data[i] = amplitude[i];
|
||||
}
|
||||
if(types & DATA_TYPE && !type.empty()) {
|
||||
float* data = reinterpret_cast<float*>(create("type", sizeof(double) * type.size()).get_raw_pointer());
|
||||
for(unsigned int i = 0; i < type.size(); ++i) data[i] = type[i];
|
||||
}
|
||||
if(types & DATA_DEVIATION && !deviation.empty()) {
|
||||
float* data = reinterpret_cast<float*>(create("deviation", sizeof(float) * deviation.size()).get_raw_pointer());
|
||||
for(unsigned int i = 0; i < deviation.size(); ++i) data[i] = deviation[i];
|
||||
}
|
||||
}
|
||||
|
||||
DataPointer BasicScan::get(const std::string& identifier)
|
||||
{
|
||||
// try to get data
|
||||
map<string, pair<unsigned char*, unsigned int>>::iterator it = m_data.find(identifier);
|
||||
|
||||
// create data fields
|
||||
if(it == m_data.end()) {
|
||||
// load from file
|
||||
if(identifier == "xyz") get(DATA_XYZ); else
|
||||
if(identifier == "rgb") get(DATA_RGB); else
|
||||
if(identifier == "reflectance") get(DATA_REFLECTANCE); else
|
||||
if(identifier == "temperature") get(DATA_TEMPERATURE); else
|
||||
if(identifier == "amplitude") get(DATA_AMPLITUDE); else
|
||||
if(identifier == "type") get(DATA_TYPE); else
|
||||
if(identifier == "deviation") get(DATA_DEVIATION); else
|
||||
// reduce on demand
|
||||
if(identifier == "xyz reduced") calcReducedOnDemand(); else
|
||||
if(identifier == "xyz reduced original") calcReducedOnDemand(); else
|
||||
// show requests reduced points, manipulate in showing the same entry
|
||||
if(identifier == "xyz reduced show") {
|
||||
calcReducedOnDemand();
|
||||
m_data["xyz reduced show"] = m_data["xyz reduced"];
|
||||
} else
|
||||
if(identifier == "octtree") {
|
||||
createOcttree();
|
||||
}
|
||||
|
||||
it = m_data.find(identifier);
|
||||
}
|
||||
|
||||
// if nothing can be loaded, return an empty pointer
|
||||
if(it == m_data.end())
|
||||
return DataPointer(0, 0);
|
||||
else
|
||||
return DataPointer(it->second.first, it->second.second);
|
||||
}
|
||||
|
||||
DataPointer BasicScan::create(const std::string& identifier, unsigned int size)
|
||||
{
|
||||
map<string, pair<unsigned char*, unsigned int>>::iterator it = m_data.find(identifier);
|
||||
if(it != m_data.end()) {
|
||||
// try to reuse, otherwise reallocate
|
||||
if(it->second.second != size) {
|
||||
delete it->second.first;
|
||||
it->second.first = new unsigned char[size];
|
||||
it->second.second = size;
|
||||
}
|
||||
} else {
|
||||
// create a new block of data
|
||||
it = m_data.insert(
|
||||
std::make_pair(
|
||||
identifier,
|
||||
std::make_pair(
|
||||
new unsigned char[size],
|
||||
size
|
||||
)
|
||||
)
|
||||
).first;
|
||||
}
|
||||
return DataPointer(it->second.first, it->second.second);
|
||||
}
|
||||
|
||||
void BasicScan::clear(const std::string& identifier)
|
||||
{
|
||||
map<string, pair<unsigned char*, unsigned int>>::iterator it = m_data.find(identifier);
|
||||
if(it != m_data.end()) {
|
||||
delete it->second.first;
|
||||
m_data.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BasicScan::createSearchTreePrivate()
|
||||
{
|
||||
DataXYZ xyz_orig(get("xyz reduced original"));
|
||||
PointerArray<double> ar(xyz_orig);
|
||||
switch(searchtree_nnstype)
|
||||
{
|
||||
case simpleKD:
|
||||
kd = new KDtree(ar.get(), xyz_orig.size());
|
||||
break;
|
||||
case ANNTree:
|
||||
kd = new ANNtree(ar, xyz_orig.size());
|
||||
break;
|
||||
case BOCTree:
|
||||
kd = new BOctTree<double>(ar.get(), xyz_orig.size(), 10.0, PointType(), true);
|
||||
break;
|
||||
case -1:
|
||||
throw runtime_error("Cannot create a SearchTree without setting a type.");
|
||||
default:
|
||||
throw runtime_error("SearchTree type not implemented");
|
||||
}
|
||||
|
||||
// TODO: make the switch cases above work with CUDA
|
||||
if (searchtree_cuda_enabled) createANNTree();
|
||||
}
|
||||
|
||||
void BasicScan::calcReducedOnDemandPrivate()
|
||||
{
|
||||
// create reduced points and transform to initial position, save a copy of this for SearchTree
|
||||
calcReducedPoints();
|
||||
transformReduced(transMatOrg);
|
||||
copyReducedToOriginal();
|
||||
}
|
||||
|
||||
void BasicScan::createANNTree()
|
||||
{
|
||||
// TODO: metrics
|
||||
#ifdef WITH_CUDA
|
||||
if(!ann_kd_tree) {
|
||||
DataXYZ xyz_orig(get("xyz reduced original"));
|
||||
ann_kd_tree = new ANNkd_tree(PointArray<double>(xyz_orig).get(), xyz_orig.size(), 3, 1, ANN_KD_STD);
|
||||
cout << "Cuda tree was generated with " << xyz_orig.size() << " points" << endl;
|
||||
} else {
|
||||
cout << "Cuda tree exists. No need for another creation" << endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BasicScan::createOcttree()
|
||||
{
|
||||
string scanFileName = m_path + "scan" + m_identifier + ".oct";
|
||||
BOctTree<float>* btree = 0;
|
||||
|
||||
// try to load from file, if successful return
|
||||
if(octtree_loadOct && exists(scanFileName)) {
|
||||
btree = new BOctTree<float>(scanFileName);
|
||||
m_data.insert(
|
||||
std::make_pair(
|
||||
"octtree",
|
||||
std::make_pair(
|
||||
reinterpret_cast<unsigned char*>(btree),
|
||||
0 // or memorySize()?
|
||||
)
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// create octtree from scan
|
||||
if(octtree_reduction_voxelSize > 0) { // with reduction, only xyz points
|
||||
DataXYZ xyz_r(get("xyz reduced show"));
|
||||
btree = new BOctTree<float>(PointerArray<double>(xyz_r).get(), xyz_r.size(), octtree_voxelSize, octtree_pointtype, true);
|
||||
} else { // without reduction, xyz + attribute points
|
||||
float** pts = octtree_pointtype.createPointArray<float>(this);
|
||||
unsigned int nrpts = size<DataXYZ>("xyz");
|
||||
btree = new BOctTree<float>(pts, nrpts, octtree_voxelSize, octtree_pointtype, true);
|
||||
for(unsigned int i = 0; i < nrpts; ++i) delete[] pts[i]; delete[] pts;
|
||||
}
|
||||
|
||||
// save created octtree
|
||||
if(octtree_saveOct) {
|
||||
cout << "Saving octree " << scanFileName << endl;
|
||||
btree->serialize(scanFileName);
|
||||
}
|
||||
|
||||
m_data.insert(
|
||||
std::make_pair(
|
||||
"octtree",
|
||||
std::make_pair(
|
||||
reinterpret_cast<unsigned char*>(btree),
|
||||
0 // or memorySize()?
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
unsigned int BasicScan::readFrames()
|
||||
{
|
||||
string filename = m_path + "scan" + m_identifier + ".frames";
|
||||
ifstream file(filename.c_str());
|
||||
file.exceptions(ifstream::eofbit|ifstream::failbit|ifstream::badbit);
|
||||
try {
|
||||
double transformation[16];
|
||||
unsigned int type;
|
||||
do {
|
||||
file >> transformation >> type;
|
||||
m_frames.push_back(Frame(transformation, type));
|
||||
} while(file.good());
|
||||
} catch(...) {}
|
||||
|
||||
return m_frames.size();
|
||||
}
|
||||
|
||||
void BasicScan::saveFrames()
|
||||
{
|
||||
string filename = m_path + "scan" + m_identifier + ".frames";
|
||||
ofstream file(filename.c_str());
|
||||
for(vector<Frame>::iterator it = m_frames.begin(); it != m_frames.end(); ++it) {
|
||||
file << it->transformation << it->type << '\n';
|
||||
}
|
||||
file << flush;
|
||||
file.close();
|
||||
}
|
||||
|
||||
unsigned int BasicScan::getFrameCount()
|
||||
{
|
||||
return m_frames.size();
|
||||
}
|
||||
|
||||
void BasicScan::getFrame(unsigned int i, const double*& pose_matrix, AlgoType& type)
|
||||
{
|
||||
const Frame& frame(m_frames.at(i));
|
||||
pose_matrix = frame.transformation;
|
||||
type = static_cast<AlgoType>(frame.type);
|
||||
}
|
||||
|
||||
void BasicScan::addFrame(AlgoType type)
|
||||
{
|
||||
m_frames.push_back(Frame(transMat, type));
|
||||
}
|
1306
.svn/pristine/a2/a270a2194e281599167e3dd2d589deb7ef689fe5.svn-base
Normal file
1306
.svn/pristine/a2/a270a2194e281599167e3dd2d589deb7ef689fe5.svn-base
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,72 @@
|
|||
#ifndef BASIC_SCAN_H
|
||||
#define BASIC_SCAN_H
|
||||
|
||||
#include "scan.h"
|
||||
#include "frame.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
class BasicScan : public Scan {
|
||||
public:
|
||||
BasicScan() {};
|
||||
|
||||
static void openDirectory(const std::string& path, IOType type, int start, int end);
|
||||
static void closeDirectory();
|
||||
/*
|
||||
Scan(const double *euler, int maxDist = -1);
|
||||
Scan(const double rPos[3], const double rPosTheta[3], int maxDist = -1);
|
||||
Scan(const double _rPos[3], const double _rPosTheta[3], vector<double *> &pts);
|
||||
*/
|
||||
virtual ~BasicScan();
|
||||
|
||||
virtual void setRangeFilter(double max, double min);
|
||||
virtual void setHeightFilter(double top, double bottom);
|
||||
virtual void setRangeMutation(double range);
|
||||
|
||||
virtual const char* getIdentifier() const { return m_identifier.c_str(); }
|
||||
|
||||
virtual DataPointer get(const std::string& identifier);
|
||||
virtual void get(unsigned int types);
|
||||
virtual DataPointer create(const std::string& identifier, unsigned int size);
|
||||
virtual void clear(const std::string& identifier);
|
||||
virtual unsigned int readFrames();
|
||||
virtual void saveFrames();
|
||||
virtual unsigned int getFrameCount();
|
||||
virtual void getFrame(unsigned int i, const double*& pose_matrix, AlgoType& type);
|
||||
|
||||
//! Constructor for creation of Scans without openDirectory
|
||||
BasicScan(double * rPos, double * rPosTheta, std::vector<double*> points);
|
||||
|
||||
protected:
|
||||
virtual void createSearchTreePrivate();
|
||||
virtual void calcReducedOnDemandPrivate();
|
||||
virtual void addFrame(AlgoType type);
|
||||
|
||||
private:
|
||||
//! Path and identifier of where the scan is located
|
||||
std::string m_path, m_identifier;
|
||||
|
||||
IOType m_type;
|
||||
|
||||
double m_filter_max, m_filter_min, m_filter_top, m_filter_bottom, m_range_mutation;
|
||||
bool m_filter_range_set, m_filter_height_set, m_range_mutation_set;
|
||||
|
||||
std::map<std::string, std::pair<unsigned char*, unsigned int>> m_data;
|
||||
|
||||
std::vector<Frame> m_frames;
|
||||
|
||||
|
||||
//! Constructor for openDirectory
|
||||
BasicScan(const std::string& path, const std::string& identifier, IOType type);
|
||||
|
||||
//! Initialization function
|
||||
void init();
|
||||
|
||||
void createANNTree();
|
||||
|
||||
void createOcttree();
|
||||
};
|
||||
|
||||
#endif //BASIC_SCAN_H
|
|
@ -0,0 +1,682 @@
|
|||
/*
|
||||
* caliboard implementation
|
||||
*
|
||||
* Copyright (C) Dorit Borrmann
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Dorit Borrmann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#include <cfloat>
|
||||
#include <fstream>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#else
|
||||
#include "XGetopt.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
using std::ofstream;
|
||||
using std::flush;
|
||||
using std::cout;
|
||||
using std::string;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <strings.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "shapes/hough.h"
|
||||
#include "slam6d/basicScan.h"
|
||||
|
||||
#include "shapes/shape.h"
|
||||
#include "shapes/ransac.h"
|
||||
#include "slam6d/icp6D.h"
|
||||
#include "slam6d/icp6Dsvd.h"
|
||||
#include "slam6d/icp6Dquat.h"
|
||||
|
||||
#ifdef WITH_SCANSERVER
|
||||
#include "scanserver/clientInterface.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void usage(char* prog) {
|
||||
#ifndef _MSC_VER
|
||||
const string bold("\033[1m");
|
||||
const string normal("\033[m");
|
||||
#else
|
||||
const string bold("");
|
||||
const string normal("");
|
||||
#endif
|
||||
cout << endl
|
||||
<< bold << "USAGE " << normal << endl
|
||||
<< " " << prog << " [options] directory" << endl << endl;
|
||||
cout << bold << "OPTIONS" << normal << endl
|
||||
<< bold << " -b" << normal << " NR, " << bold << "--bottom=" << normal << "NR" << endl
|
||||
<< " trim the scan with lower boundary NR" << endl
|
||||
<< endl
|
||||
<< bold << " -e" << normal << " NR, " << bold << "--end=" << normal << "NR" << endl
|
||||
<< " end after scan NR" << endl
|
||||
<< endl
|
||||
|
||||
<< bold << " -f" << normal << " F, " << bold << "--format=" << normal << "F" << endl
|
||||
<< " using shared library F for input" << endl
|
||||
<< " (chose F from {uos, uos_map, uos_rgb, uos_frames, uos_map_frames, old, rts, rts_map, ifp, riegl_txt, riegl_rgb, riegl_bin, zahn, ply})" << endl
|
||||
<< endl
|
||||
<< bold << " -m" << normal << " NR, " << bold << "--max=" << normal << "NR" << endl
|
||||
<< " neglegt all data points with a distance larger than NR 'units'" << endl
|
||||
<< endl
|
||||
<< bold << " -M" << normal << " NR, " << bold << "--min=" << normal << "NR" << endl
|
||||
<< " neglegt all data points with a distance smaller than NR 'units'" << endl
|
||||
<< endl
|
||||
<< bold << " -p" << normal << " NR, " << bold << "--pattern=" << normal << "NR" << endl
|
||||
<< " use pattern NR for plane detection" << endl
|
||||
<< " 0: lightbulb pattern" << endl
|
||||
<< " 1: chess pattern on cardboard" << endl
|
||||
<< " 2: chess pattern on wooden board" << endl
|
||||
<< endl
|
||||
<< bold << " -r" << normal << " NR, " << bold << "--reduce=" << normal << "NR" << endl
|
||||
<< " turns on octree based point reduction (voxel size=<NR>)" << endl
|
||||
<< endl
|
||||
<< bold << " -O" << normal << "NR (optional), " << bold << "--octree=" << normal << "NR (optional)" << endl
|
||||
<< " use randomized octree based point reduction (pts per voxel=<NR>)" << endl
|
||||
<< " requires " << bold << "-r" << normal <<" or " << bold << "--reduce" << endl
|
||||
<< endl
|
||||
<< bold << " -s" << normal << " NR, " << bold << "--start=" << normal << "NR" << endl
|
||||
<< " start at scan NR (i.e., neglects the first NR scans)" << endl
|
||||
<< " [ATTENTION: counting naturally starts with 0]" << endl
|
||||
<< endl
|
||||
<< bold << " -t" << normal << " NR, " << bold << "--top=" << normal << "NR" << endl
|
||||
<< " trim the scan with upper boundary NR" << endl
|
||||
<< endl
|
||||
<< endl << endl;
|
||||
|
||||
cout << bold << "EXAMPLES " << normal << endl
|
||||
<< " " << prog << " -m 500 -r 5 dat" << endl
|
||||
<< " " << prog << " --max=5000 -r 10.2 dat" << endl
|
||||
<< " " << prog << " -s 2 -e 10 -r dat" << endl << endl;
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
void writeFalse(string output) {
|
||||
ofstream caliout(output.c_str());
|
||||
|
||||
caliout << "failed" << endl;
|
||||
caliout.close();
|
||||
caliout.clear();
|
||||
}
|
||||
|
||||
bool matchPlaneToBoard(vector<double *> &points, double *alignxf, int pattern, string output) {
|
||||
double rPos[3] = {0.0,0.0,0.0};
|
||||
double rPosTheta[3] = {0.0,0.0,0.0};
|
||||
|
||||
vector<double *> boardpoints;
|
||||
double halfwidth;
|
||||
double halfheight;
|
||||
double w_step = 0.5;
|
||||
double h_step = 0.5;
|
||||
|
||||
switch(pattern) {
|
||||
case 0:
|
||||
halfheight = 28.5;
|
||||
halfwidth = 25.0;
|
||||
break;
|
||||
case 1:
|
||||
halfwidth = 18.3;
|
||||
halfheight = 18.5;
|
||||
w_step = 0.6;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
halfwidth = 19.0;
|
||||
halfheight = 38.0;
|
||||
break;
|
||||
case 4: //Ostia
|
||||
/*
|
||||
halfwidth = 14.85;
|
||||
halfheight = 21;
|
||||
*/
|
||||
halfwidth = 22.5;
|
||||
halfheight = 30.5;
|
||||
break;
|
||||
case 5: // Ostia large
|
||||
halfwidth = 22.5;
|
||||
halfheight = 30.5;
|
||||
break;
|
||||
}
|
||||
|
||||
for(double i = -halfwidth; i <= halfwidth; i+=w_step) {
|
||||
for(double j = -halfheight; j <= halfheight; j+=h_step) {
|
||||
double * p = new double[3];
|
||||
p[0] = i;
|
||||
p[1] = j;
|
||||
p[2] = 0.0;
|
||||
//cout << p[0] << " " << p[1] << " " << p[2] << " 1" << endl;
|
||||
boardpoints.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
int nr_points = boardpoints.size();
|
||||
int nr_points2 = points.size();
|
||||
Scan * plane = new BasicScan(rPos, rPosTheta, points);
|
||||
Scan * board = new BasicScan(rPos, rPosTheta, boardpoints);
|
||||
|
||||
for(int i = 0; i < boardpoints.size(); i++) {
|
||||
delete[] boardpoints[i];
|
||||
}
|
||||
|
||||
plane->setRangeFilter(-1, -1);
|
||||
plane->setReductionParameter(-1, 0);
|
||||
plane->setSearchTreeParameter(simpleKD, false);
|
||||
board->setRangeFilter(-1, -1);
|
||||
board->setReductionParameter(-1, 0);
|
||||
board->setSearchTreeParameter(simpleKD, false);
|
||||
|
||||
board->transform(alignxf, Scan::ICP, 0);
|
||||
|
||||
bool quiet = true;
|
||||
icp6Dminimizer *my_icp6Dminimizer = 0;
|
||||
my_icp6Dminimizer = new icp6D_SVD(quiet);
|
||||
|
||||
icp6D *my_icp = 0;
|
||||
double mdm = 50;
|
||||
int mni = 50;
|
||||
my_icp = new icp6D(my_icp6Dminimizer, mdm, mni, quiet, false, -1, false, 1, 0.00, false, false);
|
||||
my_icp->match(plane, board);
|
||||
delete my_icp;
|
||||
|
||||
mdm = 2;
|
||||
mni = 300;
|
||||
my_icp = new icp6D(my_icp6Dminimizer, mdm, mni, quiet, false, -1, false, 1, 0.00, false, false);
|
||||
my_icp->match(plane, board);
|
||||
delete my_icp;
|
||||
delete my_icp6Dminimizer;
|
||||
|
||||
double sum;
|
||||
double centroid_s[3] = {0.0, 0.0, 0.0};
|
||||
double centroid_t[3] = {0.0, 0.0, 0.0};
|
||||
vector<PtPair> pairs_out;
|
||||
Scan::getPtPairs(&pairs_out, plane, board, 1, 0, 3.0, sum, centroid_s, centroid_t);
|
||||
int nr_matches = pairs_out.size();
|
||||
|
||||
cout << "Result " << nr_matches << " " << nr_points << " " << nr_points2 << endl;
|
||||
const double * pos = board->get_rPos();
|
||||
const double * postheta = board->get_rPosTheta();
|
||||
const double * transMat = board->get_transMat();
|
||||
for(int i = 0; i < 16; i++) {
|
||||
cout << transMat[i] << " ";
|
||||
}
|
||||
|
||||
cout << endl << endl;
|
||||
cout << "Transform new: " << endl;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
cout << pos[i] << " ";
|
||||
}
|
||||
cout << endl;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
cout << deg(postheta[i]) << " ";
|
||||
}
|
||||
cout << endl;
|
||||
cout << "Calipoints Start" << endl;
|
||||
|
||||
ofstream caliout(output.c_str());
|
||||
|
||||
if(nr_matches < nr_points) {
|
||||
caliout << "failed" << endl;
|
||||
} else {
|
||||
caliout << "Calibration" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* write FRAMES
|
||||
*/
|
||||
/*
|
||||
string filename = "tmp.frames";
|
||||
|
||||
ofstream fout(filename.c_str());
|
||||
if (!fout.good()) {
|
||||
cerr << "ERROR: Cannot open file " << filename << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// write into file
|
||||
|
||||
//fout << "frames for scan" << endl;
|
||||
//fout << plane->sout.str() << endl;
|
||||
//fout << "frames for lightbulbs" << endl;
|
||||
fout << board ->sout.str() << endl;
|
||||
fout.close();
|
||||
fout.clear();
|
||||
*/
|
||||
|
||||
/*
|
||||
board->saveFrames();
|
||||
*/
|
||||
/**
|
||||
* end write frames
|
||||
*/
|
||||
|
||||
switch(pattern) {
|
||||
// lightbulb
|
||||
case 0:
|
||||
for(double y = -25; y < 30; y+=10.0) {
|
||||
for(double x = 20; x > -25; x-=10.0) {
|
||||
double * p = new double[3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = 0.0;
|
||||
transform3(transMat, p);
|
||||
//result->push_back(p);
|
||||
caliout << p[0] << " " << p[1] << " " << p[2] << endl;
|
||||
delete[] p;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// chessboard on wooden board pattern top
|
||||
case 2:
|
||||
for(double x = -7.8; x < 10; x+=5.2) {
|
||||
for(double y = 4.1; y < 33.0; y+=5.2) {
|
||||
double * p = new double[3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = 0.0;
|
||||
transform3(transMat, p);
|
||||
caliout << p[0] << " " << p[1] << " " << p[2] << endl;
|
||||
delete[] p;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// chessboard on wooden board pattern bottom
|
||||
case 3:
|
||||
for(double y = -4.1; y > -33.0; y-=5.2) {
|
||||
for(double x = -8.1; x < 10; x+=5.2) {
|
||||
double * p = new double[3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = 0.0;
|
||||
transform3(transMat, p);
|
||||
caliout << p[0] << " " << p[1] << " " << p[2] << endl;
|
||||
delete[] p;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// chessboard on cardboard
|
||||
case 1:
|
||||
for(double x = -12; x < 16; x+=4.0) {
|
||||
for(double y = -12; y < 16; y+=4.0) {
|
||||
double * p = new double[3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = 0.0;
|
||||
transform3(transMat, p);
|
||||
caliout << p[0] << " " << p[1] << " " << p[2] << endl;
|
||||
delete[] p;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Ostia
|
||||
case 4:
|
||||
for(double x = -12; x < 16; x+=8.0) {
|
||||
for(double y = -20; y < 24; y+=8.0) {
|
||||
double * p = new double[3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = 0.0;
|
||||
transform3(transMat, p);
|
||||
caliout << p[0] << " " << p[1] << " " << p[2] << endl;
|
||||
delete[] p;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
//_|_|_|_|_|_|_
|
||||
//4: 1.5*8 = 12
|
||||
//6: 2.5*8 = 20
|
||||
// Universum
|
||||
case 5:
|
||||
for(double y = 20; y > -24; y-=8.0) {
|
||||
for(double x = -12; x < 16; x+=8.0) {
|
||||
double * p = new double[3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = 0.0;
|
||||
transform3(transMat, p);
|
||||
caliout << p[0] << " " << p[1] << " " << p[2] << endl;
|
||||
delete[] p;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
caliout.close();
|
||||
caliout.clear();
|
||||
|
||||
cout << "Calipoints End" << endl;
|
||||
delete board;
|
||||
delete plane;
|
||||
return !(nr_matches < nr_points);
|
||||
}
|
||||
|
||||
int parseArgs(int argc, char **argv, string &dir, double &red, int &start, int
|
||||
&end, int &pattern, int &maxDist, int &minDist, double &top, double &bottom, int
|
||||
&octree, IOType &type, bool &quiet) {
|
||||
|
||||
bool reduced = false;
|
||||
int c;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
/* options descriptor */
|
||||
// 0: no arguments, 1: required argument, 2: optional argument
|
||||
static struct option longopts[] = {
|
||||
{ "format", required_argument, 0, 'f' },
|
||||
{ "max", required_argument, 0, 'm' },
|
||||
{ "min", required_argument, 0, 'M' },
|
||||
{ "start", required_argument, 0, 's' },
|
||||
{ "reduce", required_argument, 0, 'r' },
|
||||
{ "pattern", required_argument, 0, 'p' },
|
||||
{ "quiet", no_argument, 0, 'q' },
|
||||
{ "octree", optional_argument, 0, 'O' },
|
||||
{ "end", required_argument, 0, 'e' },
|
||||
{ "top", required_argument, 0, 't' },
|
||||
{ "bottom", required_argument, 0, 'b' },
|
||||
{ 0, 0, 0, 0} // needed, cf. getopt.h
|
||||
};
|
||||
|
||||
cout << endl;
|
||||
while ((c = getopt_long(argc, argv, "f:r:s:e:m:M:O:qp:e:t:b:", longopts, NULL)) != -1)
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
red = atof(optarg);
|
||||
reduced = true;
|
||||
break;
|
||||
case 's':
|
||||
start = atoi(optarg);
|
||||
if (start < 0) { cerr << "Error: Cannot start at a negative scan number.\n"; exit(1); }
|
||||
break;
|
||||
case 'e':
|
||||
end = atoi(optarg);
|
||||
if (end < 0) { cerr << "Error: Cannot end at a negative scan number.\n"; exit(1); }
|
||||
if (end < start) { cerr << "Error: <end> cannot be smaller than <start>.\n"; exit(1); }
|
||||
break;
|
||||
case 'f':
|
||||
try {
|
||||
type = formatname_to_io_type(optarg);
|
||||
} catch (...) { // runtime_error
|
||||
cerr << "Format " << optarg << " unknown." << endl;
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
pattern = atoi(optarg);
|
||||
if(pattern < 0 || pattern > 5) { cerr << "Error: choose pattern between 0 and 3!\n"; exit(1); }
|
||||
break;
|
||||
case 'q':
|
||||
quiet = true;
|
||||
break;
|
||||
case 'm':
|
||||
maxDist = atoi(optarg);
|
||||
break;
|
||||
case 'O':
|
||||
if (optarg) {
|
||||
octree = atoi(optarg);
|
||||
} else {
|
||||
octree = 1;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
top = atof(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
bottom = atof(optarg);
|
||||
break;
|
||||
case 'M':
|
||||
minDist = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
default:
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (optind != argc-1) {
|
||||
cerr << "\n*** Directory missing ***" << endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
dir = argv[optind];
|
||||
|
||||
#ifndef _MSC_VER
|
||||
if (dir[dir.length()-1] != '/') dir = dir + "/";
|
||||
#else
|
||||
if (dir[dir.length()-1] != '\\') dir = dir + "\\";
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function. The Hough Transform is called for the scan indicated as
|
||||
* argument.
|
||||
*
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
cout << "(c) Jacobs University Bremen, gGmbH, 2010" << endl << endl;
|
||||
|
||||
if (argc <= 1) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
// parsing the command line parameters
|
||||
// init, default values if not specified
|
||||
string dir;
|
||||
double red = -1.0;
|
||||
int start = 0;
|
||||
int end = -1;
|
||||
int maxDist = -1;
|
||||
int minDist = -1;
|
||||
int octree = 0;
|
||||
bool quiet = false;
|
||||
int pattern = 0;
|
||||
double bottom = -5;
|
||||
double top = 170;
|
||||
IOType type = UOS;
|
||||
|
||||
cout << "Parse args" << endl;
|
||||
parseArgs(argc, argv, dir, red, start, end, pattern, maxDist, minDist, top, bottom, octree, type, quiet);
|
||||
int fileNr = start;
|
||||
string calidir = dir + "/cali";
|
||||
|
||||
#ifdef WITH_SCANSERVER
|
||||
try {
|
||||
ClientInterface::create();
|
||||
} catch(std::runtime_error& e) {
|
||||
cerr << "ClientInterface could not be created: " << e.what() << endl;
|
||||
cerr << "Start the scanserver first." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
#endif //WITH_SCANSERVER
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int success = mkdir(calidir.c_str());
|
||||
#else
|
||||
int success = mkdir(calidir.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
#endif
|
||||
if(success == 0) {
|
||||
if(!quiet) {
|
||||
cout << "Writing calibration results to " << calidir << endl;
|
||||
}
|
||||
} else if(errno == EEXIST) {
|
||||
cout << "Directory " << calidir << " exists already. CONTINUE" << endl;
|
||||
} else {
|
||||
cerr << "Creating directory " << calidir << " failed" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cout << start << " " << end << endl;
|
||||
int successes = 0;
|
||||
int failures = 0;
|
||||
|
||||
long calitime = GetCurrentTimeInMilliSec();
|
||||
|
||||
//#ifndef WITH_SCANSERVER
|
||||
while (fileNr <= end) {
|
||||
Scan::openDirectory(false, dir, type, fileNr, fileNr);
|
||||
Scan::allScans[0]->setRangeFilter(maxDist, minDist);
|
||||
Scan::allScans[0]->setHeightFilter(top, bottom);
|
||||
Scan::allScans[0]->setSearchTreeParameter(simpleKD, false);
|
||||
|
||||
string output = calidir + "/scan" + to_string(fileNr,3) + ".3d";
|
||||
cout << "Top: " << top << " Bottom: " << bottom << endl;
|
||||
|
||||
Scan::allScans[0]->toGlobal();
|
||||
double id[16];
|
||||
M4identity(id);
|
||||
for(int i = 0; i < 10; i++) {
|
||||
Scan::allScans[0]->transform(id, Scan::ICP, 0); // write end pose
|
||||
}
|
||||
/*
|
||||
#else //WITH_SCANSERVER
|
||||
|
||||
Scan::readScansRedSearch(type, start, end, dir, filter, red, octree);
|
||||
for(std::vector<Scan*>::iterator it = Scan::allScans.begin(); it != Scan::allScans.end(); ++it)
|
||||
{
|
||||
Scan* scan = *it;
|
||||
string output = calidir + "/scan" + scan->getIdentifier() + ".3d";
|
||||
cout << "Top: " << top << " Bottom: " << bottom << endl;
|
||||
// set trimming, don't want to put it into readScansRedSearch too
|
||||
scan->trim(top, bottom);
|
||||
|
||||
double id[16];
|
||||
M4identity(id);
|
||||
for(int i = 0; i < 10; i++) {
|
||||
scan->transform(id, Scan::ICP, 0); // write end pose
|
||||
}
|
||||
#endif //WITH_SCANSERVER
|
||||
*/
|
||||
cout << "start plane detection" << endl;
|
||||
long starttime = GetCurrentTimeInMilliSec();
|
||||
vector<double *> points;
|
||||
CollisionPlane<double> * plane;
|
||||
plane = new LightBulbPlane<double>(50,120);
|
||||
//#ifndef WITH_SCANSERVER
|
||||
Ransac(*plane, Scan::allScans[0], &points);
|
||||
/*
|
||||
#else //WITH_SCANSERVER
|
||||
|
||||
cout << "S" << endl;
|
||||
Ransac(*plane, scan, &points);
|
||||
cout << "T" << endl;
|
||||
//#endif //WITH_SCANSERVER
|
||||
*/
|
||||
starttime = (GetCurrentTimeInMilliSec() - starttime);
|
||||
|
||||
cout << "nr points " << points.size() << endl;
|
||||
double nx,ny,nz,d;
|
||||
plane->getPlane(nx,ny,nz,d);
|
||||
cout << "DONE " << endl;
|
||||
|
||||
cout << nx << " " << ny << " " << nz << " " << d << endl;
|
||||
|
||||
if(std::isnan(d)) {
|
||||
writeFalse(output);
|
||||
failures++;
|
||||
} else {
|
||||
|
||||
if(d < 0) {
|
||||
nx = -nx;
|
||||
ny = -ny;
|
||||
nz = -nz;
|
||||
d = -d;
|
||||
}
|
||||
|
||||
double tx, ty, tz;
|
||||
tz = 0;
|
||||
ty = asin(nx);
|
||||
tx = asin(-ny/cos(ty));
|
||||
|
||||
double rPos[3];
|
||||
double rPosTheta[3];
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
rPosTheta[i] = 0.0;
|
||||
}
|
||||
|
||||
rPosTheta[0] = tx;
|
||||
rPosTheta[1] = ty;
|
||||
rPosTheta[2] = tz;
|
||||
|
||||
//rPosTheta[1] = acos(nz);
|
||||
// rotate plane model to make parallel with detected plane
|
||||
|
||||
// transform plane model to center of detected plane
|
||||
((LightBulbPlane<double> *)plane)->getCenter(rPos[0], rPos[1], rPos[2]);
|
||||
cout << "Angle: " << deg(acos(nz)) << endl;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
cout << rPos[i] << " ";
|
||||
}
|
||||
for(int i = 0; i < 3; i++) {
|
||||
cout << deg(rPosTheta[i]) << " ";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
double alignxf[16];
|
||||
EulerToMatrix4(rPos, rPosTheta, alignxf);
|
||||
if(matchPlaneToBoard(points, alignxf, pattern, output)) {
|
||||
successes++;
|
||||
} else {
|
||||
failures++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
for(int i = points.size() - 1; i > -1; i--) {
|
||||
delete[] points[i];
|
||||
}
|
||||
|
||||
|
||||
delete plane;
|
||||
|
||||
cout << "Time for Plane Detection " << starttime << endl;
|
||||
//#ifndef WITH_SCANSERVER
|
||||
delete Scan::allScans[0];
|
||||
Scan::allScans.clear();
|
||||
fileNr++;
|
||||
//#endif //WITH_SCANSERVER
|
||||
}
|
||||
calitime = (GetCurrentTimeInMilliSec() - calitime);
|
||||
|
||||
cout << "Calibration done with " << successes << " successes and " << failures
|
||||
<< " failures!" << endl;
|
||||
cout << "Time for Calibration " << calitime << endl;
|
||||
|
||||
/*
|
||||
#ifdef WITH_SCANSERVER
|
||||
Scan::clearScans();
|
||||
ClientInterface::destroy();
|
||||
#endif //WITH_SCANSERVER
|
||||
*/
|
||||
}
|
||||
|
|
@ -0,0 +1,847 @@
|
|||
/*
|
||||
* viewcull implementation
|
||||
*
|
||||
* Copyright (C) Jan Elseberg
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Frustrum culling routines
|
||||
*
|
||||
* @author Jan Elseberg. Automation Group, Jacobs University Bremen gGmbH, Germany.
|
||||
*/
|
||||
#include "show/viewcull.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <GLUT/glut.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#include "slam6d/globals.icc"
|
||||
namespace show{
|
||||
|
||||
/** The 6 planes of the viewing frustum */
|
||||
float frustum[6][4];
|
||||
|
||||
/** the modelview * projection matrix to map a model point to an onscreen coordinate */
|
||||
float matrix[16];
|
||||
/** some useful variables for faster calculation of the pixel coordinates */
|
||||
short VP[4];
|
||||
/** a unit vector pointing to the right of the screen */
|
||||
float right[3];
|
||||
/** how much detail is shown, 0 means everything is plotted */
|
||||
short DETAIL;
|
||||
|
||||
double SX, SY, SZ, EX, EY, EZ;
|
||||
float origin[3], dir[3]; /*ray */
|
||||
float dist;
|
||||
int rayX,rayY;
|
||||
float rayVP[4];
|
||||
|
||||
void calcRay(int x, int y, double znear, double zfar) {
|
||||
|
||||
GLdouble modelMatrix[16];
|
||||
GLdouble projMatrix[16];
|
||||
int viewport[4];
|
||||
glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
|
||||
glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
|
||||
glGetIntegerv(GL_VIEWPORT,viewport);
|
||||
|
||||
gluUnProject(x, viewport[3]-y, zfar, modelMatrix, projMatrix, viewport, &SX, &SY, &SZ);
|
||||
gluUnProject(x, viewport[3]-y, znear, modelMatrix, projMatrix, viewport, &EX, &EY, &EZ);
|
||||
|
||||
origin[0] = SX;
|
||||
origin[1] = SY;
|
||||
origin[2] = SZ;
|
||||
dir[0] = EX-SX;
|
||||
dir[1] = EY-SY;
|
||||
dir[2] = EZ-SZ;
|
||||
double t = sqrt( dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2] );
|
||||
dir[0] /= t;
|
||||
dir[1] /= t;
|
||||
dir[2] /= t;
|
||||
|
||||
dist = SX * dir[0] + SY * dir[1] + SZ * dir[2];
|
||||
rayVP[0] = 0.5*viewport[2];
|
||||
rayVP[1] = 0.5*viewport[2] + viewport[0];
|
||||
|
||||
rayVP[2] = 0.5*viewport[3];
|
||||
rayVP[3] = 0.5*viewport[3] + viewport[1];
|
||||
rayX = x;
|
||||
rayY = viewport[3]-y;
|
||||
|
||||
remViewport();
|
||||
}
|
||||
|
||||
void remViewport() {
|
||||
GLdouble modelMatrix[16];
|
||||
GLdouble projMatrix[16];
|
||||
int viewport[4];
|
||||
glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
|
||||
glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
|
||||
glGetIntegerv(GL_VIEWPORT,viewport);
|
||||
|
||||
MMult( projMatrix, modelMatrix, matrix );
|
||||
VP[0] = 0.5*viewport[2];
|
||||
VP[1] = 0.5*viewport[2] + viewport[0];
|
||||
|
||||
VP[2] = 0.5*viewport[3];
|
||||
VP[3] = 0.5*viewport[3] + viewport[1];
|
||||
|
||||
right[0] = modelMatrix[0];
|
||||
right[1] = modelMatrix[4];
|
||||
right[2] = modelMatrix[8];
|
||||
}
|
||||
|
||||
void ExtractFrustum(short detail)
|
||||
{
|
||||
DETAIL = detail + 1;
|
||||
remViewport();
|
||||
|
||||
float proj[16];
|
||||
float modl[16];
|
||||
float clip[16];
|
||||
float t;
|
||||
|
||||
/* Get the current PROJECTION matrix from OpenGL */
|
||||
glGetFloatv( GL_PROJECTION_MATRIX, proj );
|
||||
|
||||
/* Get the current MODELVIEW matrix from OpenGL */
|
||||
glGetFloatv( GL_MODELVIEW_MATRIX, modl );
|
||||
|
||||
/* Combine the two matrices (multiply projection by modelview) */
|
||||
clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
|
||||
clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
|
||||
clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
|
||||
clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
|
||||
|
||||
clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
|
||||
clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
|
||||
clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
|
||||
clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
|
||||
|
||||
clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
|
||||
clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
|
||||
clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
|
||||
clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
|
||||
|
||||
clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
|
||||
clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
|
||||
clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
|
||||
clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
|
||||
|
||||
/* Extract the numbers for the RIGHT plane */
|
||||
frustum[0][0] = clip[ 3] - clip[ 0];
|
||||
frustum[0][1] = clip[ 7] - clip[ 4];
|
||||
frustum[0][2] = clip[11] - clip[ 8];
|
||||
frustum[0][3] = clip[15] - clip[12];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frustum[0][0] * frustum[0][0] + frustum[0][1] * frustum[0][1] + frustum[0][2] * frustum[0][2] );
|
||||
frustum[0][0] /= t;
|
||||
frustum[0][1] /= t;
|
||||
frustum[0][2] /= t;
|
||||
frustum[0][3] /= t;
|
||||
|
||||
/* Extract the numbers for the LEFT plane */
|
||||
frustum[1][0] = clip[ 3] + clip[ 0];
|
||||
frustum[1][1] = clip[ 7] + clip[ 4];
|
||||
frustum[1][2] = clip[11] + clip[ 8];
|
||||
frustum[1][3] = clip[15] + clip[12];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frustum[1][0] * frustum[1][0] + frustum[1][1] * frustum[1][1] + frustum[1][2] * frustum[1][2] );
|
||||
frustum[1][0] /= t;
|
||||
frustum[1][1] /= t;
|
||||
frustum[1][2] /= t;
|
||||
frustum[1][3] /= t;
|
||||
|
||||
/* Extract the BOTTOM plane */
|
||||
frustum[2][0] = clip[ 3] + clip[ 1];
|
||||
frustum[2][1] = clip[ 7] + clip[ 5];
|
||||
frustum[2][2] = clip[11] + clip[ 9];
|
||||
frustum[2][3] = clip[15] + clip[13];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frustum[2][0] * frustum[2][0] + frustum[2][1] * frustum[2][1] + frustum[2][2] * frustum[2][2] );
|
||||
frustum[2][0] /= t;
|
||||
frustum[2][1] /= t;
|
||||
frustum[2][2] /= t;
|
||||
frustum[2][3] /= t;
|
||||
|
||||
/* Extract the TOP plane */
|
||||
frustum[3][0] = clip[ 3] - clip[ 1];
|
||||
frustum[3][1] = clip[ 7] - clip[ 5];
|
||||
frustum[3][2] = clip[11] - clip[ 9];
|
||||
frustum[3][3] = clip[15] - clip[13];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frustum[3][0] * frustum[3][0] + frustum[3][1] * frustum[3][1] + frustum[3][2] * frustum[3][2] );
|
||||
frustum[3][0] /= t;
|
||||
frustum[3][1] /= t;
|
||||
frustum[3][2] /= t;
|
||||
frustum[3][3] /= t;
|
||||
|
||||
/* Extract the FAR plane */
|
||||
frustum[4][0] = clip[ 3] - clip[ 2];
|
||||
frustum[4][1] = clip[ 7] - clip[ 6];
|
||||
frustum[4][2] = clip[11] - clip[10];
|
||||
frustum[4][3] = clip[15] - clip[14];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frustum[4][0] * frustum[4][0] + frustum[4][1] * frustum[4][1] + frustum[4][2] * frustum[4][2] );
|
||||
frustum[4][0] /= t;
|
||||
frustum[4][1] /= t;
|
||||
frustum[4][2] /= t;
|
||||
frustum[4][3] /= t;
|
||||
|
||||
/* Extract the NEAR plane */
|
||||
frustum[5][0] = clip[ 3] + clip[ 2];
|
||||
frustum[5][1] = clip[ 7] + clip[ 6];
|
||||
frustum[5][2] = clip[11] + clip[10];
|
||||
frustum[5][3] = clip[15] + clip[14];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frustum[5][0] * frustum[5][0] + frustum[5][1] * frustum[5][1] + frustum[5][2] * frustum[5][2] );
|
||||
frustum[5][0] /= t;
|
||||
frustum[5][1] /= t;
|
||||
frustum[5][2] /= t;
|
||||
frustum[5][3] /= t;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ExtractFrustum(float *frust[6])
|
||||
{
|
||||
remViewport();
|
||||
|
||||
float proj[16];
|
||||
float modl[16];
|
||||
float clip[16];
|
||||
float t;
|
||||
|
||||
/* Get the current PROJECTION matrix from OpenGL */
|
||||
glGetFloatv( GL_PROJECTION_MATRIX, proj );
|
||||
|
||||
/* Get the current MODELVIEW matrix from OpenGL */
|
||||
glGetFloatv( GL_MODELVIEW_MATRIX, modl );
|
||||
|
||||
/* Combine the two matrices (multiply projection by modelview) */
|
||||
clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
|
||||
clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
|
||||
clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
|
||||
clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
|
||||
|
||||
clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
|
||||
clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
|
||||
clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
|
||||
clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
|
||||
|
||||
clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
|
||||
clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
|
||||
clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
|
||||
clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
|
||||
|
||||
clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
|
||||
clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
|
||||
clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
|
||||
clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
|
||||
|
||||
/* Extract the numbers for the RIGHT plane */
|
||||
frust[0][0] = clip[ 3] - clip[ 0];
|
||||
frust[0][1] = clip[ 7] - clip[ 4];
|
||||
frust[0][2] = clip[11] - clip[ 8];
|
||||
frust[0][3] = clip[15] - clip[12];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frust[0][0] * frust[0][0] + frust[0][1] * frust[0][1] + frust[0][2] * frust[0][2] );
|
||||
frust[0][0] /= t;
|
||||
frust[0][1] /= t;
|
||||
frust[0][2] /= t;
|
||||
frust[0][3] /= t;
|
||||
|
||||
/* Extract the numbers for the LEFT plane */
|
||||
frust[1][0] = clip[ 3] + clip[ 0];
|
||||
frust[1][1] = clip[ 7] + clip[ 4];
|
||||
frust[1][2] = clip[11] + clip[ 8];
|
||||
frust[1][3] = clip[15] + clip[12];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frust[1][0] * frust[1][0] + frust[1][1] * frust[1][1] + frust[1][2] * frust[1][2] );
|
||||
frust[1][0] /= t;
|
||||
frust[1][1] /= t;
|
||||
frust[1][2] /= t;
|
||||
frust[1][3] /= t;
|
||||
|
||||
/* Extract the BOTTOM plane */
|
||||
frust[2][0] = clip[ 3] + clip[ 1];
|
||||
frust[2][1] = clip[ 7] + clip[ 5];
|
||||
frust[2][2] = clip[11] + clip[ 9];
|
||||
frust[2][3] = clip[15] + clip[13];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frust[2][0] * frust[2][0] + frust[2][1] * frust[2][1] + frust[2][2] * frust[2][2] );
|
||||
frust[2][0] /= t;
|
||||
frust[2][1] /= t;
|
||||
frust[2][2] /= t;
|
||||
frust[2][3] /= t;
|
||||
|
||||
/* Extract the TOP plane */
|
||||
frust[3][0] = clip[ 3] - clip[ 1];
|
||||
frust[3][1] = clip[ 7] - clip[ 5];
|
||||
frust[3][2] = clip[11] - clip[ 9];
|
||||
frust[3][3] = clip[15] - clip[13];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frust[3][0] * frust[3][0] + frust[3][1] * frust[3][1] + frust[3][2] * frust[3][2] );
|
||||
frust[3][0] /= t;
|
||||
frust[3][1] /= t;
|
||||
frust[3][2] /= t;
|
||||
frust[3][3] /= t;
|
||||
|
||||
/* Extract the FAR plane */
|
||||
frust[4][0] = clip[ 3] - clip[ 2];
|
||||
frust[4][1] = clip[ 7] - clip[ 6];
|
||||
frust[4][2] = clip[11] - clip[10];
|
||||
frust[4][3] = clip[15] - clip[14];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frust[4][0] * frust[4][0] + frust[4][1] * frust[4][1] + frust[4][2] * frust[4][2] );
|
||||
frust[4][0] /= t;
|
||||
frust[4][1] /= t;
|
||||
frust[4][2] /= t;
|
||||
frust[4][3] /= t;
|
||||
|
||||
/* Extract the NEAR plane */
|
||||
frust[5][0] = clip[ 3] + clip[ 2];
|
||||
frust[5][1] = clip[ 7] + clip[ 6];
|
||||
frust[5][2] = clip[11] + clip[10];
|
||||
frust[5][3] = clip[15] + clip[14];
|
||||
|
||||
/* Normalize the result */
|
||||
t = sqrt( frust[5][0] * frust[5][0] + frust[5][1] * frust[5][1] + frust[5][2] * frust[5][2] );
|
||||
frust[5][0] /= t;
|
||||
frust[5][1] /= t;
|
||||
frust[5][2] /= t;
|
||||
frust[5][3] /= t;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void myProject(float x, float y, float z, short &Xi ) {
|
||||
float pn[2];
|
||||
// x coordinate on screen, not normalized
|
||||
pn[0] = x * matrix[0] + y * matrix[4] + z * matrix[8] + matrix[12];
|
||||
// normalization
|
||||
pn[1] = x * matrix[3] + y * matrix[7] + z * matrix[11] + matrix[15];
|
||||
|
||||
// normalized x coordinate on screen
|
||||
pn[0] /= pn[1];
|
||||
|
||||
// true x coordinate in viewport coordinate system
|
||||
Xi = pn[0]*VP[0] + VP[1];
|
||||
}
|
||||
|
||||
int LOD2(float x, float y, float z, float size)
|
||||
{
|
||||
size = sqrt(3*size*size);
|
||||
|
||||
short X1;
|
||||
short X2;
|
||||
|
||||
// onscreen position of the leftmost point
|
||||
myProject(x - size*right[0], y - size*right[1], z - size*right[2], X1);
|
||||
// onscreen position of the rightmost point
|
||||
myProject(x + size*right[0], y + size*right[1], z + size*right[2], X2);
|
||||
|
||||
if (X1 > X2) {
|
||||
return (X1-X2);
|
||||
} else {
|
||||
return (X2-X1);
|
||||
}
|
||||
}
|
||||
|
||||
bool LOD(float x, float y, float z, float size)
|
||||
{
|
||||
size = sqrt(3*size*size);
|
||||
|
||||
short X1;
|
||||
short X2;
|
||||
|
||||
// onscreen position of the leftmost point
|
||||
myProject(x - size*right[0], y - size*right[1], z - size*right[2], X1);
|
||||
// onscreen position of the rightmost point
|
||||
myProject(x + size*right[0], y + size*right[1], z + size*right[2], X2);
|
||||
|
||||
if (X1 > X2) {
|
||||
return (X1-X2) > DETAIL;
|
||||
} else {
|
||||
return (X2-X1) > DETAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 0 if not in frustrum
|
||||
* 1 if partial overlap
|
||||
* 2 if entirely within frustrum
|
||||
*/
|
||||
int CubeInFrustum2( float x, float y, float z, float size )
|
||||
{
|
||||
int p;
|
||||
|
||||
float xm, xp, ym, yp, zm, zp;
|
||||
float Fxm, Fxp, Fym, Fyp, Fzm, Fzp;
|
||||
xm = x - size;
|
||||
xp = x + size;
|
||||
ym = y - size;
|
||||
yp = y + size;
|
||||
zm = z - size;
|
||||
zp = z + size;
|
||||
|
||||
for( p = 0; p < 6; p++ )
|
||||
{
|
||||
Fxm = frustum[p][0] * xm;
|
||||
Fym = frustum[p][1] * ym;
|
||||
Fzm = frustum[p][2] * zm;
|
||||
if( Fxm + Fym + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
Fxp = frustum[p][0] * xp;
|
||||
if( Fxp + Fym + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
Fyp = frustum[p][1] * yp;
|
||||
if( Fxm + Fyp + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
if( Fxp + Fyp + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
Fzp = frustum[p][2] * zp;
|
||||
if( Fxm + Fym + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
if( Fxp + Fym + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( Fxm + Fyp + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( Fxp + Fyp + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// box is in frustrum, now check wether all corners are within.
|
||||
// If one is outside return 1 otherwise 2
|
||||
for( p = 0; p < 6; p++ )
|
||||
{
|
||||
Fxm = frustum[p][0] * xm;
|
||||
Fym = frustum[p][1] * ym;
|
||||
Fzm = frustum[p][2] * zm;
|
||||
if( Fxm + Fym + Fzm + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
|
||||
Fxp = frustum[p][0] * xp;
|
||||
if( Fxp + Fym + Fzm + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
|
||||
Fyp = frustum[p][1] * yp;
|
||||
if( Fxm + Fyp + Fzm + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
|
||||
if( Fxp + Fyp + Fzm + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
|
||||
Fzp = frustum[p][2] * zp;
|
||||
if( Fxm + Fym + Fzp + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
|
||||
if( Fxp + Fym + Fzp + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( Fxm + Fyp + Fzp + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( Fxp + Fyp + Fzp + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
char PlaneAABB( float x, float y, float z, float size, float *plane )
|
||||
{
|
||||
float dist = plane[3];
|
||||
|
||||
float xm, xp, ym, yp, zm, zp;
|
||||
float Fxm, Fxp, Fym, Fyp, Fzm, Fzp;
|
||||
|
||||
float dmmm, dpmm, dmpm, dppm, dmmp, dpmp, dmpp, dppp;
|
||||
xm = x - size;
|
||||
xp = x + size;
|
||||
ym = y - size;
|
||||
yp = y + size;
|
||||
zm = z - size;
|
||||
zp = z + size;
|
||||
|
||||
{
|
||||
Fxm = plane[0] * xm;
|
||||
Fym = plane[1] * ym;
|
||||
Fzm = plane[2] * zm;
|
||||
dmmm = Fxm + Fym + Fzm + dist;
|
||||
if( dmmm > 0 )
|
||||
goto intersects;
|
||||
|
||||
Fxp = plane[0] * xp;
|
||||
dpmm = Fxp + Fym + Fzm + dist;
|
||||
if( dpmm > 0 )
|
||||
goto intersects;
|
||||
|
||||
Fyp = plane[1] * yp;
|
||||
dmpm = Fxm + Fyp + Fzm + dist;
|
||||
if( dmpm > 0 )
|
||||
goto intersects;
|
||||
|
||||
dppm = Fxp + Fyp + Fzm + dist;
|
||||
if( dppm > 0 )
|
||||
goto intersects;
|
||||
|
||||
Fzp = plane[2] * zp;
|
||||
dmmp = Fxm + Fym + Fzp + dist;
|
||||
if( dmmp > 0 )
|
||||
goto intersects;
|
||||
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp > 0 )
|
||||
goto intersects;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp > 0 )
|
||||
goto intersects;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp > 0 )
|
||||
goto intersects;
|
||||
return 0; // outside
|
||||
}
|
||||
|
||||
intersects:
|
||||
|
||||
// cube is inside, determine if plane intersects the cube
|
||||
{
|
||||
if( dmmm < 0 )
|
||||
return 1;
|
||||
Fxp = plane[0] * xp;
|
||||
dpmm = Fxp + Fym + Fzm + dist;
|
||||
if( dpmm < 0 )
|
||||
return 1;
|
||||
Fyp = plane[1] * yp;
|
||||
dmpm = Fxm + Fyp + Fzm + dist;
|
||||
if( dmpm < 0 )
|
||||
return 1;
|
||||
dppm = Fxp + Fyp + Fzm + dist;
|
||||
if( dppm < 0 )
|
||||
return 1;
|
||||
Fzp = plane[2] * zp;
|
||||
dmmp = Fxm + Fym + Fzp + dist;
|
||||
if( dmmp < 0 )
|
||||
return 1;
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp < 0 )
|
||||
return 1;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
}
|
||||
|
||||
// plane is outside
|
||||
return 2;
|
||||
|
||||
}
|
||||
*/
|
||||
char PlaneAABB( float x, float y, float z, float size, float *plane )
|
||||
{
|
||||
float dist = plane[3];
|
||||
|
||||
float xm, xp, ym, yp, zm, zp;
|
||||
float Fxm, Fxp, Fym, Fyp, Fzm, Fzp;
|
||||
|
||||
float dmmm, dpmm, dmpm, dppm, dmmp, dpmp, dmpp, dppp;
|
||||
xm = x - size;
|
||||
xp = x + size;
|
||||
ym = y - size;
|
||||
yp = y + size;
|
||||
zm = z - size;
|
||||
zp = z + size;
|
||||
|
||||
Fxm = plane[0] * xm;
|
||||
Fym = plane[1] * ym;
|
||||
Fzm = plane[2] * zm;
|
||||
dmmm = Fxm + Fym + Fzm + dist;
|
||||
if( dmmm > 0 )
|
||||
{
|
||||
Fxp = plane[0] * xp;
|
||||
dpmm = Fxp + Fym + Fzm + dist;
|
||||
if( dpmm < 0 )
|
||||
return 1;
|
||||
Fyp = plane[1] * yp;
|
||||
dmpm = Fxm + Fyp + Fzm + dist;
|
||||
if( dmpm < 0 )
|
||||
return 1;
|
||||
dppm = Fxp + Fyp + Fzm + dist;
|
||||
if( dppm < 0 )
|
||||
return 1;
|
||||
Fzp = plane[2] * zp;
|
||||
dmmp = Fxm + Fym + Fzp + dist;
|
||||
if( dmmp < 0 )
|
||||
return 1;
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp < 0 )
|
||||
return 1;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
Fxp = plane[0] * xp;
|
||||
dpmm = Fxp + Fym + Fzm + dist;
|
||||
if( dpmm > 0 )
|
||||
{
|
||||
if( dmmm < 0 )
|
||||
return 1;
|
||||
Fyp = plane[1] * yp;
|
||||
dmpm = Fxm + Fyp + Fzm + dist;
|
||||
if( dmpm < 0 )
|
||||
return 1;
|
||||
dppm = Fxp + Fyp + Fzm + dist;
|
||||
if( dppm < 0 )
|
||||
return 1;
|
||||
Fzp = plane[2] * zp;
|
||||
dmmp = Fxm + Fym + Fzp + dist;
|
||||
if( dmmp < 0 )
|
||||
return 1;
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp < 0 )
|
||||
return 1;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
Fyp = plane[1] * yp;
|
||||
dmpm = Fxm + Fyp + Fzm + dist;
|
||||
if( dmpm > 0 )
|
||||
{
|
||||
if( dmmm < 0 || dpmm < 0 )
|
||||
return 1;
|
||||
dppm = Fxp + Fyp + Fzm + dist;
|
||||
if( dppm < 0 )
|
||||
return 1;
|
||||
Fzp = plane[2] * zp;
|
||||
dmmp = Fxm + Fym + Fzp + dist;
|
||||
if( dmmp < 0 )
|
||||
return 1;
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp < 0 )
|
||||
return 1;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
dppm = Fxp + Fyp + Fzm + dist;
|
||||
if( dppm > 0 )
|
||||
{
|
||||
if( dmmm < 0 || dpmm < 0 || dmpm < 0 )
|
||||
return 1;
|
||||
Fzp = plane[2] * zp;
|
||||
dmmp = Fxm + Fym + Fzp + dist;
|
||||
if( dmmp < 0 )
|
||||
return 1;
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp < 0 )
|
||||
return 1;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
Fzp = plane[2] * zp;
|
||||
dmmp = Fxm + Fym + Fzp + dist;
|
||||
if( dmmp > 0 )
|
||||
{
|
||||
if( dmmm < 0 || dpmm < 0 || dmpm < 0 || dppm < 0 )
|
||||
return 1;
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp < 0 )
|
||||
return 1;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
dpmp = Fxp + Fym + Fzp + dist;
|
||||
if( dpmp > 0 )
|
||||
{
|
||||
if( dmmm < 0 || dpmm < 0 || dmpm < 0 || dppm < 0 || dmmp < 0 )
|
||||
return 1;
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
dmpp = Fxm + Fyp + Fzp + dist;
|
||||
if( dmpp > 0 )
|
||||
{
|
||||
if( dmmm < 0 || dpmm < 0 || dmpm < 0 || dppm < 0 || dmmp < 0 || dpmp < 0 )
|
||||
return 1;
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp < 0 )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
dppp = Fxp + Fyp + Fzp + dist;
|
||||
if( dppp > 0 )
|
||||
{
|
||||
if( dmmm < 0 || dpmm < 0 || dmpm < 0 || dppm < 0 || dmmp < 0 || dpmp < 0 || dmpp < 0)
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
return 0; // outside
|
||||
}
|
||||
|
||||
int QuadInFrustrum2old( float x, float y, float z, float size )
|
||||
{
|
||||
int p;
|
||||
|
||||
for( p = 0; p < 6; p++ )
|
||||
{
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] > 0 )
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// box is in frustrum, now check wether all corners are within. If one is outside return 1 otherwise 2
|
||||
for( p = 0; p < 6; p++ )
|
||||
{
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z - size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z - size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y - size) + frustum[p][2] * (z + size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( frustum[p][0] * (x - size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
if( frustum[p][0] * (x + size) + frustum[p][1] * (y + size) + frustum[p][2] * (z + size) + frustum[p][3] < 0 )
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
|
||||
}
|
||||
|
||||
bool CubeInFrustum( float x, float y, float z, float size )
|
||||
{
|
||||
int p;
|
||||
|
||||
float xm, xp, ym, yp, zm, zp;
|
||||
float Fxm, Fxp, Fym, Fyp, Fzm, Fzp;
|
||||
xm = x - size;
|
||||
xp = x + size;
|
||||
ym = y - size;
|
||||
yp = y + size;
|
||||
zm = z - size;
|
||||
zp = z + size;
|
||||
|
||||
for( p = 0; p < 6; p++ )
|
||||
{
|
||||
Fxm = frustum[p][0] * xm;
|
||||
Fym = frustum[p][1] * ym;
|
||||
Fzm = frustum[p][2] * zm;
|
||||
if( Fxm + Fym + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
Fxp = frustum[p][0] * xp;
|
||||
if( Fxp + Fym + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
Fyp = frustum[p][1] * yp;
|
||||
if( Fxm + Fyp + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
if( Fxp + Fyp + Fzm + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
Fzp = frustum[p][2] * zp;
|
||||
if( Fxm + Fym + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
|
||||
if( Fxp + Fym + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( Fxm + Fyp + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
if( Fxp + Fyp + Fzp + frustum[p][3] > 0 )
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
float minB[NUMDIM], maxB[NUMDIM]; /*box */
|
||||
float coord[NUMDIM]; /* hit point */
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
/** @file
|
||||
* @brief Representation of the optimized k-d tree.
|
||||
* @author Remus Dumitru. Jacobs University Bremen, Germany
|
||||
* @author Corneliu-Claudiu Prodescu. Jacobs University Bremen, Germany
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Thomas Escher. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#ifndef __KD_TREE_IMPL_H__
|
||||
#define __KD_TREE_IMPL_H__
|
||||
|
||||
#include "slam6d/kdparams.h"
|
||||
#include "globals.icc"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if !defined _OPENMP && defined OPENMP
|
||||
#define _OPENMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The optimized k-d tree.
|
||||
*
|
||||
* A kD tree for points, with limited
|
||||
* capabilities (find nearest point to
|
||||
* a given point, or to a ray).
|
||||
**/
|
||||
template<class PointData, class AccessorData, class AccessorFunc>
|
||||
class KDTreeImpl {
|
||||
public:
|
||||
inline KDTreeImpl() { }
|
||||
|
||||
virtual inline ~KDTreeImpl() {
|
||||
if (!npts) {
|
||||
#ifdef WITH_OPENMP_KD
|
||||
omp_set_num_threads(OPENMP_NUM_THREADS);
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (i == 0 && node.child1) delete node.child1;
|
||||
if (i == 1 && node.child2) delete node.child2;
|
||||
}
|
||||
} else {
|
||||
if (leaf.p) delete [] leaf.p;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void create(PointData pts, AccessorData *indices, size_t n) {
|
||||
AccessorFunc point;
|
||||
|
||||
// Find bbox
|
||||
double xmin = point(pts, indices[0])[0], xmax = point(pts, indices[0])[0];
|
||||
double ymin = point(pts, indices[0])[1], ymax = point(pts, indices[0])[1];
|
||||
double zmin = point(pts, indices[0])[2], zmax = point(pts, indices[0])[2];
|
||||
for(unsigned int i = 1; i < n; i++) {
|
||||
xmin = min(xmin, point(pts, indices[i])[0]);
|
||||
xmax = max(xmax, point(pts, indices[i])[0]);
|
||||
ymin = min(ymin, point(pts, indices[i])[1]);
|
||||
ymax = max(ymax, point(pts, indices[i])[1]);
|
||||
zmin = min(zmin, point(pts, indices[i])[2]);
|
||||
zmax = max(zmax, point(pts, indices[i])[2]);
|
||||
}
|
||||
|
||||
// Leaf nodes
|
||||
if ((n > 0) && (n <= 10)) {
|
||||
npts = n;
|
||||
leaf.p = new AccessorData[n];
|
||||
// fill leaf index array with indices
|
||||
for(unsigned int i = 0; i < n; ++i) {
|
||||
leaf.p[i] = indices[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Else, interior nodes
|
||||
npts = 0;
|
||||
|
||||
node.center[0] = 0.5 * (xmin+xmax);
|
||||
node.center[1] = 0.5 * (ymin+ymax);
|
||||
node.center[2] = 0.5 * (zmin+zmax);
|
||||
node.dx = 0.5 * (xmax-xmin);
|
||||
node.dy = 0.5 * (ymax-ymin);
|
||||
node.dz = 0.5 * (zmax-zmin);
|
||||
node.r2 = sqr(node.dx) + sqr(node.dy) + sqr(node.dz);
|
||||
|
||||
// Find longest axis
|
||||
if (node.dx > node.dy) {
|
||||
if (node.dx > node.dz) {
|
||||
node.splitaxis = 0;
|
||||
} else {
|
||||
node.splitaxis = 2;
|
||||
}
|
||||
} else {
|
||||
if (node.dy > node.dz) {
|
||||
node.splitaxis = 1;
|
||||
} else {
|
||||
node.splitaxis = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Partition
|
||||
double splitval = node.center[node.splitaxis];
|
||||
|
||||
if ( fabs(max(max(node.dx,node.dy),node.dz)) < 0.01 ) {
|
||||
npts = n;
|
||||
leaf.p = new AccessorData[n];
|
||||
// fill leaf index array with indices
|
||||
for(unsigned int i = 0; i < n; ++i) {
|
||||
leaf.p[i] = indices[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
AccessorData* left = indices, * right = indices + n - 1;
|
||||
while(true) {
|
||||
while(point(pts, *left)[node.splitaxis] < splitval)
|
||||
left++;
|
||||
while(point(pts, *right)[node.splitaxis] >= splitval)
|
||||
right--;
|
||||
if(right < left)
|
||||
break;
|
||||
std::swap(*left, *right);
|
||||
}
|
||||
|
||||
// Build subtrees
|
||||
int i;
|
||||
#ifdef WITH_OPENMP_KD // does anybody know the reason why this is slower ?? --Andreas
|
||||
omp_set_num_threads(OPENMP_NUM_THREADS);
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
#endif
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (i == 0) {
|
||||
node.child1 = new KDTreeImpl();
|
||||
node.child1->create(pts, indices, left - indices);
|
||||
}
|
||||
if (i == 1) {
|
||||
node.child2 = new KDTreeImpl();
|
||||
node.child2->create(pts, left, n - (left - indices));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* storing the parameters of the k-d tree, i.e., the current closest point,
|
||||
* the distance to the current closest point and the point itself.
|
||||
* These global variable are needed in this search.
|
||||
*
|
||||
* Padded in the parallel case.
|
||||
*/
|
||||
#ifdef _OPENMP
|
||||
#ifdef __INTEL_COMPILER
|
||||
__declspec (align(16)) static KDParams params[MAX_OPENMP_NUM_THREADS];
|
||||
#else
|
||||
static KDParams params[MAX_OPENMP_NUM_THREADS];
|
||||
#endif //__INTEL_COMPILER
|
||||
#else
|
||||
static KDParams params[MAX_OPENMP_NUM_THREADS];
|
||||
#endif
|
||||
|
||||
/**
|
||||
* number of points. If this is 0: intermediate node. If nonzero: leaf.
|
||||
*/
|
||||
int npts;
|
||||
|
||||
/**
|
||||
* Cue the standard rant about anon unions but not structs in C++
|
||||
*/
|
||||
union {
|
||||
/**
|
||||
* in case of internal node...
|
||||
*/
|
||||
struct {
|
||||
double center[3]; ///< storing the center of the voxel (R^3)
|
||||
double dx, ///< defining the voxel itself
|
||||
dy, ///< defining the voxel itself
|
||||
dz, ///< defining the voxel itself
|
||||
r2; ///< defining the voxel itself
|
||||
int splitaxis; ///< defining the kind of splitaxis
|
||||
KDTreeImpl *child1; ///< pointers to the childs
|
||||
KDTreeImpl *child2; ///< pointers to the childs
|
||||
} node;
|
||||
/**
|
||||
* in case of leaf node ...
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* store the value itself
|
||||
* Here we store just a pointer to the data
|
||||
*/
|
||||
AccessorData* p;
|
||||
} leaf;
|
||||
};
|
||||
|
||||
void _FindClosest(const PointData& pts, int threadNum) const {
|
||||
AccessorFunc point;
|
||||
|
||||
// Leaf nodes
|
||||
if (npts) {
|
||||
for (int i = 0; i < npts; i++) {
|
||||
double myd2 = Dist2(params[threadNum].p, point(pts, leaf.p[i]));
|
||||
if (myd2 < params[threadNum].closest_d2) {
|
||||
params[threadNum].closest_d2 = myd2;
|
||||
params[threadNum].closest = point(pts, leaf.p[i]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Quick check of whether to abort
|
||||
double approx_dist_bbox = max(max(fabs(params[threadNum].p[0]-node.center[0])-node.dx,
|
||||
fabs(params[threadNum].p[1]-node.center[1])-node.dy),
|
||||
fabs(params[threadNum].p[2]-node.center[2])-node.dz);
|
||||
if (approx_dist_bbox >= 0 && sqr(approx_dist_bbox) >= params[threadNum].closest_d2)
|
||||
return;
|
||||
|
||||
// Recursive case
|
||||
double myd = node.center[node.splitaxis] - params[threadNum].p[node.splitaxis];
|
||||
if (myd >= 0.0) {
|
||||
node.child1->_FindClosest(pts, threadNum);
|
||||
if (sqr(myd) < params[threadNum].closest_d2) {
|
||||
node.child2->_FindClosest(pts, threadNum);
|
||||
}
|
||||
} else {
|
||||
node.child2->_FindClosest(pts, threadNum);
|
||||
if (sqr(myd) < params[threadNum].closest_d2) {
|
||||
node.child1->_FindClosest(pts, threadNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
/** @file
|
||||
* @brief Encapsules the implementation of ANN k-d trees.
|
||||
* @author Ulugbek Makhmudov, Jacobs University Bremen, Bremen, Germany.
|
||||
* @author Andreas Nuechter, Jacobs University Bremen, Bremen, Germany.
|
||||
*/
|
||||
|
||||
#ifndef __ANN_KD_H__
|
||||
#define __ANN_KD_H__
|
||||
|
||||
#include "slam6d/kdparams.h"
|
||||
#include "slam6d/searchTree.h"
|
||||
#include "ANN/ANN.h"
|
||||
|
||||
/**
|
||||
* @brief Encapsulating class to create and store ANN KD Trees.
|
||||
*
|
||||
* A kD tree for points, with limited
|
||||
* capabilities (find nearest point to
|
||||
* a given point, or in a fixed radius distance).
|
||||
**/
|
||||
class ANNtree : public SearchTree {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
*/
|
||||
ANNtree();
|
||||
|
||||
/**
|
||||
* Constructor using the point set pts and the num_of_pts n
|
||||
*/
|
||||
ANNtree(PointerArray<double>&_pts, int n);
|
||||
|
||||
/**
|
||||
* destructor
|
||||
*/
|
||||
virtual ~ANNtree();
|
||||
|
||||
|
||||
/**
|
||||
* Finds the closest point within the tree,
|
||||
* wrt. the point given as first parameter.
|
||||
* @param _p point
|
||||
* @param maxdist2 maximal search distance.
|
||||
* @param threadNum Thread number, for parallelization
|
||||
* @return Pointer to the closest point
|
||||
*/
|
||||
double *FindClosest(double *_p, double maxdist2, int threadNum = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* a pointer to ANNkd_tree instance
|
||||
*/
|
||||
ANNkd_tree* annkd;
|
||||
ANNdistArray nn; //temporary ANNdistArray instance to use for storing the nearest neighbor
|
||||
ANNidxArray nn_idx; //temporary ANNdistArray instance to use for storing the nearest neighbor
|
||||
|
||||
double** pts;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* @file
|
||||
* @brief Representation of a 3D scan and implementation of scan matching
|
||||
* @author Andreas Nuechter. Jacobs University Bremen, Germany
|
||||
* @author Li Wei, Wuhan University, China
|
||||
* @author Li Ming, Wuhan University, China
|
||||
*/
|
||||
|
||||
#ifndef __VELOSCAN_H__
|
||||
#define __VELOSCAN_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#undef _STDIO_DEFINED
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "slam6d/basicScan.h"
|
||||
#include "veloslam/gridcell.h"
|
||||
#include "veloslam/gridcluster.h"
|
||||
|
||||
bool FilterNOMovingObjcets(clusterFeature &glu, cluster &gluData);
|
||||
|
||||
class Trajectory
|
||||
{
|
||||
public:
|
||||
Trajectory();
|
||||
public:
|
||||
vector <Point> path;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 3D scan representation and implementation of dynamic velodyne scan matching
|
||||
*/
|
||||
class VeloScan : public BasicScan {
|
||||
|
||||
public:
|
||||
VeloScan();
|
||||
VeloScan(const VeloScan& s);
|
||||
~VeloScan();
|
||||
|
||||
public:
|
||||
// FIXME
|
||||
void FindingAllofObject(int maxDist, int minDist);
|
||||
void TrackingAllofObject(int trackingAlgo);
|
||||
void ExchangePointCloud();
|
||||
void ClassifiAllofObject();
|
||||
|
||||
int DumpScan(string filename);
|
||||
int DumpScanRedPoints(string filename);
|
||||
int DeletePoints();
|
||||
|
||||
int CalcRadAndTheta();
|
||||
int TransferToCellArray(int maxDist, int minDist);
|
||||
|
||||
void MarkStaticorMovingPointCloud();
|
||||
void FreeAllCellAndCluterMemory();
|
||||
void ClassifiAllObject();
|
||||
void ClassifibyTrackingAllObject(int currentNO ,int windowsize);
|
||||
void calcReducedPoints_byClassifi(double voxelSize, int nrpts, PointType pointtype);
|
||||
|
||||
int CalcScanCellFeature();
|
||||
int CalcCellFeature(cell& cellobj,cellFeature& f);
|
||||
int FindAndCalcScanClusterFeature();
|
||||
int SearchNeigh(cluster& clu,charvv& flagvv,int i,int j);
|
||||
int CalcClusterFeature(cluster& clu,clusterFeature& f);
|
||||
void SaveObjectsInPCD(int index, cluster &gClusterData );
|
||||
void SaveFrameInPCD( );
|
||||
|
||||
bool isTrackerHandled;
|
||||
long scanid;
|
||||
|
||||
/** scanCellFeatureArray */
|
||||
cellArray scanCellArray;
|
||||
cellFeatureArray scanCellFeatureArray;
|
||||
|
||||
clusterArray scanClusterArray;
|
||||
clusterFeatureArray scanClusterFeatureArray;
|
||||
|
||||
int clusterNum;//the number of clusters to be tracked, added by yuanjun
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/** @file
|
||||
* @brief Representation of the optimized k-d tree.
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Thomas Escher
|
||||
*/
|
||||
|
||||
#ifndef __KD_H__
|
||||
#define __KD_H__
|
||||
|
||||
#include "slam6d/kdparams.h"
|
||||
#include "slam6d/searchTree.h"
|
||||
#include "slam6d/kdTreeImpl.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if !defined _OPENMP && defined OPENMP
|
||||
#define _OPENMP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
|
||||
struct Void { };
|
||||
|
||||
struct PtrAccessor {
|
||||
inline double *operator() (Void, double* indices) {
|
||||
return indices;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The optimized k-d tree.
|
||||
*
|
||||
* A kD tree for points, with limited
|
||||
* capabilities (find nearest point to
|
||||
* a given point, or to a ray).
|
||||
**/
|
||||
class KDtree : public SearchTree, private KDTreeImpl<Void, double*, PtrAccessor> {
|
||||
public:
|
||||
KDtree(double **pts, int n);
|
||||
|
||||
virtual ~KDtree();
|
||||
|
||||
virtual double *FindClosest(double *_p, double maxdist2, int threadNum = 0) const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
* scan_io_velodyne implementation
|
||||
*
|
||||
* Copyright (C) Mohammad Faisal, Dorit Borrmann, Andreas Nuechter
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of reading 3D scans
|
||||
* @author Andreas Nuechter. Jacobs University Bremen gGmbH
|
||||
* @author Dorit Borrmann. Smart Systems Group, Jacobs University Bremen gGmbH, Germany.
|
||||
* @author Mohammad Faisal. Smart Systems Group, Jacobs University Bremen gGmbH, Germany.
|
||||
*/
|
||||
#include "slam6d/point.h"
|
||||
#include "veloslam/velodefs.h"
|
||||
#include "scanio/scan_io_velodyne.h"
|
||||
#include "slam6d/globals.icc"
|
||||
#include <fstream>
|
||||
#include<strstream>
|
||||
#include <iostream>
|
||||
using std::ifstream;
|
||||
using std::ostrstream;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::ends;
|
||||
|
||||
#include <algorithm>
|
||||
using std::swap;
|
||||
|
||||
#include<cstdio>
|
||||
#include<cstdlib>
|
||||
#include<cmath>
|
||||
#include<cstring>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
using namespace boost::filesystem;
|
||||
|
||||
#define DATA_PATH_PREFIX "scan"
|
||||
#define DATA_PATH_SUFFIX ".bin"
|
||||
#define POSE_PATH_PREFIX "scan"
|
||||
#define POSE_PATH_SUFFIX ".pose"
|
||||
|
||||
#define BLOCK_OFFSET 42+16
|
||||
|
||||
#define BLOCK_SIZE 1206
|
||||
#define CIRCLELENGTH 360
|
||||
#define VELODYNE_NUM_LASERS 64
|
||||
#define CircleBufferSize CIRCLELENGTH*32*12
|
||||
#define CIRCLEROUND CIRCLELENGTH*6
|
||||
|
||||
#define RADIANS_PER_LSB 0.0174532925
|
||||
#define METERS_PER_LSB 0.002
|
||||
#define METERS_PER_CM 0.01
|
||||
|
||||
#define TWOPI_INV (0.5/M_PI)
|
||||
#define TWOPI (2*M_PI)
|
||||
|
||||
typedef struct raw_packet
|
||||
{
|
||||
unsigned char dat[1200];
|
||||
unsigned short revolution;
|
||||
unsigned char status[4];
|
||||
} raw_packet_t;
|
||||
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
long CountOfLidar = 0;
|
||||
|
||||
//Changes the variable to be filled dynamically. Added a 6th variable to enable or disable a specific sensor
|
||||
double velodyne_calibrated[VELODYNE_NUM_LASERS][6];
|
||||
|
||||
/**
|
||||
* Method to fill the calibration data using the Velodyne64 calibration data from Wuhan.
|
||||
*/
|
||||
int backup()
|
||||
{
|
||||
double velodyne_calibrated1[64][6] =
|
||||
{
|
||||
{ -7.1581192, -4.5, 102, 21.560343, -2.5999999, 1},
|
||||
{ -6.8178215, -3.4000001, 125, 21.516994, 2.5999999, 1},
|
||||
{ 0.31782165, 3, 130, 20.617426, -2.5999999, 1},
|
||||
{ 0.65811908, 4.5999999, 128, 20.574717, 2.5999999, 1},
|
||||
{ -6.4776502, -0.5, 112, 21.473722, -2.5999999, 1},
|
||||
{ -6.1375928, 1, 125, 21.430525, 2.5999999, 1},
|
||||
{ -8.520812, -1.5, 106, 21.734608, -2.5999999, 1},
|
||||
{ -8.1798887, 0.40000001, 127, 21.690901, 2.5999999, 1},
|
||||
{ -5.797637, 4, 111, 21.387396, -2.5999999, 1},
|
||||
{ -5.4577708, 5.5, 126, 21.34433, 2.5999999, 1},
|
||||
{ -7.8391404, 3.0999999, 113, 21.647291, -2.5999999, 1},
|
||||
{ -7.4985547, 4.5, 123, 21.603773, 2.5999999, 1},
|
||||
{ -3.0802133, -4.5, 105, 21.044245, -2.5999999, 1},
|
||||
{ -2.7406337, -3.2, 133, 21.001518, 2.5999999, 1},
|
||||
{ -5.1179824, -5.5, 110, 21.301321, -2.5999999, 1},
|
||||
{ -4.7782598, -4, 129, 21.258366, 2.5999999, 1},
|
||||
{ -2.4010365, -0.2, 111, 20.958813, -2.5999999, 1},
|
||||
{ -2.0614092, 1, 130, 20.916126, 2.5999999, 1},
|
||||
{ -4.4385905, -1.2, 115, 21.215462, -2.5999999, 1},
|
||||
{ -4.0989642, 0, 133, 21.172602, 2.5999999, 1},
|
||||
{ -1.7217404, 3.8, 113, 20.873451, -2.5999999, 1},
|
||||
{ -1.3820176, 5, 130, 20.830786, 2.5999999, 1},
|
||||
{ -3.7593663, 3, 117, 21.129782, -2.5999999, 1},
|
||||
{ -3.4197867, 4.5, 129, 21.086998, 2.5999999, 1},
|
||||
{ 0.998555, -4.5, 107, 20.531982, -2.5999999, 1},
|
||||
{ 1.339141, -3.2, 131, 20.489222, 2.5999999, 1},
|
||||
{ -1.0422293, -5.4000001, 128, 20.788124, -2.5999999, 1},
|
||||
{ -0.70236301, -4, 134, 20.745461, 2.5999999, 1},
|
||||
{ 1.679889, -0.5, 124, 20.446428, -2.5999999, 1},
|
||||
{ 2.0208123, 1, 136, 20.403601, 2.5999999, 1},
|
||||
{ -0.36240739, -1.5, 131, 20.702793, -2.5999999, 1},
|
||||
{ -0.022349782, 0.2, 136, 20.660116, 2.5999999, 1},
|
||||
{ -22.737886, -7.8000002, 101, 16.019152, -2.5999999, 1},
|
||||
{ -22.226072, -5, 88, 15.954137, 2.5999999, 1},
|
||||
{ -11.513928, 4.5, 121, 14.680806, -2.5999999, 1},
|
||||
{ -11.002114, 7.4000001, 88, 14.623099, 2.5999999, 1},
|
||||
{ -21.714685, -1, 94, 15.889649, -2.5999999, 1},
|
||||
{ -21.203688, 2, 88, 15.82566, 2.5999999, 1},
|
||||
{ -24.790272, -2.5, 114, 16.284933, -2.5999999, 1},
|
||||
{ -24.276321, 0.5, 89, 16.217583, 2.5999999, 1},
|
||||
{ -20.693031, 6, 98, 15.762167, -2.5999999, 1},
|
||||
{ -20.182682, 9, 92, 15.699132, 2.5999999, 1},
|
||||
{ -23.762968, 4.5, 107, 16.15085, -2.5999999, 1},
|
||||
{ -23.250172, 7.5, 80, 16.084715, 2.5999999, 1},
|
||||
{ -16.615318, -7.5, 121, 15.26925, -2.5999999, 1},
|
||||
{ -16.105938, -5, 92, 15.209245, 2.5999999, 1},
|
||||
{ -19.672594, -9, 119, 15.63654, -2.5999999, 1},
|
||||
{ -19.162729, -6, 89, 15.574372, 2.5999999, 1},
|
||||
{ -15.596496, -1, 109, 15.14954, -2.5999999, 1},
|
||||
{ -15.086954, 2, 88, 15.090119, 2.5999999, 1},
|
||||
{ -18.653046, -2, 117, 15.51261, -2.5999999, 1},
|
||||
{ -18.143503, 0.69999999, 88, 15.451235, 2.5999999, 1},
|
||||
{ -14.577271, 5.5, 112, 15.030966, -2.5999999, 1},
|
||||
{ -14.067405, 8.3999996, 87, 14.972065, 2.5999999, 1},
|
||||
{ -17.634062, 5, 119, 15.390228, -6.1999998, 1},
|
||||
{ -17.124681, 7.5, 97, 15.329572, 2.5999999, 1},
|
||||
{ -10.489829, -7.5, 119, 14.565539, -2.5999999, 1},
|
||||
{ -9.9770317, -4.6999998, 95, 14.508112, 2.5999999, 1},
|
||||
{ -13.557318, -8.5, 126, 14.913401, -2.5999999, 1},
|
||||
{ -13.046968, -6, 92, 14.854958, 2.5999999, 1},
|
||||
{ -9.4636793, -1, 112, 14.450804, -2.5999999, 1},
|
||||
{ -8.949728, 1.5, 93, 14.3936, 2.5999999, 1},
|
||||
{ -12.536313, -2, 121, 14.796721, -2.5999999, 1},
|
||||
{ -12.025314, 0.40000001, 96, 14.738676, 2.5999999, 1},
|
||||
};
|
||||
|
||||
for ( int i = 0; i < VELODYNE_NUM_LASERS; i++ )
|
||||
{
|
||||
velodyne_calibrated[i][0] = velodyne_calibrated1[i][0];
|
||||
velodyne_calibrated[i][1] = velodyne_calibrated1[i][1];
|
||||
velodyne_calibrated[i][2] = velodyne_calibrated1[i][2];
|
||||
velodyne_calibrated[i][3] = velodyne_calibrated1[i][3];
|
||||
velodyne_calibrated[i][4] = velodyne_calibrated1[i][4];
|
||||
velodyne_calibrated[i][5] = velodyne_calibrated1[i][5];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
double rotCorrection[VELODYNE_NUM_LASERS];
|
||||
double vertCorrection[VELODYNE_NUM_LASERS];
|
||||
double distCorrection[VELODYNE_NUM_LASERS];
|
||||
double vertoffsetCorrection[VELODYNE_NUM_LASERS];
|
||||
double horizdffsetCorrection[VELODYNE_NUM_LASERS];
|
||||
double enabled[VELODYNE_NUM_LASERS]; //New variable to change enabling and disabling of data.
|
||||
|
||||
int physical2logical[VELODYNE_NUM_LASERS];
|
||||
int logical2physical[VELODYNE_NUM_LASERS];
|
||||
|
||||
double absf ( double a )
|
||||
{
|
||||
if ( a < 0 )
|
||||
return -a;
|
||||
return a;
|
||||
}
|
||||
|
||||
int velodyne_physical_to_logical ( int phys )
|
||||
{
|
||||
return physical2logical[phys];
|
||||
}
|
||||
|
||||
int velodyne_logical_to_physical ( int logical )
|
||||
{
|
||||
return logical2physical[logical];
|
||||
}
|
||||
|
||||
int laser_phi_compare(const void *_a, const void *_b)
|
||||
{
|
||||
int a = *((int*) _a);
|
||||
int b = *((int*) _b);
|
||||
|
||||
if (velodyne_calibrated[a][0] < velodyne_calibrated[b][0])
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** valid only for v > 0 **/
|
||||
static inline double mod2pi_positive(double vin)
|
||||
{
|
||||
double q = vin * TWOPI_INV + 0.5;
|
||||
int qi = (int) q;
|
||||
|
||||
return vin - qi*TWOPI;
|
||||
}
|
||||
|
||||
/** Map v to [-PI, PI] **/
|
||||
static inline double mod2pi(double vin)
|
||||
{
|
||||
if (vin < 0)
|
||||
return -mod2pi_positive(-vin);
|
||||
else
|
||||
return mod2pi_positive(vin);
|
||||
}
|
||||
|
||||
/** Return vin such that it is within PI degrees of ref **/
|
||||
static inline double mod2pi_ref(double ref, double vin)
|
||||
{
|
||||
return ref + mod2pi(vin - ref);
|
||||
}
|
||||
|
||||
int velodyne_calib_precompute()
|
||||
{
|
||||
int i;
|
||||
int logical;
|
||||
for ( i = 0; i < VELODYNE_NUM_LASERS; i++ )
|
||||
logical2physical[i] = i;
|
||||
|
||||
qsort ( logical2physical, VELODYNE_NUM_LASERS, sizeof ( int ), laser_phi_compare );
|
||||
|
||||
for ( logical = 0; logical < VELODYNE_NUM_LASERS; logical++ )
|
||||
{
|
||||
physical2logical[logical2physical[logical]] = logical;
|
||||
}
|
||||
|
||||
//vertCorrection rotCorrection distCorrection vertOffsetCorrection horizOffsetCorrection enable
|
||||
for ( i = 0; i < VELODYNE_NUM_LASERS; i++ )
|
||||
{
|
||||
vertCorrection[i] = velodyne_calibrated[i][0] * RADIANS_PER_LSB;
|
||||
rotCorrection[i] = velodyne_calibrated[i][1] * RADIANS_PER_LSB;
|
||||
distCorrection[i] = velodyne_calibrated[i][2] * METERS_PER_CM;
|
||||
vertoffsetCorrection[i] = velodyne_calibrated[i][3] * METERS_PER_CM;
|
||||
horizdffsetCorrection[i] = velodyne_calibrated[i][4] * METERS_PER_CM;
|
||||
enabled[i] = velodyne_calibrated[i][5];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int calibrate(string filename)
|
||||
{
|
||||
int linecount = 0;
|
||||
string line;
|
||||
std::ifstream myfile (filename.c_str());
|
||||
if (myfile.is_open())
|
||||
{
|
||||
cout << "Using Calibration File"<<endl;
|
||||
string data[6];
|
||||
getline (myfile,line);
|
||||
string theDelimiter = ",";
|
||||
int j=0;
|
||||
do
|
||||
{
|
||||
getline (myfile,line);
|
||||
int i = 0;
|
||||
size_t start = 0, end = 0;
|
||||
while ( end != string::npos && i < 6)
|
||||
{
|
||||
end = line.find( theDelimiter, start);
|
||||
data[i] = line.substr(start, (end == string::npos)?string::npos:end - start);
|
||||
start = ((end>(string::npos - theDelimiter.size()))?string::npos:end + theDelimiter.size());
|
||||
i++;
|
||||
}
|
||||
|
||||
velodyne_calibrated[j][0] = atof(data[0].c_str());
|
||||
velodyne_calibrated[j][1] = atof(data[1].c_str());
|
||||
velodyne_calibrated[j][2] = atof(data[2].c_str());
|
||||
velodyne_calibrated[j][3] = atof(data[3].c_str());
|
||||
velodyne_calibrated[j][4] = atof(data[4].c_str());
|
||||
velodyne_calibrated[j][5] = atof(data[5].c_str());
|
||||
linecount++;
|
||||
j++;
|
||||
}
|
||||
while(!myfile.eof());
|
||||
|
||||
myfile.close();
|
||||
|
||||
if (linecount < 60)
|
||||
{
|
||||
for (int i = 32; i<64; i++)
|
||||
{
|
||||
velodyne_calibrated[i][0] = 0.0;
|
||||
velodyne_calibrated[i][1] = 0.0;
|
||||
velodyne_calibrated[i][2] = 0.0;
|
||||
velodyne_calibrated[i][3] = 0.0;
|
||||
velodyne_calibrated[i][4] = 0.0;
|
||||
velodyne_calibrated[i][5] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Unable to open calibration file.\nUsing Wuhan hardcored values."<<endl;
|
||||
backup();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int read_one_packet (
|
||||
FILE *fp,
|
||||
PointFilter& filter,
|
||||
std::vector<double>* xyz,
|
||||
std::vector<unsigned char>* rgb,
|
||||
std::vector<float>* reflectance,
|
||||
std::vector<float>* amplitude,
|
||||
std::vector<int>* type,
|
||||
std::vector<float>* deviation)
|
||||
{
|
||||
|
||||
int c, i, j;
|
||||
unsigned char Head;
|
||||
BYTE buf[BLOCK_SIZE];
|
||||
Point point;
|
||||
BYTE *p;
|
||||
unsigned short *ps;
|
||||
unsigned short *pt;
|
||||
unsigned short *pshort;
|
||||
|
||||
double ctheta;
|
||||
double theta, phi;
|
||||
|
||||
double sin_ctheta, cos_ctheta;
|
||||
double sin_theta, cos_theta;
|
||||
double sin_phi, cos_phi;
|
||||
|
||||
unsigned short physicalNO;
|
||||
unsigned short logicalNO;
|
||||
|
||||
float rotational;
|
||||
float distance;
|
||||
float corredistance;
|
||||
int intensity;
|
||||
int physical;
|
||||
int size;
|
||||
|
||||
unsigned short rot;
|
||||
double x, y, z;
|
||||
|
||||
int circle_col = 0;
|
||||
int circle_row = 0;
|
||||
|
||||
for ( c = 0 ; c < CIRCLELENGTH; c++ )
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
fseek(fp , BLOCK_OFFSET, SEEK_CUR);
|
||||
#else
|
||||
#ifdef __CYGWIN__
|
||||
fseek(fp , BLOCK_OFFSET, SEEK_CUR);
|
||||
#else
|
||||
fseeko(fp , BLOCK_OFFSET, SEEK_CUR);
|
||||
#endif
|
||||
#endif
|
||||
size=fread ( buf, 1, BLOCK_SIZE, fp );
|
||||
|
||||
if(size<BLOCK_SIZE)
|
||||
return -1;
|
||||
|
||||
ps = ( unsigned short * ) buf;
|
||||
p = buf;
|
||||
physicalNO = 0;
|
||||
|
||||
for ( i = 0; i < 12; i++ )
|
||||
{
|
||||
//Each frame start with 0xEEFF || 0xDDFF
|
||||
if ( *ps == 0xEEFF )
|
||||
Head = 0;
|
||||
else if ( *ps == 0xDDFF )
|
||||
Head = 32;
|
||||
|
||||
pshort = ( unsigned short * ) ( p + 2 );
|
||||
rot = ( ( unsigned short ) ( *pshort ) / 100.0 );
|
||||
|
||||
circle_col = c * 6 + i / 2;
|
||||
rotational = ( ( float ) ( *pshort ) ) / 100.0;
|
||||
|
||||
for ( j = 0; j < 32; j++ )
|
||||
{
|
||||
physicalNO = j + Head;
|
||||
logicalNO = velodyne_physical_to_logical ( physicalNO );
|
||||
|
||||
circle_col = c * 6 + i / 2;
|
||||
circle_row = logicalNO;
|
||||
|
||||
pt = ( unsigned short * ) ( p + 4 + j * 3 );
|
||||
distance = absf ( ( *pt ) * 0.002 );
|
||||
|
||||
if( distance < 120 && distance > 2.2 )
|
||||
{
|
||||
BYTE *inty = ( BYTE * ) ( p + 4 + j * 3 + 2 );
|
||||
intensity = *inty;
|
||||
|
||||
ctheta = 2 * M_PI - rotational * RADIANS_PER_LSB;
|
||||
if ( ctheta == 2*M_PI )
|
||||
ctheta = 0;
|
||||
|
||||
sin_ctheta = sin ( ctheta );
|
||||
cos_ctheta = cos ( ctheta );
|
||||
|
||||
//vertCorrection rotCorrection distCorrection vertOffsetCorrection horizOffsetCorrection
|
||||
// corredistance = ( distance + distCorrection[physicalNO] ) * ( 1.0 + vertoffsetCorrection[physicalNO] );
|
||||
corredistance = ( distance + distCorrection[physicalNO] ) ;
|
||||
theta = mod2pi_ref ( M_PI, ctheta + rotCorrection[physicalNO] ); /////////????////////
|
||||
phi = vertCorrection[physicalNO]; ////////?????/////////////////
|
||||
|
||||
sin_theta = sin ( theta );
|
||||
cos_theta = cos ( theta );
|
||||
sin_phi = sin ( phi );
|
||||
cos_phi = cos ( phi );
|
||||
|
||||
/////////////////////?a??¡Á?¡À¨º/////////////////////
|
||||
x = corredistance * cos_theta * cos_phi;
|
||||
y = corredistance * sin_theta * cos_phi;
|
||||
z = corredistance * sin_phi +vertoffsetCorrection[physicalNO]*cos_phi;
|
||||
|
||||
x -= horizdffsetCorrection[physicalNO] * cos_ctheta;
|
||||
y -= horizdffsetCorrection[physicalNO] * sin_ctheta;
|
||||
|
||||
point.rad = sqrt( x*x + y*y );
|
||||
point.tan_theta = y/x;
|
||||
|
||||
point.type = POINT_TYPE_GROUND;
|
||||
point.x=x*100;
|
||||
point.y=z*100;
|
||||
point.z=-y*100;
|
||||
|
||||
double p[3];
|
||||
p[0] = point.x;
|
||||
p[1] = point.y;
|
||||
p[2] = point.z;
|
||||
|
||||
//Enable Check. Could be moved earlier to remove all the unnecessary calculations.
|
||||
//Here to simplify the implementation
|
||||
if(filter.check(p) && (enabled[physicalNO]==1))
|
||||
{
|
||||
for(int ii = 0; ii < 3; ++ii) xyz->push_back(p[ii]);
|
||||
}
|
||||
}
|
||||
}
|
||||
p = p + 100;
|
||||
ps = ( unsigned short * ) p;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::list<std::string> ScanIO_velodyne::readDirectory(const char* dir_path, unsigned int start, unsigned int end)
|
||||
{
|
||||
//Calling the calibration method with the file name "calibration.txt" in the same folder as the scan.bin
|
||||
string califilename;
|
||||
string dir(dir_path);
|
||||
califilename = dir + "calibration" + ".txt";
|
||||
calibrate(califilename);
|
||||
std::list<std::string> identifiers;
|
||||
// fileCounter = start;
|
||||
|
||||
velodyne_calib_precompute();
|
||||
for(unsigned int i = start; i <= end; ++i)
|
||||
{
|
||||
std::string identifier(to_string(i,3));
|
||||
|
||||
path data(dir_path);
|
||||
data /= path(std::string(DATA_PATH_PREFIX) + DATA_PATH_SUFFIX);
|
||||
|
||||
path pose(dir_path);
|
||||
pose /= path(std::string(POSE_PATH_PREFIX) + identifier + POSE_PATH_SUFFIX);
|
||||
|
||||
if(!exists(data))
|
||||
break;
|
||||
identifiers.push_back(identifier);
|
||||
}
|
||||
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
void ScanIO_velodyne::readPose(const char* dir_path, const char* identifier, double* pose)
|
||||
{
|
||||
unsigned int i;
|
||||
// on pose information for veloslam
|
||||
for(i = 0; i < 6; ++i) pose[i] = 0.0;
|
||||
for(i = 3; i < 6; ++i) pose[i] = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
bool ScanIO_velodyne::supports(IODataType type)
|
||||
{
|
||||
return !!(type & (DATA_XYZ));
|
||||
}
|
||||
|
||||
|
||||
void ScanIO_velodyne::readScan(
|
||||
const char* dir_path,
|
||||
const char* identifier,
|
||||
PointFilter& filter,
|
||||
std::vector<double>* xyz,
|
||||
std::vector<unsigned char>* rgb,
|
||||
std::vector<float>* reflectance,
|
||||
std::vector<float>* temperature,
|
||||
std::vector<float>* amplitude,
|
||||
std::vector<int>* type,
|
||||
std::vector<float>* deviation)
|
||||
{
|
||||
unsigned int i;
|
||||
FILE *scan_in;
|
||||
|
||||
path data_path(dir_path);
|
||||
data_path /= path(std::string(DATA_PATH_PREFIX) + DATA_PATH_SUFFIX);
|
||||
if(!exists(data_path))
|
||||
throw std::runtime_error(std::string("There is no scan file for [") + identifier + "] in [" + dir_path + "]");
|
||||
|
||||
char filename[256];
|
||||
sprintf(filename, "%s%s%s",dir_path ,DATA_PATH_PREFIX, DATA_PATH_SUFFIX );
|
||||
|
||||
#ifdef _MSC_VER
|
||||
scan_in = fopen(filename,"rb");
|
||||
#else
|
||||
#ifdef __CYGWIN__
|
||||
scan_in = fopen(filename,"rb");
|
||||
#else
|
||||
scan_in = fopen64(filename,"rb");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(scan_in == NULL)
|
||||
{
|
||||
cerr<<data_path <<endl;
|
||||
cerr << "ERROR: Missing file " << data_path <<" "<<strerror(errno)<< endl;
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "Processing Scan " << data_path;
|
||||
cout.flush();
|
||||
|
||||
xyz->reserve(12*32*CIRCLELENGTH);
|
||||
|
||||
fileCounter= atoi(identifier);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
fseek(scan_in, 24, SEEK_SET);
|
||||
fseek(scan_in, (BLOCK_SIZE+BLOCK_OFFSET)*CIRCLELENGTH*fileCounter, SEEK_CUR);
|
||||
#else
|
||||
#ifdef __CYGWIN__
|
||||
fseek(scan_in, 24, SEEK_SET);
|
||||
fseek(scan_in, (BLOCK_SIZE+BLOCK_OFFSET)*CIRCLELENGTH*fileCounter, SEEK_CUR);
|
||||
#else
|
||||
fseeko(scan_in, 24, SEEK_SET);
|
||||
fseeko(scan_in, (BLOCK_SIZE+BLOCK_OFFSET)*CIRCLELENGTH*fileCounter, SEEK_CUR);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
read_one_packet(
|
||||
scan_in,
|
||||
filter,
|
||||
xyz,
|
||||
rgb,
|
||||
reflectance,
|
||||
amplitude,
|
||||
type,
|
||||
deviation);
|
||||
|
||||
cout << " with " << xyz->size() << " Points";
|
||||
cout << " done " << fileCounter<<endl;
|
||||
|
||||
fclose(scan_in);
|
||||
// process next frames
|
||||
}
|
||||
|
||||
/**
|
||||
* class factory for object construction
|
||||
*
|
||||
* @return Pointer to new object
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
extern "C" __declspec(dllexport) ScanIO* create()
|
||||
#else
|
||||
extern "C" ScanIO* create()
|
||||
#endif
|
||||
{
|
||||
return new ScanIO_velodyne;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* class factory for object construction
|
||||
*
|
||||
* @return Pointer to new object
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
extern "C" __declspec(dllexport) void destroy(ScanIO *sio)
|
||||
#else
|
||||
extern "C" void destroy(ScanIO *sio)
|
||||
#endif
|
||||
{
|
||||
delete sio;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,729 @@
|
|||
/*
|
||||
* scan_red implementation
|
||||
*
|
||||
* Copyright (C) Johannes Schauer
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "slam6d/scan.h"
|
||||
#include "slam6d/globals.icc"
|
||||
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
namespace po = boost::program_options;
|
||||
|
||||
#include "slam6d/fbr/panorama.h"
|
||||
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/imgproc/imgproc_c.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
enum image_type {M_RANGE, M_INTENSITY};
|
||||
|
||||
enum segment_method {THRESHOLD, ADAPTIVE_THRESHOLD, PYR_MEAN_SHIFT, PYR_SEGMENTATION, WATERSHED};
|
||||
|
||||
/* Function used to check that 'opt1' and 'opt2' are not specified
|
||||
at the same time. */
|
||||
void conflicting_options(const po::variables_map & vm,
|
||||
const char *opt1, const char *opt2)
|
||||
{
|
||||
if (vm.count(opt1) && !vm[opt1].defaulted()
|
||||
&& vm.count(opt2) && !vm[opt2].defaulted())
|
||||
throw std::logic_error(string("Conflicting options '")
|
||||
+ opt1 + "' and '" + opt2 + "'.");
|
||||
}
|
||||
|
||||
/* Function used to check that if 'for_what' is specified, then
|
||||
'required_option' is specified too. */
|
||||
void option_dependency(const po::variables_map & vm,
|
||||
const char *for_what, const char *required_option)
|
||||
{
|
||||
if (vm.count(for_what) && !vm[for_what].defaulted())
|
||||
if (vm.count(required_option) == 0
|
||||
|| vm[required_option].defaulted())
|
||||
throw std::logic_error(string("Option '") + for_what +
|
||||
"' requires option '" +
|
||||
required_option + "'.");
|
||||
}
|
||||
|
||||
/*
|
||||
* validates panorama method specification
|
||||
*/
|
||||
namespace fbr {
|
||||
void validate(boost::any& v, const std::vector<std::string>& values,
|
||||
projection_method*, int) {
|
||||
if (values.size() == 0)
|
||||
throw std::runtime_error("Invalid model specification");
|
||||
string arg = values.at(0);
|
||||
if(strcasecmp(arg.c_str(), "EQUIRECTANGULAR") == 0) v = EQUIRECTANGULAR;
|
||||
else if(strcasecmp(arg.c_str(), "CYLINDRICAL") == 0) v = CYLINDRICAL;
|
||||
else if(strcasecmp(arg.c_str(), "MERCATOR") == 0) v = MERCATOR;
|
||||
else if(strcasecmp(arg.c_str(), "RECTILINEAR") == 0) v = RECTILINEAR;
|
||||
else if(strcasecmp(arg.c_str(), "PANNINI") == 0) v = PANNINI;
|
||||
else if(strcasecmp(arg.c_str(), "STEREOGRAPHIC") == 0) v = STEREOGRAPHIC;
|
||||
else if(strcasecmp(arg.c_str(), "ZAXIS") == 0) v = ZAXIS;
|
||||
else if(strcasecmp(arg.c_str(), "CONIC") == 0) v = CONIC;
|
||||
else throw std::runtime_error(std::string("projection method ") + arg + std::string(" is unknown"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* validates segmentation method specification
|
||||
*/
|
||||
void validate(boost::any& v, const std::vector<std::string>& values,
|
||||
segment_method*, int) {
|
||||
if (values.size() == 0)
|
||||
throw std::runtime_error("Invalid model specification");
|
||||
string arg = values.at(0);
|
||||
if(strcasecmp(arg.c_str(), "THRESHOLD") == 0) v = THRESHOLD;
|
||||
else if(strcasecmp(arg.c_str(), "ADAPTIVE_THRESHOLD") == 0) v = ADAPTIVE_THRESHOLD;
|
||||
else if(strcasecmp(arg.c_str(), "PYR_MEAN_SHIFT") == 0) v = PYR_MEAN_SHIFT;
|
||||
else if(strcasecmp(arg.c_str(), "PYR_SEGMENTATION") == 0) v = PYR_SEGMENTATION;
|
||||
else if(strcasecmp(arg.c_str(), "WATERSHED") == 0) v = WATERSHED;
|
||||
else throw std::runtime_error(std::string("segmentation method ") + arg + std::string(" is unknown"));
|
||||
}
|
||||
|
||||
/*
|
||||
* validates input type specification
|
||||
*/
|
||||
void validate(boost::any& v, const std::vector<std::string>& values,
|
||||
IOType*, int) {
|
||||
if (values.size() == 0)
|
||||
throw std::runtime_error("Invalid model specification");
|
||||
string arg = values.at(0);
|
||||
try {
|
||||
v = formatname_to_io_type(arg.c_str());
|
||||
} catch (...) { // runtime_error
|
||||
throw std::runtime_error("Format " + arg + " unknown.");
|
||||
}
|
||||
}
|
||||
|
||||
void segmentation_option_dependency(const po::variables_map & vm, segment_method stype, const char *option)
|
||||
{
|
||||
if (vm.count("segment") && vm["segment"].as<segment_method>() == stype) {
|
||||
if (!vm.count(option)) {
|
||||
throw std::logic_error (string("this segmentation option needs ")+option+" to be set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void segmentation_option_conflict(const po::variables_map & vm, segment_method stype, const char *option)
|
||||
{
|
||||
if (vm.count("segment") && vm["segment"].as<segment_method>() == stype) {
|
||||
if (vm.count(option)) {
|
||||
throw std::logic_error (string("this segmentation option is incompatible with ")+option);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* parse commandline options, fill arguments
|
||||
*/
|
||||
void parse_options(int argc, char **argv, int &start, int &end,
|
||||
bool &scanserver, image_type &itype, int &width, int &height,
|
||||
fbr::projection_method &ptype, string &dir, IOType &iotype,
|
||||
int &maxDist, int &minDist, int &nImages, int &pParam, bool &logarithm,
|
||||
float &cutoff, segment_method &stype, string &marker, bool &dump_pano,
|
||||
bool &dump_seg, double &thresh, int &maxlevel, int &radius,
|
||||
double &pyrlinks, double &pyrcluster, int &pyrlevels)
|
||||
{
|
||||
po::options_description generic("Generic options");
|
||||
generic.add_options()
|
||||
("help,h", "output this help message");
|
||||
|
||||
po::options_description input("Input options");
|
||||
input.add_options()
|
||||
("start,s", po::value<int>(&start)->default_value(0),
|
||||
"start at scan <arg> (i.e., neglects the first <arg> scans) "
|
||||
"[ATTENTION: counting naturally starts with 0]")
|
||||
("end,e", po::value<int>(&end)->default_value(-1),
|
||||
"end after scan <arg>")
|
||||
("format,f", po::value<IOType>(&iotype)->default_value(UOS),
|
||||
"using shared library <arg> for input. (chose F from {uos, uos_map, "
|
||||
"uos_rgb, uos_frames, uos_map_frames, old, rts, rts_map, ifp, "
|
||||
"riegl_txt, riegl_rgb, riegl_bin, zahn, ply})")
|
||||
("max,M", po::value<int>(&maxDist)->default_value(-1),
|
||||
"neglegt all data points with a distance larger than <arg> 'units")
|
||||
("min,m", po::value<int>(&minDist)->default_value(-1),
|
||||
"neglegt all data points with a distance smaller than <arg> 'units")
|
||||
("scanserver,S", po::value<bool>(&scanserver)->default_value(false),
|
||||
"Use the scanserver as an input method and handling of scan data");
|
||||
|
||||
po::options_description image("Panorama image options");
|
||||
image.add_options()
|
||||
("range,r", "create range image")
|
||||
("intensity,i", "create intensity image")
|
||||
("width,w", po::value<int>(&width)->default_value(1280),
|
||||
"width of panorama")
|
||||
("height,h", po::value<int>(&height)->default_value(960),
|
||||
"height of panorama")
|
||||
("panorama,p", po::value<fbr::projection_method>(&ptype)->
|
||||
default_value(fbr::EQUIRECTANGULAR), "panorama type (EQUIRECTANGULAR, "
|
||||
"CYLINDRICAL, MERCATOR, RECTILINEAR, PANNINI, STEREOGRAPHIC, ZAXIS, "
|
||||
"CONIC)")
|
||||
("num-images,N", po::value<int>(&nImages)->default_value(1),
|
||||
"number of images used for some projections")
|
||||
("proj-param,P", po::value<int>(&pParam)->default_value(0),
|
||||
"special projection parameter")
|
||||
("dump-pano,d", po::bool_switch(&dump_pano),
|
||||
"output panorama (useful to create marker image for watershed)");
|
||||
|
||||
po::options_description range_image("Range image options");
|
||||
range_image.add_options()
|
||||
("logarithm,L", po::bool_switch(&logarithm),
|
||||
"use the logarithm for range image panoramas")
|
||||
("cutoff,C", po::value<float>(&cutoff)->default_value(0.0), // FIXME: percentage is the wrong word
|
||||
"percentage of furthest away data points to cut off to improve "
|
||||
"precision for closer values (values from 0.0 to 1.0)");
|
||||
|
||||
po::options_description segment("Segmentation options");
|
||||
segment.add_options()
|
||||
("segment,g", po::value<segment_method>(&stype)->
|
||||
default_value(PYR_MEAN_SHIFT), "segmentation method (THRESHOLD, "
|
||||
"ADAPTIVE_THRESHOLD, PYR_MEAN_SHIFT, PYR_SEGMENTATION, WATERSHED)")
|
||||
("marker,K", po::value<string>(&marker),
|
||||
"marker mask for watershed segmentation")
|
||||
("thresh,T", po::value<double>(&thresh),
|
||||
"threshold for threshold segmentation")
|
||||
("maxlevel,X", po::value<int>(&maxlevel),
|
||||
"maximum level for meanshift segmentation")
|
||||
("radius,R", po::value<int>(&radius),
|
||||
"radius for meanshift segmentation")
|
||||
("links,l", po::value<double>(&pyrlinks),
|
||||
"error threshold for establishing the links for pyramid segmentation")
|
||||
("clustering,c", po::value<double>(&pyrcluster),
|
||||
"error threshold for the segments clustering for pyramid "
|
||||
"segmentation")
|
||||
("levels,E", po::value<int>(&pyrlevels)->default_value(4),
|
||||
"levels of pyramid segmentation")
|
||||
("dump-seg,D", po::bool_switch(&dump_seg),
|
||||
"output segmentation image (for debugging)");
|
||||
|
||||
po::options_description hidden("Hidden options");
|
||||
hidden.add_options()
|
||||
("input-dir", po::value<string>(&dir), "input dir");
|
||||
|
||||
// all options
|
||||
po::options_description all;
|
||||
all.add(generic).add(input).add(image).add(range_image).add(segment).add(hidden);
|
||||
|
||||
// options visible with --help
|
||||
po::options_description cmdline_options;
|
||||
cmdline_options.add(generic).add(input).add(image).add(range_image).add(segment);
|
||||
|
||||
// positional argument
|
||||
po::positional_options_description pd;
|
||||
pd.add("input-dir", 1);
|
||||
|
||||
// process options
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(argc, argv).
|
||||
options(all).positional(pd).run(), vm);
|
||||
po::notify(vm);
|
||||
|
||||
// display help
|
||||
if (vm.count("help")) {
|
||||
cout << cmdline_options;
|
||||
cout << "\nExample usage:\n"
|
||||
<< "bin/scan2segments -s 0 -e 0 -f riegl_txt --segment PYR_SEGMENTATION -l 50 -c 50 -E 4 -D -i ~/path/to/bremen_city\n"
|
||||
<< "bin/scan2segments -s 0 -e 0 -f riegl_txt --segment PYR_SEGMENTATION -l 255 -c 30 -E 2 -D -i ~/path/to/bremen_city\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// option conflicts and dependencies
|
||||
conflicting_options(vm, "range", "intensity");
|
||||
option_dependency(vm, "logarithm", "range");
|
||||
option_dependency(vm, "cutoff", "range");
|
||||
|
||||
// decide between range and intensity panorama
|
||||
if (vm.count("range"))
|
||||
itype = M_RANGE;
|
||||
else
|
||||
itype = M_INTENSITY;
|
||||
|
||||
segmentation_option_dependency(vm, WATERSHED, "marker");
|
||||
segmentation_option_conflict(vm, WATERSHED, "thresh");
|
||||
segmentation_option_conflict(vm, WATERSHED, "maxlevel");
|
||||
segmentation_option_conflict(vm, WATERSHED, "radius");
|
||||
segmentation_option_conflict(vm, WATERSHED, "links");
|
||||
segmentation_option_conflict(vm, WATERSHED, "clustering");
|
||||
segmentation_option_conflict(vm, WATERSHED, "levels");
|
||||
|
||||
segmentation_option_conflict(vm, THRESHOLD, "marker");
|
||||
segmentation_option_dependency(vm, THRESHOLD, "thresh");
|
||||
segmentation_option_conflict(vm, THRESHOLD, "maxlevel");
|
||||
segmentation_option_conflict(vm, THRESHOLD, "radius");
|
||||
segmentation_option_conflict(vm, THRESHOLD, "links");
|
||||
segmentation_option_conflict(vm, THRESHOLD, "clustering");
|
||||
segmentation_option_conflict(vm, THRESHOLD, "levels");
|
||||
|
||||
segmentation_option_conflict(vm, PYR_MEAN_SHIFT, "marker");
|
||||
segmentation_option_conflict(vm, PYR_MEAN_SHIFT, "thresh");
|
||||
segmentation_option_dependency(vm, PYR_MEAN_SHIFT, "maxlevel");
|
||||
segmentation_option_dependency(vm, PYR_MEAN_SHIFT, "radius");
|
||||
segmentation_option_conflict(vm, PYR_MEAN_SHIFT, "links");
|
||||
segmentation_option_conflict(vm, PYR_MEAN_SHIFT, "clustering");
|
||||
segmentation_option_conflict(vm, PYR_MEAN_SHIFT, "levels");
|
||||
|
||||
segmentation_option_conflict(vm, PYR_SEGMENTATION, "marker");
|
||||
segmentation_option_conflict(vm, PYR_SEGMENTATION, "thresh");
|
||||
segmentation_option_conflict(vm, PYR_SEGMENTATION, "maxlevel");
|
||||
segmentation_option_conflict(vm, PYR_SEGMENTATION, "radius");
|
||||
segmentation_option_dependency(vm, PYR_SEGMENTATION, "links");
|
||||
segmentation_option_dependency(vm, PYR_SEGMENTATION, "clustering");
|
||||
|
||||
// correct pParam and nImages for certain panorama types
|
||||
if (ptype == fbr::PANNINI && pParam == 0) {
|
||||
pParam = 1;
|
||||
if(nImages < 3) nImages = 3;
|
||||
}
|
||||
if (ptype == fbr::STEREOGRAPHIC && pParam == 0) {
|
||||
pParam = 2;
|
||||
if(nImages < 3) nImages = 3;
|
||||
}
|
||||
if (ptype == fbr::RECTILINEAR && nImages < 3) {
|
||||
nImages = 3;
|
||||
}
|
||||
|
||||
// add trailing slash to directory if not present yet
|
||||
if (dir[dir.length()-1] != '/') dir = dir + "/";
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieve a cv::Mat with x,y,z,r from a scan object
|
||||
* functionality borrowed from scan_cv::convertScanToMat but this function
|
||||
* does not allow a scanserver to be used, prints to stdout and can only
|
||||
* handle a single scan
|
||||
*/
|
||||
cv::Mat scan2mat(Scan *source)
|
||||
{
|
||||
DataXYZ xyz = source->get("xyz");
|
||||
DataReflectance xyz_reflectance = source->get("reflectance");
|
||||
unsigned int nPoints = xyz.size();
|
||||
cv::Mat scan(nPoints,1,CV_32FC(4));
|
||||
scan = cv::Scalar::all(0);
|
||||
cv::MatIterator_<cv::Vec4f> it;
|
||||
it = scan.begin<cv::Vec4f>();
|
||||
for(unsigned int i = 0; i < nPoints; i++){
|
||||
float x, y, z, reflectance;
|
||||
x = xyz[i][0];
|
||||
y = xyz[i][1];
|
||||
z = xyz[i][2];
|
||||
reflectance = xyz_reflectance[i];
|
||||
|
||||
//normalize the reflectance
|
||||
reflectance += 32;
|
||||
reflectance /= 64;
|
||||
reflectance -= 0.2;
|
||||
reflectance /= 0.3;
|
||||
if (reflectance < 0) reflectance = 0;
|
||||
if (reflectance > 1) reflectance = 1;
|
||||
|
||||
(*it)[0] = x;
|
||||
(*it)[1] = y;
|
||||
(*it)[2] = z;
|
||||
(*it)[3] = reflectance;
|
||||
|
||||
++it;
|
||||
}
|
||||
return scan;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert a matrix of float values (range image) to a matrix of unsigned
|
||||
* eight bit characters using different techniques
|
||||
*/
|
||||
cv::Mat float2uchar(cv::Mat &source, bool logarithm, float cutoff)
|
||||
{
|
||||
cv::Mat result(source.size(), CV_8U, cv::Scalar::all(0));
|
||||
float max = 0;
|
||||
// find maximum value
|
||||
if (cutoff == 0.0) {
|
||||
// without cutoff, just iterate through all values to find the largest
|
||||
for (cv::MatIterator_<float> it = source.begin<float>();
|
||||
it != source.end<float>(); ++it) {
|
||||
float val = *it;
|
||||
if (val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// when a cutoff is specified, sort all the points by value and then
|
||||
// specify the max so that <cutoff> values are larger than it
|
||||
vector<float> sorted(source.cols*source.rows);
|
||||
int i = 0;
|
||||
for (cv::MatIterator_<float> it = source.begin<float>();
|
||||
it != source.end<float>(); ++it, ++i) {
|
||||
sorted[i] = *it;
|
||||
}
|
||||
std::sort(sorted.begin(), sorted.end());
|
||||
max = sorted[(int)(source.cols*source.rows*(1.0-cutoff))];
|
||||
cout << "A cutoff of " << cutoff << " resulted in a max value of " << max << endl;
|
||||
}
|
||||
|
||||
cv::MatIterator_<float> src = source.begin<float>();
|
||||
cv::MatIterator_<uchar> dst = result.begin<uchar>();
|
||||
cv::MatIterator_<float> end = source.end<float>();
|
||||
if (logarithm) {
|
||||
// stretch values from 0 to max logarithmically over 0 to 255
|
||||
// using the logarithm allows to represent smaller values with more
|
||||
// precision and larger values with less
|
||||
max = log(max+1);
|
||||
for (; src != end; ++src, ++dst) {
|
||||
float val = (log(*src+1)*255.0)/max;
|
||||
if (val > 255)
|
||||
*dst = 255;
|
||||
else
|
||||
*dst = (uchar)val;
|
||||
}
|
||||
} else {
|
||||
// stretch values from 0 to max linearly over 0 to 255
|
||||
for (; src != end; ++src, ++dst) {
|
||||
float val = (*src*255.0)/max;
|
||||
if (val > 255)
|
||||
*dst = 255;
|
||||
else
|
||||
*dst = (uchar)val;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* from grayscale image, create a binary image using a fixed threshold
|
||||
*/
|
||||
cv::Mat calculateThreshold(vector<vector<cv::Vec3f>> &segmented_points,
|
||||
cv::Mat &img, vector<vector<vector<cv::Vec3f> > > extendedMap,
|
||||
double thresh)
|
||||
{
|
||||
int i, j, idx;
|
||||
cv::Mat res;
|
||||
cv::threshold(img, res, thresh, 255, cv::THRESH_BINARY);
|
||||
segmented_points.resize(2);
|
||||
|
||||
for (i = 0; i < res.rows; i++) {
|
||||
for (j = 0; j < res.cols; j++) {
|
||||
idx = res.at<uchar>(i,j);
|
||||
if (idx != 0)
|
||||
idx = 1;
|
||||
segmented_points[idx].insert(segmented_points[idx].end(),
|
||||
extendedMap[i][j].begin(),
|
||||
extendedMap[i][j].end());
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate the pyramid mean shift segmentation of the image
|
||||
*/
|
||||
cv::Mat calculatePyrMeanShift(vector<vector<cv::Vec3f>> &segmented_points,
|
||||
cv::Mat &img, vector<vector<vector<cv::Vec3f> > > extendedMap,
|
||||
int maxlevel, int radius)
|
||||
{
|
||||
int i, j, idx;
|
||||
cv::Mat imgGray, res, tmp;
|
||||
cvtColor(img, imgGray, CV_GRAY2BGR);
|
||||
cv::pyrMeanShiftFiltering(imgGray, tmp, radius, radius, maxlevel);
|
||||
cvtColor(tmp, res, CV_BGR2GRAY);
|
||||
|
||||
// some colors will be empty
|
||||
// fill histogram first and then pick those entries that are not empty
|
||||
vector<vector<cv::Vec3f>> histogram(256);
|
||||
|
||||
for (i = 0; i < res.rows; i++) {
|
||||
for (j = 0; j < res.cols; j++) {
|
||||
idx = res.at<uchar>(i,j);
|
||||
histogram[idx].insert(histogram[idx].end(),
|
||||
extendedMap[i][j].begin(),
|
||||
extendedMap[i][j].end());
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (!histogram[i].empty()) {
|
||||
segmented_points.push_back(histogram[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
///TODO: need to pass *two* thresh params, see: http://bit.ly/WmFeub
|
||||
cv::Mat calculatePyrSegmentation(vector<vector<cv::Vec3f>> &segmented_points,
|
||||
cv::Mat &img, vector<vector<vector<cv::Vec3f> > > extendedMap,
|
||||
double thresh1, double thresh2, int pyrlevels)
|
||||
{
|
||||
int i, j, idx;
|
||||
int block_size = 1000;
|
||||
IplImage ipl_img = img;
|
||||
IplImage* ipl_original = &ipl_img;
|
||||
IplImage* ipl_segmented = 0;
|
||||
|
||||
CvMemStorage* storage = cvCreateMemStorage(block_size);
|
||||
CvSeq* comp = NULL;
|
||||
|
||||
// the following lines are required because the level must not be more
|
||||
// than log2(min(width, height))
|
||||
ipl_original->width &= -(1<<pyrlevels);
|
||||
ipl_original->height &= -(1<<pyrlevels);
|
||||
|
||||
ipl_segmented = cvCloneImage( ipl_original );
|
||||
|
||||
// apply the pyramid segmentation algorithm
|
||||
cvPyrSegmentation(ipl_original, ipl_segmented, storage, &comp, pyrlevels, thresh1+1, thresh2+1);
|
||||
|
||||
// mapping of color value to component id
|
||||
map<int, int> mapping;
|
||||
unsigned int segments = comp->total;
|
||||
for (unsigned int cur_seg = 0; cur_seg < segments; ++cur_seg) {
|
||||
CvConnectedComp* cc = (CvConnectedComp*) cvGetSeqElem(comp, cur_seg);
|
||||
// since images are single-channel grayscale, only the first value is
|
||||
// of interest
|
||||
mapping.insert(pair<int, int>(cc->value.val[0], cur_seg));
|
||||
}
|
||||
|
||||
segmented_points.resize(segments);
|
||||
|
||||
uchar *data = (uchar *)ipl_segmented->imageData;
|
||||
int step = ipl_segmented->widthStep;
|
||||
for (i = 0; i < ipl_segmented->height; i++) {
|
||||
for (j = 0; j < ipl_segmented->width; j++) {
|
||||
idx = mapping[data[i*step+j]];
|
||||
segmented_points[idx].insert(segmented_points[idx].end(),
|
||||
extendedMap[i][j].begin(),
|
||||
extendedMap[i][j].end());
|
||||
}
|
||||
}
|
||||
|
||||
// clearing memory
|
||||
cvReleaseMemStorage(&storage);
|
||||
|
||||
cv::Mat res(ipl_segmented);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate the adaptive threshold
|
||||
*/
|
||||
cv::Mat calculateAdaptiveThreshold(vector<vector<cv::Vec3f>> &segmented_points,
|
||||
cv::Mat &img, vector<vector<vector<cv::Vec3f> > > extendedMap)
|
||||
{
|
||||
int i, j, idx;
|
||||
cv::Mat res;
|
||||
cv::adaptiveThreshold(img, res, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 49, 5);
|
||||
segmented_points.resize(2);
|
||||
|
||||
for (i = 0; i < res.rows; i++) {
|
||||
for (j = 0; j < res.cols; j++) {
|
||||
idx = res.at<uchar>(i,j);
|
||||
if (idx != 0)
|
||||
idx = 1;
|
||||
segmented_points[idx].insert(segmented_points[idx].end(),
|
||||
extendedMap[i][j].begin(),
|
||||
extendedMap[i][j].end());
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* using a marker image, calculate the watershed segmentation
|
||||
* a marker image can be created from the panorama retrieved by using the
|
||||
* --dump-pano option
|
||||
*/
|
||||
cv::Mat calculateWatershed(vector<vector<cv::Vec3f>> &segmented_points,
|
||||
string &marker, cv::Mat &img, vector<vector<vector<cv::Vec3f> > > extendedMap)
|
||||
{
|
||||
int i, j, idx;
|
||||
cv::Mat markerMask = cv::imread(marker, 0);
|
||||
vector<vector<cv::Point> > contours;
|
||||
vector<cv::Vec4i> hierarchy;
|
||||
cv::findContours(markerMask, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
|
||||
if (contours.empty())
|
||||
throw std::runtime_error("empty marker mask");
|
||||
cv::Mat markers(markerMask.size(), CV_32S);
|
||||
markers = cv::Scalar::all(0);
|
||||
int compCount = 0;
|
||||
for (int idx = 0; idx >= 0; idx = hierarchy[idx][0], compCount++ )
|
||||
cv::drawContours(markers, contours, idx,
|
||||
cv::Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX);
|
||||
if (compCount == 0)
|
||||
throw std::runtime_error("no component found");
|
||||
cv::Mat imgGray;
|
||||
cvtColor(img, imgGray, CV_GRAY2BGR);
|
||||
cv::watershed(imgGray, markers);
|
||||
|
||||
segmented_points.resize(compCount);
|
||||
|
||||
for (i = 0; i < markers.rows; i++) {
|
||||
for (j = 0; j < markers.cols; j++) {
|
||||
idx = markers.at<int>(i,j);
|
||||
if (idx > 0 && idx <= compCount) {
|
||||
segmented_points[idx-1].insert(segmented_points[idx-1].end(),
|
||||
extendedMap[i][j].begin(),
|
||||
extendedMap[i][j].end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return markers;
|
||||
}
|
||||
|
||||
/*
|
||||
* given a vector of segmented 3d points, write them out as uos files
|
||||
*/
|
||||
void write3dfiles(vector<vector<cv::Vec3f>> &segmented_points, string &segdir)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
vector<ofstream*> outfiles(segmented_points.size());
|
||||
for (i = 0; i < segmented_points.size(); i++) {
|
||||
std::stringstream outfilename;
|
||||
outfilename << segdir << "/scan" << std::setw(3) << std::setfill('0') << i << ".3d";
|
||||
outfiles[i] = new ofstream(outfilename.str());
|
||||
}
|
||||
|
||||
for (i = 0; i < segmented_points.size(); i++) {
|
||||
for (vector<cv::Vec3f>::iterator it=segmented_points[i].begin() ;
|
||||
it < segmented_points[i].end();
|
||||
it++) {
|
||||
(*(outfiles[i])) << (*it)[0] << " " << (*it)[1] << " " << (*it)[2] << endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < segmented_points.size(); i++) {
|
||||
outfiles[i]->close();
|
||||
}
|
||||
}
|
||||
|
||||
// write .pose files
|
||||
// .frames files can later be generated from them using ./bin/pose2frames
|
||||
void writeposefiles(int num, string &segdir, const double* rPos, const double* rPosTheta)
|
||||
{
|
||||
for (int i = 0; i < num; i++) {
|
||||
std::stringstream posefilename;
|
||||
posefilename << segdir << "/scan" << std::setw(3) << std::setfill('0') << i << ".pose";
|
||||
ofstream posefile(posefilename.str());
|
||||
posefile << rPos[0] << " " << rPos[1] << " " << rPos[2] << endl;
|
||||
posefile << deg(rPosTheta[0]) << " "
|
||||
<< deg(rPosTheta[1]) << " "
|
||||
<< deg(rPosTheta[2]) << endl;
|
||||
posefile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void createdirectory(string segdir)
|
||||
{
|
||||
int success = mkdir(segdir.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
|
||||
if (success == 0 || errno == EEXIST) {
|
||||
cout << "Writing segmentations to " << segdir << endl;
|
||||
} else {
|
||||
cerr << "Creating directory " << segdir << " failed" << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// commandline arguments
|
||||
int start, end;
|
||||
bool scanserver;
|
||||
image_type itype;
|
||||
int width, height;
|
||||
int maxDist, minDist;
|
||||
int nImages, pParam;
|
||||
fbr::projection_method ptype;
|
||||
bool logarithm;
|
||||
float cutoff;
|
||||
string dir;
|
||||
IOType iotype;
|
||||
segment_method stype;
|
||||
string marker;
|
||||
bool dump_pano, dump_seg;
|
||||
double thresh;
|
||||
int maxlevel, radius;
|
||||
double pyrlinks, pyrcluster;
|
||||
int pyrlevels;
|
||||
|
||||
parse_options(argc, argv, start, end, scanserver, itype, width, height,
|
||||
ptype, dir, iotype, maxDist, minDist, nImages, pParam, logarithm,
|
||||
cutoff, stype, marker, dump_pano, dump_seg, thresh, maxlevel,
|
||||
radius, pyrlinks, pyrcluster, pyrlevels);
|
||||
|
||||
Scan::openDirectory(scanserver, dir, iotype, start, end);
|
||||
|
||||
if(Scan::allScans.size() == 0) {
|
||||
cerr << "No scans found. Did you use the correct format?" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cv::Mat img, res;
|
||||
string segdir;
|
||||
|
||||
for(ScanVector::iterator it = Scan::allScans.begin(); it != Scan::allScans.end(); ++it) {
|
||||
Scan* scan = *it;
|
||||
|
||||
// apply optional filtering
|
||||
scan->setRangeFilter(maxDist, minDist);
|
||||
|
||||
// create target directory
|
||||
segdir = dir + "segmented" + scan->getIdentifier();
|
||||
createdirectory(segdir);
|
||||
|
||||
// create panorama
|
||||
fbr::panorama fPanorama(width, height, ptype, nImages, pParam, fbr::EXTENDED);
|
||||
fPanorama.createPanorama(scan2mat(scan));
|
||||
|
||||
if (itype == M_RANGE) {
|
||||
// the range image has to be converted from float to uchar
|
||||
img = fPanorama.getRangeImage();
|
||||
img = float2uchar(img, logarithm, cutoff);
|
||||
} else {
|
||||
// intensity image
|
||||
img = fPanorama.getReflectanceImage();
|
||||
}
|
||||
|
||||
// output panorama image
|
||||
if (dump_pano)
|
||||
imwrite(segdir+"/panorama.png", img);
|
||||
|
||||
// will store the result of the segmentation
|
||||
vector<vector<cv::Vec3f>> segmented_points;
|
||||
|
||||
if (stype == THRESHOLD) {
|
||||
res = calculateThreshold(segmented_points, img, fPanorama.getExtendedMap(), thresh);
|
||||
} else if (stype == PYR_MEAN_SHIFT) {
|
||||
res = calculatePyrMeanShift(segmented_points, img, fPanorama.getExtendedMap(),
|
||||
maxlevel, radius);
|
||||
} else if (stype == PYR_SEGMENTATION) {
|
||||
res = calculatePyrSegmentation(segmented_points, img, fPanorama.getExtendedMap(), pyrlinks, pyrcluster, pyrlevels);
|
||||
} else if (stype == ADAPTIVE_THRESHOLD) {
|
||||
res = calculateAdaptiveThreshold(segmented_points, img, fPanorama.getExtendedMap());
|
||||
} else if (stype == WATERSHED) {
|
||||
res = calculateWatershed(segmented_points, marker, img, fPanorama.getExtendedMap());
|
||||
}
|
||||
|
||||
// output segmentation image
|
||||
if (dump_seg)
|
||||
imwrite(segdir+"/segmentation.png", res);
|
||||
|
||||
// write .3d and .pose files
|
||||
write3dfiles(segmented_points, segdir);
|
||||
writeposefiles(segmented_points.size(), segdir, scan->get_rPos(), scan->get_rPosTheta());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Point Cloud Segmentation using Felzenszwalb-Huttenlocher Algorithm
|
||||
*
|
||||
* Copyright (C) Jacobs University Bremen
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
* @author Mihai-Cotizo Sima
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __FHGRAPH_H_
|
||||
#define __FHGRAPH_H_
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include <slam6d/point.h>
|
||||
#include <slam6d/scan.h>
|
||||
#include <segmentation/segment-graph.h>
|
||||
#include <ANN/ANN.h>
|
||||
|
||||
class FHGraph {
|
||||
public:
|
||||
FHGraph(std::vector< Point >& ps, double weight(Point, Point), double sigma, double eps, int neighbors, float radius);
|
||||
edge* getGraph();
|
||||
Point operator[](int index);
|
||||
int getNumPoints();
|
||||
int getNumEdges();
|
||||
|
||||
void dispose();
|
||||
private:
|
||||
void compute_neighbors(double weight(Point, Point), double eps);
|
||||
void do_gauss(double sigma);
|
||||
void without_gauss();
|
||||
|
||||
std::vector<edge> edges;
|
||||
std::vector<Point>& points;
|
||||
int V;
|
||||
int E;
|
||||
|
||||
int nr_neighbors;
|
||||
float radius;
|
||||
|
||||
|
||||
struct he{ int x; float w; };
|
||||
std::vector< std::list<he> > adjency_list;
|
||||
};
|
||||
|
||||
#endif
|
1250
.svn/pristine/f3/f3e9f1b6c337fbc37530de57024eb510574a0af0.svn-base
Normal file
1250
.svn/pristine/f3/f3e9f1b6c337fbc37530de57024eb510574a0af0.svn-base
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,36 @@
|
|||
FIND_PACKAGE(OpenCV REQUIRED)
|
||||
|
||||
SET(FBR_IO_SRC scan_cv.cc)
|
||||
add_library(fbr_cv_io STATIC ${FBR_IO_SRC})
|
||||
|
||||
SET(FBR_PANORAMA_SRC panorama.cc)
|
||||
#add_library(fbr_panorama STATIC ${FBR_PANORAMA_SRC})
|
||||
add_library(fbr_panorama STATIC ${FBR_PANORAMA_SRC} fbr_global.cc)
|
||||
|
||||
|
||||
SET(FBR_FEATURE_SRC feature.cc)
|
||||
add_library(fbr_feature STATIC ${FBR_FEATURE_SRC})
|
||||
|
||||
SET(FBR_FEATURE_MATCHER_SRC feature_matcher.cc)
|
||||
add_library(fbr_feature_matcher STATIC ${FBR_FEATURE_MATCHER_SRC})
|
||||
|
||||
SET(FBR_REGISTRATION_SRC registration.cc)
|
||||
add_library(fbr_registration STATIC ${FBR_REGISTRATION_SRC})
|
||||
|
||||
SET(FBR_SRC scan_cv.cc panorama.cc feature.cc feature_matcher.cc registration.cc fbr_global.cc)
|
||||
add_library(fbr STATIC ${FBR_SRC})
|
||||
|
||||
IF(WITH_FBR)
|
||||
SET(FBR_LIBS scan ANN ${OpenCV_LIBS})
|
||||
|
||||
add_executable(featurebasedregistration feature_based_registration.cc fbr_global.cc)
|
||||
#target_link_libraries(featurebasedregistration fbr_cv_io fbr_panorama fbr_feature fbr_feature_matcher fbr_registration ${FBR_LIBS})
|
||||
target_link_libraries(featurebasedregistration fbr ${FBR_LIBS})
|
||||
ENDIF(WITH_FBR)
|
||||
|
||||
### EXPORT SHARED LIBS
|
||||
|
||||
IF(EXPORT_SHARED_LIBS)
|
||||
add_library(fbr_s SHARED ${FBR_SRC})
|
||||
target_link_libraries(fbr_s scan ANN ${OpenCV_LIBS})
|
||||
ENDIF(EXPORT_SHARED_LIBS)
|
|
@ -0,0 +1,420 @@
|
|||
cmake_minimum_required (VERSION 2.8.2)
|
||||
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdparty/CMakeModules" ${CMAKE_MODULE_PATH})
|
||||
project (Slam6D)
|
||||
|
||||
#include_directories(OPENGL_INCLUDE_DIR)
|
||||
IF(WIN32)
|
||||
set(Boost_USE_STATIC_LIBS TRUE)
|
||||
ELSE(WIN32)
|
||||
set(Boost_USE_STATIC_LIBS FALSE)
|
||||
ENDIF(WIN32)
|
||||
|
||||
SET(Boost_ADDITIONAL_VERSIONS "1.42" "1.42.0" "1.44" "1.44.0" "1.45.0" "1.45" "1.46" "1.46.1" "1.47.0" "1.47" "1.48" "1.49")
|
||||
IF(WIN32)
|
||||
# for some unknown reason no one variant works on all windows platforms
|
||||
find_package( Boost COMPONENTS serialization graph regex filesystem system thread date_time REQUIRED)
|
||||
ELSE(WIN32)
|
||||
find_package( Boost COMPONENTS serialization graph regex filesystem system thread date_time REQUIRED)
|
||||
ENDIF(WIN32)
|
||||
|
||||
if(Boost_FOUND)
|
||||
link_directories(${BOOST_LIBRARY_DIRS})
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
#################################################
|
||||
# Declare Options and modify build accordingly ##
|
||||
#################################################
|
||||
|
||||
## FreeGLUT
|
||||
OPTION(WITH_FREEGLUT "Whether freeglut is available. This enables iterative drawing in show. ON/OFF" ON)
|
||||
|
||||
IF(WITH_FREEGLUT)
|
||||
MESSAGE(STATUS "With freeglut")
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_FREEGLUT")
|
||||
ELSE(WITH_FREEGLUT)
|
||||
MESSAGE(STATUS "Without freeglut")
|
||||
ENDIF(WITH_FREEGLUT)
|
||||
|
||||
## Show
|
||||
OPTION(WITH_SHOW "Whether to build Show. This is the Visualization program of slam6d. ON/OFF" ON)
|
||||
|
||||
IF(WITH_SHOW)
|
||||
FIND_PACKAGE(OpenGL REQUIRED)
|
||||
FIND_PACKAGE(GLUT REQUIRED)
|
||||
MESSAGE(STATUS "With show")
|
||||
ELSE(WITH_SHOW)
|
||||
# SET (WITH_OCTREE_DISPLAY "ON" CACHE INTERNAL "" FORCE)
|
||||
MESSAGE(STATUS "Without show")
|
||||
ENDIF(WITH_SHOW)
|
||||
|
||||
## WXShow
|
||||
OPTION(WITH_WXSHOW "Whether to build WXShow. This is the wxwidgets variant of Show. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_WXSHOW)
|
||||
FIND_PACKAGE(OpenGL REQUIRED)
|
||||
FIND_PACKAGE(GLUT REQUIRED)
|
||||
find_package(wxWidgets COMPONENTS core base gl REQUIRED)
|
||||
# set wxWidgets_wxrc_EXECUTABLE to be ignored in the configuration
|
||||
SET (wxWidgets_wxrc_EXECUTABLE " " CACHE INTERNAL "" FORCE)
|
||||
# wxWidgets include (this will do all the magic to configure everything)
|
||||
include( ${wxWidgets_USE_FILE})
|
||||
MESSAGE(STATUS "With wxshow")
|
||||
ELSE(WITH_XWSHOW)
|
||||
MESSAGE(STATUS "Without wxshow")
|
||||
ENDIF(WITH_WXSHOW)
|
||||
|
||||
## Shapes
|
||||
OPTION(WITH_SHAPE_DETECTION "Whether to build shapes and planes executable for detecting planes. ON/OFF" OFF)
|
||||
IF(WITH_SHAPE_DETECTION)
|
||||
MESSAGE(STATUS "With shape detection")
|
||||
ELSE(WITH_SHAPE_DETECTION)
|
||||
MESSAGE(STATUS "Without shape detection")
|
||||
ENDIF(WITH_SHAPE_DETECTION)
|
||||
|
||||
## Interior reconstruction
|
||||
option(WITH_MODEL "Whether to build model executable for modelling interior environments. ON/OFF" OFF)
|
||||
|
||||
if(WITH_MODEL)
|
||||
message(STATUS "With interior reconstruction")
|
||||
else(WITH_MODEL)
|
||||
message(STATUS "Without interior reconstruction")
|
||||
endif(WITH_MODEL)
|
||||
|
||||
## Thermo
|
||||
OPTION(WITH_THERMO "Whether to build executables for mutual calibration of laser scanner and camera. ON/OFF" OFF)
|
||||
IF(WITH_THERMO)
|
||||
FIND_PACKAGE(OpenCV REQUIRED)
|
||||
add_subdirectory(3rdparty/cvblob)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/cvblob)
|
||||
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/cvblob)
|
||||
MESSAGE(STATUS "With thermo")
|
||||
ELSE(WITH_THERMO)
|
||||
MESSAGE(STATUS "Without thermo")
|
||||
ENDIF(WITH_THERMO)
|
||||
|
||||
## Octree
|
||||
OPTION(WITH_OCTREE_DISPLAY "Whether to use octree display for efficiently culling scans ON/OFF" ON)
|
||||
|
||||
IF(WITH_OCTREE_DISPLAY)
|
||||
MESSAGE(STATUS "Using octree display")
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_GL_POINTS")
|
||||
ELSE(WITH_OCTREE_DISPLAY)
|
||||
MESSAGE(STATUS "Using displaylists: Warning potentially much slower")
|
||||
ENDIF(WITH_OCTREE_DISPLAY)
|
||||
#SET (WITH_OCTREE_DISPLAY ${WITH_OCTREE_DISPLAY} CACHE BOOL
|
||||
#"Whether to use octree display for efficiently culling scans ON/OFF" FORCE)
|
||||
|
||||
|
||||
## Octree
|
||||
OPTION(WITH_COMPACT_OCTREE "Whether to use the compact octree display ON/OFF" OFF)
|
||||
|
||||
IF(WITH_COMPACT_OCTREE)
|
||||
MESSAGE(STATUS "Using compact octrees")
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_COMPACT_TREE")
|
||||
ELSE(WITH_COMPACT_OCTREE)
|
||||
MESSAGE(STATUS "Not using compact octreees: Warning uses more memory")
|
||||
ENDIF(WITH_COMPACT_OCTREE)
|
||||
|
||||
## Glee?
|
||||
OPTION(WITH_GLEE "Whether to use OpenGL extensions, requires glee. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_GLEE)
|
||||
MESSAGE(STATUS "Using opengl extensions")
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_GLEE")
|
||||
ELSE(WITH_GLEE)
|
||||
MESSAGE(STATUS "Not using opengl extensions")
|
||||
ENDIF(WITH_GLEE)
|
||||
|
||||
## Gridder
|
||||
OPTION(WITH_GRIDDER "Whether to build the 2DGridder binary ON/OFF" OFF)
|
||||
|
||||
IF(WITH_GRIDDER)
|
||||
MESSAGE(STATUS "With 2DGridder")
|
||||
ELSE(WITH_GRIDDER)
|
||||
MESSAGE(STATUS "Without 2DGridder")
|
||||
ENDIF(WITH_GRIDDER)
|
||||
|
||||
## Dynamic VELOSLAM
|
||||
OPTION(WITH_VELOSLAM "Whether to build the Velodyne data processing (veloslam/veloshow) ON/OFF" OFF)
|
||||
|
||||
IF(WITH_VELOSLAM)
|
||||
MESSAGE(STATUS "With VELOSLAM")
|
||||
ELSE(WITH_VELOSLAM)
|
||||
MESSAGE(STATUS "Without VELOSLAM")
|
||||
ENDIF(WITH_VELOSLAM)
|
||||
|
||||
## Home-made Laserscanner
|
||||
OPTION(WITH_DAVID_3D_SCANNER "Whether to build the David scanner app for homemade laser scanners binary ON/OFF" OFF)
|
||||
|
||||
IF(WITH_DAVID_3D_SCANNER)
|
||||
MESSAGE(STATUS "With David scanner")
|
||||
ELSE(WITH_DAVID_3D_SCANNER)
|
||||
MESSAGE(STATUS "Without David scanner")
|
||||
ENDIF(WITH_DAVID_3D_SCANNER)
|
||||
|
||||
## Tools
|
||||
|
||||
OPTION(WITH_TOOLS "Whether to build additional tools like convergence frame_to_graph etc. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_TOOLS)
|
||||
MESSAGE(STATUS "With Tools")
|
||||
ELSE(WITH_TOOLS)
|
||||
MESSAGE(STATUS "Without Tools")
|
||||
ENDIF(WITH_TOOLS)
|
||||
|
||||
## Segmentation
|
||||
|
||||
OPTION(WITH_SEGMENTATION "Whether to build scan segmantion program ON/OFF" OFF)
|
||||
|
||||
IF(WITH_SEGMENTATION)
|
||||
MESSAGE(STATUS "With segmentation")
|
||||
find_package (Boost COMPONENTS program_options REQUIRED)
|
||||
ELSE(WITH_SEGMENTATION)
|
||||
MESSAGE(STATUS "Without segmentation")
|
||||
ENDIF(WITH_SEGMENTATION)
|
||||
|
||||
## CAD matching
|
||||
OPTION (WITH_CAD "Wether to build with CAD import lib ON/OFF" OFF)
|
||||
|
||||
IF (WITH_CAD)
|
||||
MESSAGE (STATUS "With CAD import")
|
||||
find_package (Boost COMPONENTS program_options filesystem REQUIRED)
|
||||
ELSE (WITH_CAD)
|
||||
MESSAGE (STATUS "Without CAD import")
|
||||
ENDIF (WITH_CAD)
|
||||
|
||||
## RivLib
|
||||
OPTION(WITH_RIVLIB "Whether the RIEGL rivlib is present ON/OFF" OFF)
|
||||
|
||||
IF(WITH_RIVLIB)
|
||||
MESSAGE(STATUS "Compiling a scan IO for RXP files")
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty)
|
||||
link_directories(${CMAKE_SOURCE_DIR}/3rdparty)
|
||||
SET(RIEGL_DIR ${CMAKE_SOURCE_DIR}/3rdparty/riegl/)
|
||||
IF(WIN32)
|
||||
SET(RIVLIB ${RIEGL_DIR}libscanlib-mt.lib ${RIEGL_DIR}libctrllib-mt.lib ${RIEGL_DIR}libboost_system-mt-1_43_0-vns.lib)
|
||||
ELSE(WIN32)
|
||||
SET(RIVLIB ${RIEGL_DIR}libscanlib-mt-s.a ${RIEGL_DIR}libctrllib-mt-s.a ${RIEGL_DIR}libboost_system-mt-s-1_43_0-vns.a pthread)
|
||||
ENDIF(WIN32)
|
||||
FIND_PACKAGE(LibXml2 )
|
||||
|
||||
ELSE(WITH_RIVLIB)
|
||||
MESSAGE(STATUS "Do NOT compile a scan IO for RXP")
|
||||
ENDIF(WITH_RIVLIB)
|
||||
|
||||
## CUDA support, TODO depend on CUDA_FIND
|
||||
OPTION(WITH_CUDA "Compile with CUDA support" OFF)
|
||||
IF(WITH_CUDA)
|
||||
MESSAGE(STATUS "Compiling WITH CUDA support")
|
||||
FIND_PACKAGE(CUDA)
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_CUDA")
|
||||
ELSE(WITH_CUDA)
|
||||
MESSAGE(STATUS "Compiling WITHOUT CUDA support")
|
||||
ENDIF(WITH_CUDA)
|
||||
|
||||
## PMD
|
||||
OPTION(WITH_PMD "Whether to build the PMD tools like grabVideoAnd3D calibrate etc. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_PMD)
|
||||
FIND_PACKAGE(OpenGL REQUIRED)
|
||||
MESSAGE(STATUS "With Tools")
|
||||
ELSE(WITH_PMD)
|
||||
MESSAGE(STATUS "Without Tools")
|
||||
ENDIF(WITH_PMD)
|
||||
|
||||
## FBR
|
||||
OPTION(WITH_FBR "Whether to compile feature based registration. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_FBR)
|
||||
MESSAGE(STATUS "With FBR ")
|
||||
ELSE(WITH_FBR)
|
||||
MESSAGE(STATUS "Without FBR")
|
||||
ENDIF(WITH_FBR)
|
||||
|
||||
## Special treatment for system specifics
|
||||
IF(APPLE)
|
||||
add_definitions(-Dfopen64=fopen)
|
||||
ENDIF(APPLE)
|
||||
|
||||
## Multiple Cores
|
||||
IF(APPLE)
|
||||
SET(PROCESSOR_COUNT 2)
|
||||
ELSE(APPLE)
|
||||
INCLUDE(CountProcessors)
|
||||
SET(NUMBER_OF_CPUS "${PROCESSOR_COUNT}" CACHE STRING "The number of processors to use (default: ${PROCESSOR_COUNT})" )
|
||||
ENDIF(APPLE)
|
||||
|
||||
# OPEN
|
||||
FIND_PACKAGE(OpenMP)
|
||||
IF(OPENMP_FOUND)
|
||||
OPTION(WITH_OPENMP "Whether to use parallel processing capabilities of OPENMP. ON/OFF" ON)
|
||||
ENDIF(OPENMP_FOUND)
|
||||
|
||||
IF(OPENMP_FOUND AND WITH_OPENMP)
|
||||
MESSAGE(STATUS "With OpenMP ")
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAX_OPENMP_NUM_THREADS=${NUMBER_OF_CPUS} -DOPENMP_NUM_THREADS=${NUMBER_OF_CPUS} ${OpenMP_CXX_FLAGS} -DOPENMP")
|
||||
ELSE(OPENMP_FOUND AND WITH_OPENMP)
|
||||
MESSAGE(STATUS "Without OpenMP")
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAX_OPENMP_NUM_THREADS=1 -DOPENMP_NUM_THREADS=1")
|
||||
ENDIF(OPENMP_FOUND AND WITH_OPENMP)
|
||||
|
||||
## TORO
|
||||
OPTION(WITH_TORO "Whether to use TORO. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_TORO)
|
||||
IF(WIN32)
|
||||
SET(Subversion_SVN_EXECUTABLE "svn.exe")
|
||||
ENDIF(WIN32)
|
||||
cmake_minimum_required (VERSION 2.8)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(toro3d
|
||||
SVN_REPOSITORY https://www.openslam.org/data/svn/toro/trunk
|
||||
SOURCE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/toro"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND make
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND cp ${CMAKE_SOURCE_DIR}/3rdparty/toro/toro3d ${CMAKE_SOURCE_DIR}/bin/
|
||||
)
|
||||
MESSAGE(STATUS "With TORO ")
|
||||
ELSE(WITH_TORO)
|
||||
MESSAGE(STATUS "Without TORO")
|
||||
ENDIF(WITH_TORO)
|
||||
|
||||
|
||||
## HOGMAN
|
||||
OPTION(WITH_HOGMAN "Whether to use HOGMAN. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_HOGMAN)
|
||||
# dependant on libqt4-devi
|
||||
find_package( Qt4 REQUIRED)
|
||||
# CMake of earlier versions do not have external project capabilities
|
||||
cmake_minimum_required (VERSION 2.8)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(hogman
|
||||
SVN_REPOSITORY https://svn.openslam.org/data/svn/hog-man/trunk
|
||||
SOURCE_DIR "${CMAKE_SOURCE_DIR}/3rdparty/hogman"
|
||||
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR>
|
||||
BUILD_COMMAND LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib make
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/bin/hogman3d ${CMAKE_SOURCE_DIR}/bin/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_csparse.so ${CMAKE_SOURCE_DIR}/lib/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_graph_optimizer_hogman.so ${CMAKE_SOURCE_DIR}/lib/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_graph_optimizer.so ${CMAKE_SOURCE_DIR}/lib/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_graph.so ${CMAKE_SOURCE_DIR}/lib/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_graph_viewer.so ${CMAKE_SOURCE_DIR}/lib/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_math.so ${CMAKE_SOURCE_DIR}/lib/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_qglviewer.so ${CMAKE_SOURCE_DIR}/lib/ &&
|
||||
cp ${CMAKE_SOURCE_DIR}/3rdparty/hogman/lib/libhogman_stuff.so ${CMAKE_SOURCE_DIR}/lib/
|
||||
)
|
||||
MESSAGE(STATUS "With HOGMAN: Currently hogman needs to be compiled manually, please make sure hogman3d is somewhere in your PATH")
|
||||
ELSE(WITH_HOGMAN)
|
||||
MESSAGE(STATUS "Without HOGMAN")
|
||||
ENDIF(WITH_HOGMAN)
|
||||
|
||||
OPTION(EXPORT_SHARED_LIBS "Whether to build additional shared libraries for use in other projects. ON/OFF" OFF)
|
||||
|
||||
IF(EXPORT_SHARED_LIBS)
|
||||
MESSAGE(STATUS "exporting additional libraries")
|
||||
ELSE(EXPORT_SHARED_LIBS)
|
||||
MESSAGE(STATUS "not exporting libraries")
|
||||
ENDIF(EXPORT_SHARED_LIBS)
|
||||
|
||||
OPTION(WITH_METRICS "Whether to use metrics in slam6d. ON/OFF" OFF)
|
||||
|
||||
IF(WITH_METRICS)
|
||||
MESSAGE(STATUS "With metrics in slam6d.")
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_METRICS")
|
||||
ELSE(WITH_METRICS)
|
||||
MESSAGE(STATUS "Without metrics in slam6d.")
|
||||
ENDIF(WITH_METRICS)
|
||||
|
||||
IF(WIN32)
|
||||
SET(ADDITIONAL_CFLAGS "-O2" CACHE STRING"Additional flags given to the compiler ()" )
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/windows/)
|
||||
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/windows)
|
||||
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/windows/x64)
|
||||
add_library(XGetopt STATIC ${CMAKE_SOURCE_DIR}/3rdparty/windows/XGetopt.cpp)
|
||||
SET(CMAKE_STATIC_LIBRARY_SUFFIX "32.lib")
|
||||
ELSE(WIN32)
|
||||
SET(ADDITIONAL_CFLAGS "-O3 -std=c++0x -msse3 -Wall -finline-functions -Wno-unused-but-set-variable -Wno-write-strings -Wno-char-subscripts -Wno-unused-result" CACHE STRING"Additional flags given to the compiler (-O3 -Wall -finline-functions -Wno-write-strings)" )
|
||||
# Add include path for OpenGL without GL/-prefix
|
||||
# to avoid the include incompatibility between MACOS
|
||||
# and linux
|
||||
FIND_PATH(OPENGL_INC gl.h /usr/include/GL)
|
||||
include_directories(${OPENGL_INC})
|
||||
ENDIF(WIN32)
|
||||
|
||||
# Add OpenGL includes for MACOS if needed
|
||||
# The OSX OpenGL frameworks natively supports freeglut extensions
|
||||
IF(APPLE)
|
||||
include_directories(/System/Library/Frameworks/GLUT.framework/Headers)
|
||||
include_directories(/System/Library/Frameworks/OpenGL.framework/Headers)
|
||||
ENDIF(APPLE)
|
||||
|
||||
SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ADDITIONAL_CFLAGS}")
|
||||
|
||||
# Hide CMake variables
|
||||
SET (CMAKE_INSTALL_PREFIX "/usr/local" CACHE INTERNAL "" FORCE)
|
||||
SET (CMAKE_BUILD_TYPE "" CACHE INTERNAL "" FORCE)
|
||||
|
||||
|
||||
# Set output directories for libraries and executables
|
||||
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib )
|
||||
SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/obj )
|
||||
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin )
|
||||
|
||||
# Set include and link dirs ...
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/glui)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/wxthings/include/)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/ann_1.1.1_modified/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/ann_1.1.1_modified/src)
|
||||
link_directories(${CMAKE_SOURCE_DIR}/obj)
|
||||
link_directories(${CMAKE_SOURCE_DIR}/lib)
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(src/slam6d)
|
||||
add_subdirectory(src/scanio)
|
||||
add_subdirectory(src/scanserver)
|
||||
add_subdirectory(src/segmentation)
|
||||
add_subdirectory(src/veloslam)
|
||||
add_subdirectory(src/show)
|
||||
add_subdirectory(src/grid)
|
||||
add_subdirectory(src/pmd)
|
||||
add_subdirectory(src/shapes)
|
||||
add_subdirectory(src/thermo)
|
||||
IF(WITH_FBR)
|
||||
add_subdirectory(src/slam6d/fbr)
|
||||
ENDIF(WITH_FBR)
|
||||
add_subdirectory(src/scanner)
|
||||
add_subdirectory(src/model)
|
||||
|
||||
IF(EXPORT_SHARED_LIBS)
|
||||
## Compiling a shared library containing all of the project
|
||||
add_library(slam SHARED src/slam6d/icp6D.cc)
|
||||
target_link_libraries(slam scan_s ANN_s sparse_s newmat_s show_s fbr_s)
|
||||
ENDIF(EXPORT_SHARED_LIBS)
|
||||
|
||||
MESSAGE (STATUS "Build environment is set up!")
|
||||
|
||||
|
||||
# hack to "circumvent" Debug and Release folders that are created under visual studio
|
||||
# this is why the INSTALL target has to be used in visual studio
|
||||
IF(MSVC)
|
||||
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/bin/Release/ CONFIGURATIONS Release DESTINATION ${CMAKE_SOURCE_DIR}/windows FILES_MATCHING PATTERN "*.dll" PATTERN "*.exe")
|
||||
IF( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/3rdparty/windows/x64/ CONFIGURATIONS Release DESTINATION ${CMAKE_SOURCE_DIR}/windows FILES_MATCHING PATTERN "*.dll" PATTERN "*.exe")
|
||||
ELSE( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/3rdparty/windows/ CONFIGURATIONS Release DESTINATION ${CMAKE_SOURCE_DIR}/windows FILES_MATCHING PATTERN "*.dll" PATTERN "*.exe")
|
||||
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
|
||||
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/bin/Debug/ CONFIGURATIONS Debug DESTINATION ${CMAKE_SOURCE_DIR}/windows FILES_MATCHING PATTERN "*.dll" PATTERN "*.exe")
|
||||
IF( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/3rdparty/windows/x64/ CONFIGURATIONS Debug DESTINATION ${CMAKE_SOURCE_DIR}/windows FILES_MATCHING PATTERN "*.dll" PATTERN "*.exe")
|
||||
ELSE( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/3rdparty/windows/ CONFIGURATIONS Debug DESTINATION ${CMAKE_SOURCE_DIR}/windows FILES_MATCHING PATTERN "*.dll" PATTERN "*.exe")
|
||||
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
ENDIF(MSVC)
|
|
@ -0,0 +1,11 @@
|
|||
IF(WITH_SEGMENTATION)
|
||||
add_executable(scan2segments scan2segments.cc ../slam6d/fbr/fbr_global.cc)
|
||||
add_executable(fhsegmentation fhsegmentation.cc FHGraph.cc disjoint-set.cc segment-graph.cc)
|
||||
|
||||
FIND_PACKAGE(OpenCV REQUIRED)
|
||||
|
||||
target_link_libraries(scan2segments scan ANN fbr_cv_io fbr_panorama fbr_feature fbr_feature_matcher fbr_registration ${Boost_LIBRARIES} ${OpenCV_LIBS})
|
||||
target_link_libraries(fhsegmentation scan ANN ${Boost_LIBRARIES} ${OpenCV_LIBS})
|
||||
|
||||
|
||||
ENDIF(WITH_SEGMENTATION)
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* kdMeta implementation
|
||||
*
|
||||
* Copyright (C) Andreas Nuechter, Kai Lingemann, Thomas Escher
|
||||
*
|
||||
* Released under the GPL version 3.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief An optimized k-d tree implementation. MetaScan variant.
|
||||
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
* @author Thomas Escher. Institute of Computer Science, University of Osnabrueck, Germany.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include "slam6d/kdMeta.h"
|
||||
#include "slam6d/globals.icc"
|
||||
#include "slam6d/scan.h"
|
||||
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
#include <algorithm>
|
||||
using std::swap;
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
// KDtree class static variables
|
||||
template<class PointData, class AccessorData, class AccessorFunc>
|
||||
KDParams KDTreeImpl<PointData, AccessorData, AccessorFunc>::params[MAX_OPENMP_NUM_THREADS];
|
||||
|
||||
KDtreeMetaManaged::KDtreeMetaManaged(const vector<Scan*>& scans) :
|
||||
m_count_locking(0)
|
||||
{
|
||||
// create scan pointer and data pointer arrays
|
||||
m_size = scans.size();
|
||||
m_scans = new Scan*[m_size];
|
||||
for(unsigned int i = 0; i < m_size; ++i)
|
||||
m_scans[i] = scans[i];
|
||||
m_data = new DataXYZ*[m_size];
|
||||
|
||||
lock();
|
||||
create(m_data, prepareTempIndices(scans), getPointsSize(scans));
|
||||
unlock();
|
||||
|
||||
// allocate in prepareTempIndices, deleted here
|
||||
delete[] m_temp_indices;
|
||||
}
|
||||
|
||||
KDtreeMetaManaged::~KDtreeMetaManaged()
|
||||
{
|
||||
delete[] m_scans;
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
Index* KDtreeMetaManaged::prepareTempIndices(const vector<Scan*>& scans)
|
||||
{
|
||||
unsigned int n = getPointsSize(scans);
|
||||
|
||||
m_temp_indices = new Index[n];
|
||||
unsigned int s = 0, j = 0;
|
||||
unsigned int scansize = scans[s]->size<DataXYZ>("xyz reduced");
|
||||
for(unsigned int i = 0; i < n; ++i) {
|
||||
m_temp_indices[i].set(s, j++);
|
||||
// switch to next scan
|
||||
if(j >= scansize) {
|
||||
++s;
|
||||
j = 0;
|
||||
if(s < scans.size())
|
||||
scansize = scans[s]->size<DataXYZ>("xyz reduced");
|
||||
}
|
||||
}
|
||||
return m_temp_indices;
|
||||
}
|
||||
|
||||
unsigned int KDtreeMetaManaged::getPointsSize(const vector<Scan*>& scans)
|
||||
{
|
||||
unsigned int n = 0;
|
||||
for(vector<Scan*>::const_iterator it = scans.begin(); it != scans.end(); ++it) {
|
||||
n += (*it)->size<DataXYZ>("xyz reduced");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
double* KDtreeMetaManaged::FindClosest(double *_p, double maxdist2, int threadNum) const
|
||||
{
|
||||
params[threadNum].closest = 0;
|
||||
params[threadNum].closest_d2 = maxdist2;
|
||||
params[threadNum].p = _p;
|
||||
_FindClosest(m_data, threadNum);
|
||||
return params[threadNum].closest;
|
||||
}
|
||||
|
||||
void KDtreeMetaManaged::lock()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(m_mutex_locking);
|
||||
if(m_count_locking == 0) {
|
||||
// lock all the contained scans, metascan uses the transformed points
|
||||
for(unsigned int i = 0; i < m_size; ++i) {
|
||||
m_data[i] = new DataXYZ(m_scans[i]->get("xyz reduced"));
|
||||
}
|
||||
}
|
||||
++m_count_locking;
|
||||
}
|
||||
|
||||
void KDtreeMetaManaged::unlock()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(m_mutex_locking);
|
||||
--m_count_locking;
|
||||
if(m_count_locking == 0) {
|
||||
// delete each locking object
|
||||
for(unsigned int i = 0; i < m_size; ++i) {
|
||||
delete m_data[i];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glut.h>
|
||||
#elif __APPLE__
|
||||
#include <GLUT/glut.h>
|
||||
#include <OpenGl/glu.h>
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#include <GL/glu.h>
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifndef __VIEWCULL_H__
|
||||
#define __VIEWCULL_H__
|
||||
namespace show{
|
||||
|
||||
///////////////////////// Variable declarations...
|
||||
/** The 6 planes of the viewing frustum */
|
||||
extern float frustum[6][4];
|
||||
|
||||
/** the modelview * projection matrix to map a model point to an onscreen coordinate */
|
||||
extern float matrix[16];
|
||||
/** some useful variables for faster calculation of the pixel coordinates */
|
||||
extern short VP[4];
|
||||
/** a unit vector pointing to the right of the screen */
|
||||
extern float right[3];
|
||||
/** how much detail is shown, 0 means everything is plotted */
|
||||
extern short DETAIL;
|
||||
|
||||
extern double SX, SY, SZ, EX, EY, EZ;
|
||||
extern float origin[3], dir[3]; /*ray */
|
||||
extern float dist;
|
||||
extern int rayX,rayY;
|
||||
extern float rayVP[4];
|
||||
|
||||
#define NUMDIM 3
|
||||
#define RIGHT 0
|
||||
#define LEFT 1
|
||||
#define MIDDLE 2
|
||||
|
||||
extern float minB[NUMDIM], maxB[NUMDIM]; /*box */
|
||||
extern float coord[NUMDIM]; /* hit point */
|
||||
|
||||
|
||||
template <class T> bool HitBoundingBox(const T center[3], T size )
|
||||
{
|
||||
minB[0] = center[0] - size;
|
||||
minB[1] = center[1] - size;
|
||||
minB[2] = center[2] - size;
|
||||
|
||||
maxB[0] = center[0] + size;
|
||||
maxB[1] = center[1] + size;
|
||||
maxB[2] = center[2] + size;
|
||||
|
||||
bool inside = true;
|
||||
char quadrant[NUMDIM];
|
||||
register int i;
|
||||
int whichPlane;
|
||||
float maxT[NUMDIM];
|
||||
float candidatePlane[NUMDIM];
|
||||
|
||||
// Find candidate planes; this loop can be avoided if
|
||||
// rays cast all from the eye(assume perpsective view)
|
||||
for (i=0; i<NUMDIM; i++)
|
||||
if(origin[i] < minB[i]) {
|
||||
quadrant[i] = LEFT;
|
||||
candidatePlane[i] = minB[i];
|
||||
inside = false;
|
||||
}else if (origin[i] > maxB[i]) {
|
||||
quadrant[i] = RIGHT;
|
||||
candidatePlane[i] = maxB[i];
|
||||
inside = false;
|
||||
}else {
|
||||
candidatePlane[i] = 0.0;
|
||||
quadrant[i] = MIDDLE;
|
||||
}
|
||||
|
||||
// Ray origin inside bounding box
|
||||
if(inside) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
// Calculate T distances to candidate planes
|
||||
for (i = 0; i < NUMDIM; i++)
|
||||
if (quadrant[i] != MIDDLE && dir[i] !=0.)
|
||||
maxT[i] = (candidatePlane[i]-origin[i]) / dir[i];
|
||||
else
|
||||
maxT[i] = -1.;
|
||||
|
||||
// Get largest of the maxT's for final choice of intersection
|
||||
whichPlane = 0;
|
||||
for (i = 1; i < NUMDIM; i++)
|
||||
if (maxT[whichPlane] < maxT[i])
|
||||
whichPlane = i;
|
||||
|
||||
// Check final candidate actually inside box
|
||||
if (maxT[whichPlane] < 0.) return (false);
|
||||
for (i = 0; i < NUMDIM; i++)
|
||||
if (whichPlane != i) {
|
||||
coord[i] = origin[i] + maxT[whichPlane] *dir[i];
|
||||
if (coord[i] < minB[i] || coord[i] > maxB[i])
|
||||
return (false);
|
||||
} else {
|
||||
coord[i] = candidatePlane[i];
|
||||
}
|
||||
return (true); // ray hits box
|
||||
}
|
||||
|
||||
void calcRay(int x, int y, double znear, double zfar);
|
||||
|
||||
#include <float.h>
|
||||
template <class T>
|
||||
float RayDist(T *point)
|
||||
{
|
||||
return point[0] * dir[0] + point[1] * dir[1] + point[2] * dir[2] - dist;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
short ScreenDist(T *point) {
|
||||
float pn[3];
|
||||
// x coordinate on screen, not normalized
|
||||
pn[0] = point[0] * matrix[0] + point[1] * matrix[4] + point[2] * matrix[8] + matrix[12];
|
||||
pn[1] = point[0] * matrix[1] + point[1] * matrix[5] + point[2] * matrix[9] + matrix[13];
|
||||
// normalization
|
||||
pn[2] = point[0] * matrix[3] + point[1] * matrix[7] + point[2] * matrix[11] + matrix[15];
|
||||
|
||||
// normalized x coordinate on screen
|
||||
pn[0] /= pn[2];
|
||||
pn[1] /= pn[2];
|
||||
|
||||
// true x coordinate in viewport coordinate system
|
||||
//Xi = pn[0]*VP[0] + VP[1];
|
||||
//fTempo[4]*0.5+0.5)*viewport[2]+viewport[0];
|
||||
|
||||
float XX = ( (pn[0])*rayVP[0] + rayVP[1]);
|
||||
float YY = ( (pn[1])*rayVP[2] + rayVP[3]);
|
||||
|
||||
short dx, dy;
|
||||
if (XX > rayX) dx = XX-rayX;
|
||||
else dx = rayX-XX;
|
||||
|
||||
if (YY > rayY) dy = YY-rayY;
|
||||
else dy = rayY-YY;
|
||||
|
||||
// for the benefit of visual studio's compiler cast to float
|
||||
return sqrt((float)(dx*dx + dy*dy));
|
||||
}
|
||||
|
||||
void ExtractFrustum(short detail);
|
||||
void ExtractFrustum(float *frust[6]);
|
||||
|
||||
|
||||
bool CubeInFrustum( float x, float y, float z, float size );
|
||||
int CubeInFrustum2( float x, float y, float z, float size );
|
||||
char PlaneAABB( float x, float y, float z, float size, float *plane );
|
||||
|
||||
void remViewport();
|
||||
bool LOD(float x, float y, float z, float size);
|
||||
int LOD2(float x, float y, float z, float size);
|
||||
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue