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.

270 lines
5.8 KiB
C++

/**
* 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);
}