You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1251 lines
33 KiB
C++

/*
* hough implementation
*
* Copyright (C) Dorit Borrmann, Jan Elseberg, Kai Lingemann, Andreas Nuechter, Remus Dumitru
*
* Released under the GPL version 3.
*
*/
#include "newmat/newmatap.h"
using namespace NEWMAT;
#include "shapes/hough.h"
#include "slam6d/globals.icc"
#include <math.h>
#include <time.h>
#include <limits>
#include "shapes/quadtree.h"
#include <errno.h>
#include <iterator>
#ifdef _MSC_VER
#include <windows.h>
#include <direct.h>
#else
#include <dlfcn.h>
#endif
#include <sys/stat.h>
/**
* Hough Constructor.
* Loads the Configfile, located in "bin/hough.cfg" and initializes the
* accumulator. For details about the implemented Hough methods please read:
*
* Dorit Borrmann, Jan Elseberg, Kai Lingemann, and Andreas Nüchter. The 3D
* Hough Transform for Plane Detection in Point Clouds - A Review and A new
* Accumulator Design, Journal 3D Research, Springer, Volume 2, Number 2,
* March 2011.
*/
Hough::Hough(bool q, std::string configFile)
{
quiet = q;
// If the user has specified a configFile, load it
if(configFile.size() > 0) {
myConfigFileHough.LoadCfg(configFile.c_str());
if (!quiet) {
std::cout << "Loaded Configfile" << std::endl;
myConfigFileHough.ShowConfiguration();
}
}
}
Hough::Hough(Scan * GlobalScan, bool q, std::string configFile)
{
quiet = q;
if(configFile.size() > 0) {
myConfigFileHough.LoadCfg(configFile.c_str());
if(!quiet) {
std::cout << "Loaded Configfile" << std::endl;
myConfigFileHough.ShowConfiguration();
}
}
SetScan(GlobalScan);
}
void Hough::SetScan(Scan* scan)
{
nrEntries = 0;
maximum = false;
planeCounter = 0;
allPoints = new vector<Point>();
DataXYZ points_red = scan->get("xyz reduced");
for(unsigned int i = 0; i < points_red.size(); i++)
{
Point p(points_red[i]);
allPoints->push_back(p);
}
switch(myConfigFileHough.Get_AccumulatorType()) {
case 0:
acc = new AccumulatorSimple(myConfigFileHough);
break;
case 1:
acc = new AccumulatorBall(myConfigFileHough);
break;
case 2:
acc = new AccumulatorCube(myConfigFileHough);
break;
case 3:
acc = new AccumulatorBallI(myConfigFileHough);
break;
}
srand(time(0)); // make the results actually random
//srand(0); // make the results repeatable
}
/**
* Desctructor.
*/
Hough::~Hough() {
if(out.is_open()) {
out.flush();
out.close();
}
for(vector<ConvexPlane*>::iterator it = planes.begin();
it != planes.end(); it++) {
ConvexPlane* tmp = (*it);
delete tmp;
}
delete acc;
delete allPoints;
}
/**
* Randomized Hough Transform
*/
int Hough::RHT() {
if (!quiet) cout << "RHT" << endl;
Point p1, p2, p3;
double theta, phi, rho;
int planeSize = 2000;
unsigned int stop = (unsigned int)(allPoints->size()/100.0)*myConfigFileHough.Get_MinSizeAllPoints();
int plane = 1;
long start, end;
start = GetCurrentTimeInMilliSec();
int counter = 0;
while( allPoints->size() > stop &&
planes.size() < (unsigned int)myConfigFileHough.Get_MaxPlanes() &&
counter < (int)myConfigFileHough.Get_TrashMax()) {
unsigned int pint = (int) (((*allPoints).size())*(rand()/(RAND_MAX+1.0)));
p1 = (*allPoints)[pint];
pint = (int) (((*allPoints).size())*(rand()/(RAND_MAX+1.0)));
p2 = (*allPoints)[pint];
pint = (int) (((*allPoints).size())*(rand()/(RAND_MAX+1.0)));
p3 = (*allPoints)[pint];
// check distance
if(!distanceOK(p1, p2, p3)) continue;
//cout << "Distance OK" << endl;
// calculate Plane
if(calculatePlane(p1, p2, p3, theta, phi, rho)) {
// increment accumulator cell
if(acc->accumulate(theta, phi, rho)) {
end = GetCurrentTimeInMilliSec() - start;
start = GetCurrentTimeInMilliSec();
if (!quiet) cout << "Time for RHT " << plane << ": " << end << endl;
double * n = acc->getMax(rho, theta, phi);
if (!quiet) cout << rho << " " << theta << " " << phi << endl;
planeSize = deletePoints(n, rho);
delete[] n;
if (!quiet) cout << "Delete Points done " << plane << endl;
if(planeSize < (int)myConfigFileHough.Get_MinPlaneSize()) counter++;
end = GetCurrentTimeInMilliSec() - start;
start = GetCurrentTimeInMilliSec();
if(!quiet) cout << "Time for Polygonization " << plane << ": " << end << endl;
acc->resetAccumulator();
plane++;
if(!quiet) cout << "Planes " << planes.size() << endl;
}
}
}
/*
vector<Point>::iterator itr = allPoints->begin();
Point p;
start = GetCurrentTimeInMilliSec();
while(itr != allPoints->end()) {
p = *(itr);
cout << p.x << " " << p.y << " " << p.z << endl;
itr++;
}
*/
return (int)planes.size();
}
/**
* Standard Hough Transform
*/
void Hough::SHT() {
vector<Point>::iterator itr = allPoints->begin();
Point p;
long start, end;
start = GetCurrentTimeInMilliSec();
while(itr != allPoints->end()) {
p = *(itr);
acc->accumulate(p);
itr++;
}
end = GetCurrentTimeInMilliSec() - start;
start = GetCurrentTimeInMilliSec();
if (!quiet) cout << "Time for SHT: " << end << endl;
if(myConfigFileHough.Get_PeakWindow()) {
acc->peakWindow(myConfigFileHough.Get_WindowSize());
}
multiset<int*, maxcompare>* maxlist = acc->getMax();
multiset<int*, maxcompare>::iterator it = maxlist->begin();
int threshold = ((*it)[0] * myConfigFileHough.Get_PlaneRatio());
unsigned int stop = (int)(allPoints->size()/100.0)*myConfigFileHough.Get_MinSizeAllPoints();
while(it != maxlist->end() &&
stop < allPoints->size() &&
planes.size() < (unsigned int)myConfigFileHough.Get_MaxPlanes() &&
(*it)[0] > threshold) {
int* tmp = (*it);
double * polar = acc->getMax(tmp);
deletePoints(polar, polar[3]);
delete[] polar;
it++;
}
if (!quiet) cout << "Time for Polygonization: " << end << endl;
it = maxlist->begin();
for(;it != maxlist->end(); it++) {
int* tmp = (*it);
delete[] tmp;
}
delete maxlist;
}
/**
* Function that returns all the remaining points in the allPoints vector.
* @return points that do not lie on an already detected plane
*/
double * const* Hough::getPoints(int &size) {
size = allPoints->size();
double ** returnPoints = new double*[allPoints->size()];
for(unsigned int i = 0; i < allPoints->size(); i++) {
Point p = (*allPoints)[i];
returnPoints[i] = new double[3];
returnPoints[i][0] = p.x;
returnPoints[i][1] = p.y;
returnPoints[i][2] = p.z;
}
return returnPoints;
}
/**
* Deletes all points that lie on a list of planes.
* @param model the list of planes
* @param size the number of remaining points after delete operation
* @return the remaining points
*/
double * const* Hough::deletePoints(vector<ConvexPlane*> &model, int &size) {
for(unsigned int i = 0; i < model.size(); i++) {
deletePoints(model[i]->n, model[i]->rho);
}
double ** returnPoints = new double*[allPoints->size()];
for(unsigned int i = 0; i < allPoints->size(); i++) {
Point p = (*allPoints)[i];
returnPoints[i] = new double[3];
returnPoints[i][0] = p.x;
returnPoints[i][1] = p.y;
returnPoints[i][2] = p.z;
}
size = allPoints->size();
return returnPoints;
}
/**
* Probabilistic Hough Transform
*/
void Hough::PHT() {
unsigned int stop =
(int)(allPoints->size()/100.0)*myConfigFileHough.Get_MinSizeAllPoints();
bool *voted = new bool[allPoints->size()];
for(unsigned int i = 0; i < allPoints->size(); i++) {
voted[i] = false;
}
unsigned int i = 0;
while(i < stop && planes.size() < (unsigned int)myConfigFileHough.Get_MaxPlanes()) {
unsigned int pint = (int) (((*allPoints).size())*(rand()/(RAND_MAX+1.0)));
if(!voted[i]) {
Point p = (*allPoints)[pint];
acc->accumulate(p);
i++;
}
}
// List of Maxima
if(myConfigFileHough.Get_PeakWindow()) {
acc->peakWindow(myConfigFileHough.Get_WindowSize());
}
multiset<int*, maxcompare>* maxlist = acc->getMax();
// cout << "Mean " << acc->mean() << endl;
// cout << "Variance " << acc->variance() << endl;
multiset<int*, maxcompare>::iterator it = maxlist->begin();
int threshold = ((*it)[0] * myConfigFileHough.Get_PlaneRatio());
while(it != maxlist->end() &&
stop < allPoints->size() &&
planes.size() < (unsigned int)myConfigFileHough.Get_MaxPlanes() &&
(*it)[0] > threshold) {
int* tmp = (*it);
double * tmp2 = acc->getMax(tmp);
deletePoints(tmp2, tmp2[3]);
delete [] tmp2;
it++;
}
it = maxlist->begin();
for(;it != maxlist->end(); it++) {
int* tmp = (*it);
delete[] tmp;
}
delete maxlist;
delete[] voted;
}
/**
* Progressive Probabilistic Hough Transform
*/
void Hough::PPHT() {
unsigned int stop =
(int)(allPoints->size()/100.0)*myConfigFileHough.Get_MinSizeAllPoints();
while(stop < allPoints->size() &&
planes.size() < (unsigned int)myConfigFileHough.Get_MaxPlanes()) {
bool *voted = new bool[allPoints->size()];
for(unsigned int i = 0; i < allPoints->size(); i++) {
voted[i] = false;
}
unsigned int pint;
do {
pint = (int) (((*allPoints).size())*(rand()/(RAND_MAX+1.0)));
Point p = (*allPoints)[pint];
if(!voted[pint]) {
double * angles = acc->accumulateRet(p);
if(angles[0] > -0.0001) {
double * n = polar2normal(angles[1], angles[2]);
deletePoints(n, angles[0]);
acc->resetAccumulator();
delete [] n;
} else {
voted[pint] = true;
}
delete [] angles;
}
} while(!voted[pint]);
delete[] voted;
}
}
/**
* Adaptive Probabilistic Hough Transform
*/
void Hough::APHT() {
int max = 0;
int maxpos = 0;
vector<int*> mergelist = vector<int*>();
int stability[20] = {0};
do {
//randomly select points and perform HT for them
vector<int*> altlist = mergelist;
mergelist = vector<int*>();
multiset<int*,valuecompare> maxlist = multiset<int*,valuecompare>();
for(int i = 0; i < 10; i++) {
unsigned int pint = (int) (((*allPoints).size())*(rand()/(RAND_MAX+1.0)));
Point p = (*allPoints)[pint];
int * max = acc->accumulateAPHT(p);
// store the maximum cell touched by the HT
maxlist.insert(max);
}
// merge active with previous list
multiset<int*,valuecompare>::iterator mi = maxlist.begin();
vector<int*>::iterator ai = altlist.begin();
int i = 0;
while(i < 20) {
bool mi_oder_ai = false;
if(ai == altlist.end()) {
if(mi == maxlist.end()) {
break;
} else {
mi_oder_ai = true;
}
} else if(mi == maxlist.end()) {
mi_oder_ai = false;
} else if((*mi)[0] <= (*ai[0])) {
mi_oder_ai = false;
} else {
mi_oder_ai = true;
}
int *tmp;
if(mi_oder_ai) {
tmp = (*mi);
mi++;
} else {
tmp = (*ai);
ai++;
}
bool insert = true;
for(vector<int*>::iterator it = mergelist.begin(); it != mergelist.end();
it++) {
if(myConfigFileHough.Get_AccumulatorType() != 2) {
if( sqrt(
((*it)[3] - (tmp[3])) * ((*it)[3] - (tmp[3])) +
((*it)[1] - (tmp[1])) * ((*it)[1] - (tmp[1])) +
((*it)[2] - (tmp[2])) * ((*it)[2] - (tmp[2])) ) < 3.0) {
insert = false;
break;
}
} else {
if( sqrt(
((*it)[4] - (tmp[4])) * ((*it)[4] - (tmp[4])) +
((*it)[1] - (tmp[1])) * ((*it)[1] - (tmp[1])) +
((*it)[2] - (tmp[2])) * ((*it)[2] - (tmp[2])) +
((*it)[3] - (tmp[3])) * ((*it)[3] - (tmp[3])) ) < 3.0) {
insert = false;
break;
}
}
}
if(insert) {
mergelist.push_back(tmp);
i++;
}
}
// compare lists, calculate stability
i = 0;
for(unsigned int i = 1; i < altlist.size(); i++) {
for(unsigned int j = 0; j < i; j++) {
int * tmp1 = mergelist[j];
bool treffer = false;
for(unsigned int k = 0; k < i; k++) {
int * tmp2 = altlist[k];
if(myConfigFileHough.Get_AccumulatorType() != 2) {
if( sqrt(
((tmp2)[3] - (tmp1[3])) * ((tmp2)[3] - (tmp1[3])) +
((tmp2)[1] - (tmp1[1])) * ((tmp2)[1] - (tmp1[1])) +
((tmp2)[2] - (tmp1[2])) * ((tmp2)[2] - (tmp1[2])) ) < 3.0) {
treffer = true;
break;
}
} else {
if( sqrt(
((tmp2)[4] - (tmp1[4])) * ((tmp2)[4] - (tmp1[4])) +
((tmp2)[1] - (tmp1[1])) * ((tmp2)[1] - (tmp1[1])) +
((tmp2)[2] - (tmp1[2])) * ((tmp2)[2] - (tmp1[2])) +
((tmp2)[3] - (tmp1[3])) * ((tmp2)[3] - (tmp1[3])) ) < 3.0) {
treffer = true;
break;
}
}
}
if(!treffer) {
stability[i-1] = -1;
break;
}
}
stability[i-1]++;
}
for(int i = mergelist.size(); i < 20; i++) {
stability[i] = 0;
}
// determine stability count,
// a set of n entries is considered to be stable, if all planes in the set
// are the maximal entries of the mergelist in this iteration and have also
// been the maximal entries in the previous iteration (the order in the set
// does not count). The stability count for a number n is the number of
// iterations for which the set of size n has been stable.
// The maximum stability count is the stability count for the size n, that
// is the maximum of all stability counts.
max = 0;
maxpos = 0;
for(int i = 0; i < 20; i++) {
if(stability[i] >= max) {
max = stability[i];
maxpos = i;
}
}
// repeat until maximum stability count exceeds a threshold
} while(max < (int)myConfigFileHough.Get_AccumulatorMax()
&& stability[myConfigFileHough.Get_MaxPlanes()] <
myConfigFileHough.Get_AccumulatorMax() * myConfigFileHough.Get_PlaneRatio()
);
if(stability[myConfigFileHough.Get_MaxPlanes()] >= myConfigFileHough.Get_AccumulatorMax() * myConfigFileHough.Get_PlaneRatio()) {
maxpos = myConfigFileHough.Get_MaxPlanes();
}
for(int i = 0; i <= maxpos; i++) {
double * n = acc->getMax(mergelist[i]);
deletePoints(n, n[3]);
delete[] n;
}
}
/**
* Verifies the distance criterion needed for the RHT. The distance between the
* three selected points may not exceed a maximal or fall below a minimal
* distance.
*/
bool Hough::distanceOK(Point p1, Point p2, Point p3) {
// p1 - p2
double distance = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) + (p1.z - p2.z) * (p1.z - p2.z);
if(sqrt(distance) < myConfigFileHough.Get_MinDist()) return false;
if(sqrt(distance) > myConfigFileHough.Get_MaxDist()) return false;
// p2 - p3
distance = (p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y) + (p3.z - p2.z) * (p3.z - p2.z);
if(sqrt(distance) < myConfigFileHough.Get_MinDist()) return false;
if(sqrt(distance) > myConfigFileHough.Get_MaxDist()) return false;
// p3 - p1
distance = (p1.x - p3.x) * (p1.x - p3.x) + (p1.y - p3.y) * (p1.y - p3.y) + (p1.z - p3.z) * (p1.z - p3.z);
if(sqrt(distance) < myConfigFileHough.Get_MinDist()) return false;
if(sqrt(distance) > myConfigFileHough.Get_MaxDist()) return false;
return true;
}
/**
* Calculates the polar coordinates (rho, theta, phi) of the plane spanned by
* three points p1, p2, and p3.
*/
bool Hough::calculatePlane(Point p1, Point p2, Point p3, double &theta, double &phi, double &rho) {
double v1[3];
double v2[3];
double n[3];
v1[0] = p3.x - p2.x;
v1[1] = p3.y - p2.y;
v1[2] = p3.z - p2.z;
v2[0] = p1.x - p2.x;
v2[1] = p1.y - p2.y;
v2[2] = p1.z - p2.z;
Cross(v1,v2,n);
if(sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]) < 0.000000001) return false;
Normalize3(n);
rho = p1.x * n[0] + p1.y * n[1] + p1.z * n[2];
if(rho < 0) {
rho = -rho;
for(int i = 0; i < 3; i++) {
n[i] = -n[i];
}
}
double polar[3];
toPolar(n, polar);
phi = polar[0];
theta = polar[1];
if((fabs(theta) < 0.001) && (fabs(phi) < 0.001) ) return false;
return true;
}
/**
* Improved function for point deletion.
*/
int Hough::deletePointsQuad(double * n, double rho) {
if (!quiet) cout << allPoints->size() ;
Normalize3(n);
vector<Point> *nallPoints = new vector<Point>();
vector<Point> planePoints;
out << n[0] << " " << n[1] << " " << n[2] << " " << rho << " ";
Point p;
vector<Point>::iterator itr = allPoints->begin();
while(itr != allPoints->end()) {
p = *(itr);
// if point close to plane, delete it
double distance = p.x * n[0] + p.y * n[1] + p.z*n[2] - rho;
if( fabs(distance) < myConfigFileHough.Get_MaxPointPlaneDist()) {
planePoints.push_back(p);
}
itr++;
}
double n2[4];
// calculating the best fit plane
calcPlane(planePoints, n2);
out << n2[0] << " " << n2[1] << " " << n2[2] << " " << n2[3] << " " ;
itr = allPoints->begin();
planePoints.clear();
while(itr != allPoints->end()) {
p = *(itr);
// if point close to plane, delete it
double distance = p.x * n2[0] + p.y * n2[1] + p.z*n2[2] - n2[3];
if( fabs(distance) < myConfigFileHough.Get_MaxPointPlaneDist()) {
planePoints.push_back(p);
} else {
nallPoints->push_back(p);
}
itr++;
}
delete allPoints;
allPoints = nallPoints;
if (!quiet) cout << "Planepoints " << planePoints.size() << endl;
int nr_points = planePoints.size();
// TODO Clustering
double min_angle = rad(1.0);
double _phi, _theta;
double **pppoints;
pppoints = new double*[nr_points];
for (unsigned int i = 0; i < planePoints.size(); i++) {
pppoints[i] = new double[3];
Point p(planePoints[i]);
double m[3];
m[0] = p.x;
m[1] = p.y;
m[2] = p.z;
Normalize3(m);
_phi = acos(m[2]);
double costheta = acos(m[0]/sin(_phi));
double sintheta = m[1]/sin(_phi);
double EPS = 0.0001;
if(fabs(sin(costheta) - sintheta) < EPS) {
_theta = costheta;
} else if(fabs( sin( 2*M_PI - costheta ) - sintheta ) < EPS) {
_theta = 2*M_PI - costheta;
} else {
_theta = 0;
cout << "Error JP" << endl;
}
pppoints[i][0] = _phi;
pppoints[i][1] = _theta;
pppoints[i][2] = sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
}
planePoints.clear();
QuadTree tree(pppoints, nr_points , 0.3, min_angle);
vector<set<double *> > cps;
cps = tree.getClusters();
unsigned int max_points = 0;
int index = -1;
for (unsigned int i = 0; i < cps.size(); i++) {
if (max_points < cps[i].size()) {
max_points = cps[i].size();
index = i;
}
}
for (unsigned int i = 0; i < cps.size(); i++) {
for (set<double *>::iterator it = cps[i].begin();
it != cps[i].end(); it++) {
Point p;
p.x = (*it)[2] * cos( (*it)[1] ) * sin( (*it)[0] );
p.y = (*it)[2] * sin( (*it)[1] ) * sin( (*it)[0] );
p.z = (*it)[2] * cos( (*it)[0] );
if ((int)i != index) {
allPoints->push_back(p);
} else {
planePoints.push_back(p);
}
}
}
double n4[4];
calcPlane(planePoints, n4);
ConvexPlane * plane1 = new ConvexPlane(n4, planePoints);
planes.push_back(plane1);
for (int i = 0; i < nr_points; i++) {
delete[] pppoints[i];
}
delete[] pppoints;
return max_points;
// ENDE
}
/**
* Deletes points from allPoints that lie on the given plane. All points from
* the biggest cluster on that plane are deleted. If the cluster is
* sufficiently planar, the convex hull is added to the result list.
*
* @param n normal vector of the plane
* @param rho distance between plane and origin
* @return the number of points in the deleted cluster plane
*/
int Hough::deletePoints(double * n, double rho) {
char direction = ' ';
Normalize3(n);
vector<Point> *nallPoints = new vector<Point>();
vector<Point> planePoints;
Point p;
vector<Point>::iterator itr = allPoints->begin();
while(itr != allPoints->end()) {
p = *(itr);
// if point close to plane, delete it
double distance = p.x * n[0] + p.y * n[1] + p.z*n[2] - rho;
if( fabs(distance) < myConfigFileHough.Get_MaxPointPlaneDist()) {
planePoints.push_back(p);
}
itr++;
}
double n2[4];
// calculating the best fit plane
double D = calcPlane(planePoints, n2);
bool nocluster = false;
if(D > myConfigFileHough.Get_MinPlanarity()) {
nocluster = true;
}
if(fabs(n2[0]) < fabs(n2[1])) {
if(fabs(n2[1]) < fabs(n2[2])) {
direction = 'z';
} else {
direction = 'y';
}
} else if (fabs(n2[2]) < fabs(n2[0])){
direction = 'x';
} else {
direction = 'z';
}
itr = allPoints->begin();
planePoints.clear();
vPtPair planePairs;
double minx, maxx, miny, maxy;
minx = 1000000;
miny = 1000000;
maxx = -1000000;
maxy= -1000000;
while(itr != allPoints->end()) {
p = *(itr);
// if point close to plane, delete it
double distance = p.x * n2[0] + p.y * n2[1] + p.z*n2[2] - n2[3];
if( fabs(distance) < myConfigFileHough.Get_MaxPointPlaneDist()) {
Point tmp, p2;
double distance = p.x * n2[0] + p.y * n2[1] + p.z*n2[2] - n2[3];
tmp.x = p.x - distance * n2[0];
tmp.y = p.y - distance * n2[1];
tmp.z = p.z - distance * n2[2];
switch(direction) {
case 'x': p2.x = tmp.y;
p2.y = tmp.z;
break;
case 'y': p2.x = tmp.x;
p2.y = tmp.z;
break;
case 'z': p2.x = tmp.x;
p2.y = tmp.y;
break;
default: cout << "OHOH" << endl;
}
p2.z = -1;
if(p2.x < minx) minx = p2.x;
if(p2.y < miny) miny = p2.y;
if(p2.x > maxx) maxx = p2.x;
if(p2.y > maxy) maxy = p2.y;
PtPair myPair(p,p2);
planePairs.push_back(myPair);
} else {
nallPoints->push_back(p);
}
itr++;
}
delete allPoints;
allPoints = nallPoints;
int region = -1;
if(planePairs.size() > 2) {
region = cluster(planePairs, minx, maxx, miny, maxy);
}
// delete points from this list
list< double*> point_list;
vPtPair::iterator vitr;
vector<Point> tmp_points;
for(vitr = planePairs.begin(); vitr != planePairs.end(); vitr++) {
// Case distinction x-z or x-y or y-z
p = (*vitr).p1;
Point p2 = (*vitr).p2;
if(fabs(p2.z - region) < 0.1) {
double * point = new double[2];
point[0] = p2.x;
point[1] = p2.y;
point_list.push_back(point);
tmp_points.push_back(p);
} else {
allPoints->push_back(p);
}
}
D = calcPlane(tmp_points, n2);
nocluster = false;
if(D > myConfigFileHough.Get_MinPlanarity()) {
nocluster = true;
}
unsigned int maxPlane = point_list.size();
// color points
unsigned char rgb[3];
for(int x = 0; x < 3; x++) {
rgb[x] = (unsigned char)((255)*(rand()/(RAND_MAX+1.0)));
}
for(itr = tmp_points.begin(); itr != tmp_points.end(); itr++) {
p = (*itr);
if(nocluster || maxPlane >= myConfigFileHough.Get_MinPlaneSize()) {
p.rgb[0] = 0;
p.rgb[1] = 0;
p.rgb[2] = 0;
} else {
p.rgb[0] = rgb[0];
p.rgb[1] = rgb[1];
p.rgb[2] = rgb[2];
}
coloredPoints.push_back(p);
}
tmp_points.clear();
if(nocluster || maxPlane < myConfigFileHough.Get_MinPlaneSize()) {
for(list<double* >::iterator it = point_list.begin();
it != point_list.end(); ) {
double* tmp = (*it);
it = point_list.erase(it);
delete[] tmp;
}
point_list.clear();
return maxPlane;
}
// If plane ok, calculate convex hull
vector<double *> convex_hull;
ConvexPlane::JarvisMarchConvexHull(point_list,convex_hull);
for(list<double* >::iterator it = point_list.begin();
it != point_list.end(); ) {
double* tmp = (*it);
it = point_list.erase(it);
delete[] tmp;
}
point_list.clear();
if(nocluster) {
for(vector<double* >::iterator it = convex_hull.begin();
it != convex_hull.end(); it++) {
double* tmp = (*it);
delete[] tmp;
}
return maxPlane;
}
ConvexPlane * plane1 = new ConvexPlane(n2, n2[3], direction, convex_hull);
plane1->pointsize = maxPlane;
planes.push_back(plane1);
if(!quiet) cout << "Points left " << allPoints->size() << "\n";
return maxPlane;
// ENDE
}
/**
* Clustering using Two-Pass algorithm
*/
int Hough::cluster(vPtPair &pairs, double minx, double maxx, double miny, double maxy) {
if(pairs.size() < 3) return -1;
vPtPair::iterator vitr;
vector<set<int> > linked;
double factor = myConfigFileHough.Get_PointDist();
int xlength = 1 + (maxx - minx) / factor;
int ylength = 1 + (maxy - miny) / factor;
vector< vector<int> > colors;
for(int i = 0; i < ylength; i++) {
vector<int> *tmp = new vector<int>;
colors.push_back(*tmp);
for(int j = 0; j < xlength; j++) {
colors[i].push_back(0);
}
delete tmp;
}
//int colors[ylength][xlength];
vector< vector<bool> > points;
for(int i = 0; i < ylength; i++) {
vector<bool> *tmp = new vector<bool>;
points.push_back(*tmp);
for(int j = 0; j < xlength; j++) {
points[i].push_back(false);
}
delete tmp;
}
int region = 0;
for(vitr = pairs.begin(); vitr != pairs.end(); vitr++) {
int x = (int)(((*vitr).p2.x - minx) / (maxx - minx) * xlength - 0.5);
int y = (int)(((*vitr).p2.y - miny) / (maxy - miny) * ylength - 0.5);
points[y][x] = true;
}
int up, left;
for(int y = 0; y < ylength; y++) {
for(int x = 0; x < xlength; x++) {
if(points[y][x]) {
if(x==0) {
left = 0;
} else {
left = colors[y][x-1];
}
if(y==0) {
up = 0;
} else {
up = colors[y-1][x];
}
if (left == 0) {
if (up == 0) {
colors[y][x] = ++region; // new region
set<int> joined;
joined.insert(region);
linked.push_back(joined);
} else {
colors[y][x] = up; // use upper region
}
} else if (up == 0) {
colors[y][x] = left; // use left region
} else {
colors[y][x] = up; // use upper region (left is the same)
if(left == up) {
continue;
}
else {
set<int> current;
set<int> joined;
joined.insert(up);
joined.insert(left);
for(vector<set<int> >::iterator itr = linked.begin(); itr != linked.end(); ) {
current = (*itr);
if(current.find(up) != current.end() || current.find(left) != current.end()) {
set<int> newjoined;
insert_iterator<set<int> > res_ins(newjoined, newjoined.begin());
set_union(joined.begin(), joined.end(), current.begin(), current.end(), res_ins);
joined.clear();
// delete joined;
joined = newjoined;
itr=linked.erase(itr);
} else {
itr++;
}
}
linked.push_back(joined);
}
}
}
}
}
int *counter = new int[region+1];
for(int i = 0; i <= region; i++) {
counter[i] = 0;
}
for(int y = 0; y < ylength; y++) {
for(int x = 0; x < xlength; x++) {
counter[colors[y][x]]++;
}
}
int *linkedindex = new int[linked.size()];
for(unsigned int i = 0; i < linked.size(); i++) {
linkedindex[i] = 0;
}
set<int> current;
for(unsigned int i = 0; i < linked.size(); i++) {
current = linked[i];
for(set<int>::iterator it = current.begin(); it != current.end(); it++) {
linkedindex[i] += counter[(*it)];
}
}
delete[] counter;
int maxindex = 0;
for(unsigned int i = 1; i < linked.size(); i++) {
if(linkedindex[i] > linkedindex[maxindex]) {
maxindex = i;
}
}
delete[] linkedindex;
set<int> max = linked[maxindex];
int zaehler = 0;
for(vitr = pairs.begin(); vitr != pairs.end(); vitr++) {
int x = (int)(((*vitr).p2.x - minx) / (maxx - minx) * xlength - 0.5);
int y = (int)(((*vitr).p2.y - miny) / (maxy - miny) * ylength - 0.5);
if(max.find(colors[y][x]) != max.end()) {
(*vitr).p2.z = maxindex;
zaehler++;
} else {
(*vitr).p2.z = -1;
}
}
/*
for(vector<set<int> >::iterator itr = linked.begin(); itr != linked.end(); ) {
set<>current = (*itr);
if(current.find(up) != current.end() || current.find(left) != current.end()) {
*/
return maxindex;
}
/**
* Writes <the convex hull of each detected plane to the directory given in the
* config file. Also writes a list of detected planes to the directory.
*/
int Hough::writePlanes(int startCount) {
int counter = startCount;
string blub = "";
blub = blub + myConfigFileHough.Get_PlaneDir();
#ifdef _MSC_VER
int success = mkdir(blub.c_str());
#else
int success = mkdir(blub.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
#endif
if(success != 0 && errno != EEXIST) {
cerr << "Creating directory " << blub << " failed" << endl;
return -1;
}
if(!quiet) cout << "Writing " << planes.size() << " Planes to " << blub << endl;
ofstream out;
string blub3 = blub + "/planes.list";
out.open(blub3.c_str());
for(vector<ConvexPlane*>::iterator it = planes.begin(); it != planes.end(); it++) {
string blub2 = blub + "/plane"+ to_string(counter,3) + ".3d";
out << "Plane " << blub2 << endl;
(*it)->writePlane(blub2, counter);
counter++;
}
out.close();
out.flush();
return (int)planes.size();
}
/**
* Writes the convex hull of each detected plane to a file.
*/
void Hough::writePlanes(std::string filePrefix)
{
int counter = 0;
if (!quiet) std::cout << "There are " << planes.size() << " planes." << std::endl;
for(vector<ConvexPlane*>::iterator it = planes.begin(); it != planes.end(); it++)
{
std::stringstream ss;
ss << filePrefix << "_" << counter << ".txt";
(*it)->writeNormal(ss.str(), counter);
//(*it)->writePlane(ss.str(), counter);
counter++;
}
}
/**
* Writes the remaining points from allPoints to the plane directory given in
* the config file.
*/
void Hough::writePlanePoints(string filename) {
ofstream out;
out.open(filename.c_str());
Point p;
vector<Point>::iterator itr = coloredPoints.begin();
while(itr != coloredPoints.end()) {
p = *(itr);
out << p.x << " " << p.y << " " << p.z << " " << (int)p.rgb[0] << " " << (int)(p.rgb[1]) << " " << (int)(p.rgb[2]) << endl;
itr++;
}
itr = allPoints->begin();
while(itr != allPoints->end()) {
p = *(itr);
out << p.x << " " << p.y << " " << p.z << " " << 255 << " " << 255 << " " << 255 << endl;
itr++;
}
out.close();
}
/**
* Writes the remaining points from allPoints to the plane directory given in
* the config file.
*/
void Hough::writeAllPoints(int index, vector<Point> points) {
string blub = "";
blub = blub + myConfigFileHough.Get_PlaneDir() + "/scans";
#ifdef _MSC_VER
int success = mkdir(blub.c_str());
#else
int success = mkdir(blub.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
#endif
if(success != 0 && errno != EEXIST) {
cerr << "Creating directory " << blub << " failed" << endl;
return;
}
blub = blub + "/scan" + to_string(index,3) + ".3d";
ofstream out;
out.open(blub.c_str());
Point p;
vector<Point>::iterator itr = points.begin();
while(itr != points.end()) {
p = *(itr);
out << p.x << " " << p.y << " " << p.z << " " << (int)p.rgb[0] << " " << (int)(p.rgb[1]) << " " << (int)(p.rgb[2]) << endl;
itr++;
}
out.close();
}
/**
* Given a set of points this function will calculate the best fit plane
* @param the set of points
* @param the plane description as normal vector and distance to origin
*/
double calcPlane(vector<Point> &ppoints, double plane[4]) {
SymmetricMatrix A(3);
A = 0;
int n;
n = ppoints.size();
if(n < 3) return 0;
double cx, cy, cz;
cx = 0.0;
cy = 0.0;
cz = 0.0;
for (int i = 0; i < n; i++) {
Point p = ppoints[i];
cx += p.x;
cy += p.y;
cz += p.z;
}
cx /= n;
cy /= n;
cz /= n;
for (int i = 0; i < n; i++) {
Point p = ppoints[i];
A(1, 1) += (p.x - cx)*(p.x - cx);
A(2, 2) += (p.y - cy)*(p.y - cy);
A(3, 3) += (p.z - cz)*(p.z - cz);
A(1, 2) += (p.x - cx)*(p.y - cy);
A(1, 3) += (p.x - cx)*(p.z - cz);
A(2, 3) += (p.y - cy)*(p.z - cz);
}
DiagonalMatrix D;
Matrix V;
try {
Jacobi(A,D,V);
} catch (ConvergenceException) {
cout << "couldn't find plane..." << endl;
return 0;
}
/*
cout << "A: "<< endl << A << endl;
cout << "D: "<< endl << D << endl;
cout << "V: "<< endl << V << endl;
*/
int index;
D.MinimumAbsoluteValue1(index);
plane[0] = V(1,index);
plane[1] = V(2,index);
plane[2] = V(3,index);
plane[3] = plane[0]*cx + plane[1]*cy + plane[2]*cz;
double sum = 0.0;
for(int i = 1; i < 4; i++) {
sum += D(i);
}
sum = D(index)/sum;
return sum;
}