/* * 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 #include #include #include "shapes/quadtree.h" #include #include #ifdef _MSC_VER #include #include #else #include #endif #include /** * 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(); 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::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::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::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* maxlist = acc->getMax(); multiset::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 &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* maxlist = acc->getMax(); // cout << "Mean " << acc->mean() << endl; // cout << "Variance " << acc->variance() << endl; multiset::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 mergelist = vector(); int stability[20] = {0}; do { //randomly select points and perform HT for them vector altlist = mergelist; mergelist = vector(); multiset maxlist = multiset(); 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::iterator mi = maxlist.begin(); vector::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::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 *nallPoints = new vector(); vector planePoints; out << n[0] << " " << n[1] << " " << n[2] << " " << rho << " "; Point p; vector::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 > 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::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 *nallPoints = new vector(); vector planePoints; Point p; vector::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 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::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 convex_hull; ConvexPlane::JarvisMarchConvexHull(point_list,convex_hull); for(list::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::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 > linked; double factor = myConfigFileHough.Get_PointDist(); int xlength = 1 + (maxx - minx) / factor; int ylength = 1 + (maxy - miny) / factor; vector< vector > colors; for(int i = 0; i < ylength; i++) { vector *tmp = new vector; colors.push_back(*tmp); for(int j = 0; j < xlength; j++) { colors[i].push_back(0); } delete tmp; } //int colors[ylength][xlength]; vector< vector > points; for(int i = 0; i < ylength; i++) { vector *tmp = new vector; 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 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 current; set joined; joined.insert(up); joined.insert(left); for(vector >::iterator itr = linked.begin(); itr != linked.end(); ) { current = (*itr); if(current.find(up) != current.end() || current.find(left) != current.end()) { set newjoined; insert_iterator > 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 current; for(unsigned int i = 0; i < linked.size(); i++) { current = linked[i]; for(set::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 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 >::iterator itr = linked.begin(); itr != linked.end(); ) { set<>current = (*itr); if(current.find(up) != current.end() || current.find(left) != current.end()) { */ return maxindex; } /** * Writes ::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::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::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 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::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 &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; }