Skip to content

Commit

Permalink
Improve the syntax of ScalarFieldTools::computeCellGaussianFilter
Browse files Browse the repository at this point in the history
  • Loading branch information
dgirardeau committed Mar 14, 2024
1 parent a8ce427 commit aff0e79
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 68 deletions.
15 changes: 7 additions & 8 deletions include/ScalarFieldTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,15 @@ namespace CCCoreLib
DgmOctree* theOctree = nullptr);

//! Computes a spatial gaussian filter on a scalar field associated to a point cloud
/** The "amplitutde" of the gaussian filter must be precised (sigma).
As 99% of the gaussian distribution is between -3*sigma and +3*sigma
around the mean value, this filter will only look for neighbouring
points (around each point) in a sphere of radius 3*sigma.
It also permits to use the filter as a bilateral filter. Where the wights are computed also considering the
distance of the neighbor's scalar value from the current point scalar value. (weighted with gaussian as distances are)
Warning: this method assumes the input scalar field is different from output.
/** The "amplitutde" of the Gaussian filter must be specified (sigma).
As 99% of the Gaussian distribution is between -3*sigma and +3*sigma around the mean value,
this filter will only look for neighbors within a sphere of radius 3*sigma.
One can also use the filter as a Bilateral filter. In this case the weights are computed considering the
difference of the neighbors SF values with the current point SF value (also following a Gaussian distribution).
Warning: this method assumes the input scalar field is different from the output one.
\param sigma filter variance
\param theCloud a point cloud (associated to scalar values)
\param sigmaSF the sigma for the bilateral filter. when different than -1 turns the gaussian filter into a bilateral filter
\param sigmaSF if strictly positive, the variance for the Bilateral filter
\param progressCb the client application can get some notification of the process progress through this callback mechanism (see GenericProgressCallback)
\param theOctree the octree, if it has already been computed
\return success
Expand Down
104 changes: 44 additions & 60 deletions src/ScalarFieldTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,8 @@ bool ScalarFieldTools::applyScalarFieldGaussianFilter(PointCoordinateType sigma,
progressCb->update(0);
}

void* additionalParameters[2] = { reinterpret_cast<void*>(&sigma),
reinterpret_cast<void*>(&sigmaSF)
};
void* additionalParameters[2] { reinterpret_cast<void*>(&sigma),
reinterpret_cast<void*>(&sigmaSF) };

bool success = true;

Expand All @@ -298,10 +297,9 @@ bool ScalarFieldTools::applyScalarFieldGaussianFilter(PointCoordinateType sigma,
return success;
}

//FONCTION "CELLULAIRE" DE CALCUL DU FILTRE GAUSSIEN (PAR PROJECTION SUR LE PLAN AUX MOINDRES CARRES)
//DETAIL DES PARAMETRES ADDITIONNELS (2) :
// [0] -> (PointCoordinateType*) sigma : gauss function sigma
// [1] -> (PointCoordinateType*) sigmaSF : used when in "bilateral modality" - if -1 pure gaussian filtering is performed
// Additional parameters:
// [0] -> (PointCoordinateType*) sigma: Gaussian filter sigma
// [1] -> (PointCoordinateType*) sigmaSF: Bilateral filter sigma (if > 0)
bool ScalarFieldTools::computeCellGaussianFilter( const DgmOctree::octreeCell& cell,
void** additionalParameters,
NormalizedProgress* nProgress/*=nullptr*/)
Expand All @@ -312,7 +310,7 @@ bool ScalarFieldTools::computeCellGaussianFilter( const DgmOctree::octreeCell& c

//we use only the squared value of sigma
PointCoordinateType sigma2 = 2*sigma*sigma;
PointCoordinateType radius = 3*sigma; //2.5 sigma > 99%
PointCoordinateType radius = 3*sigma; //3*sigma > 99.7%

//we use only the squared value of sigmaSF
PointCoordinateType sigmaSF2 = 2*sigmaSF*sigmaSF;
Expand Down Expand Up @@ -348,73 +346,59 @@ bool ScalarFieldTools::computeCellGaussianFilter( const DgmOctree::octreeCell& c

const GenericIndexedCloudPersist* cloud = cell.points->getAssociatedCloud();

//Pure Gaussian Filtering
if (sigmaSF == -1)
bool bilateralFilter = (sigmaSF > 0);

for (unsigned i = 0; i < n; ++i) //for each point in cell
{
for (unsigned i = 0; i < n; ++i) //for each point in cell
ScalarType queryValue = 0;
if (bilateralFilter)
{
//we get the points inside a spherical neighbourhood (radius: '3*sigma')
cell.points->getPoint(i,nNSS.queryPoint);
//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (k)!
unsigned k = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS,radius,false);
queryValue = cell.points->getPointScalarValue(i); //scalar of the query point

//each point adds a contribution weighted by its distance to the sphere center
it = nNSS.pointsInNeighbourhood.begin();
double meanValue = 0.0;
double wSum = 0.0;
for (unsigned j = 0; j < k; ++j, ++it)
// check that the query SF value is valid, otherwise no need to compute anything
if (!ScalarField::ValidValue(queryValue))
{
double weight = exp(-(it->squareDistd) / sigma2); //PDF: -exp(-(x-mu)^2/(2*sigma^2))
ScalarType val = cloud->getPointScalarValue(it->pointIndex);
//scalar value must be valid
if (ScalarField::ValidValue(val))
{
meanValue += static_cast<double>(val) * weight;
wSum += weight;
}
cell.points->setPointScalarValue(i, NAN_VALUE);
continue;
}
}

ScalarType newValue = (wSum > 0.0 ? static_cast<ScalarType>(meanValue / wSum) : NAN_VALUE);

cell.points->setPointScalarValue(i, newValue);
//we get the points inside a spherical neighbourhood (radius: '3*sigma')
cell.points->getPoint(i, nNSS.queryPoint);
//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (k)!
unsigned k = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS, radius, false);

if (nProgress && !nProgress->oneStep())
return false;
}
}
//Bilateral Filtering using the second sigma parameters on values (when given)
else
{
for (unsigned i = 0; i < n; ++i) //for each point in cell
//each point adds a contribution weighted by its distance to the sphere center
it = nNSS.pointsInNeighbourhood.begin();
double meanValue = 0.0;
double wSum = 0.0;
for (unsigned j = 0; j < k; ++j, ++it)
{
ScalarType queryValue = cell.points->getPointScalarValue(i); //scalar of the query point
double weight = exp(-(it->squareDistd) / sigma2); //PDF: -exp(-(x-mu)^2/(2*sigma^2))

//we get the points inside a spherical neighbourhood (radius: '3*sigma')
cell.points->getPoint(i, nNSS.queryPoint);
//warning: there may be more points at the end of nNSS.pointsInNeighbourhood than the actual nearest neighbors (k)!
unsigned k = cell.parentOctree->findNeighborsInASphereStartingFromCell(nNSS, radius, false);
ScalarType val = cloud->getPointScalarValue(it->pointIndex);

//scalar value must be valid
if (!ScalarField::ValidValue(val))
{
continue;
}

//each point adds a contribution weighted by its distance to the sphere center
it = nNSS.pointsInNeighbourhood.begin();
double meanValue = 0.0;
double wSum = 0.0;
for (unsigned j = 0; j < k; ++j, ++it)
if (bilateralFilter)
{
ScalarType val = cloud->getPointScalarValue(it->pointIndex);
ScalarType dSF = queryValue - val;
double weight = exp(-(it->squareDistd) / sigma2) * exp(-(dSF*dSF) / sigmaSF2);
//scalar value must be valid
if (ScalarField::ValidValue(val))
{
meanValue += static_cast<double>(val) * weight;
wSum += weight;
}
weight *= exp(-(dSF*dSF) / sigmaSF2);
}

cell.points->setPointScalarValue(i, wSum > 0.0 ? static_cast<ScalarType>(meanValue / wSum) : NAN_VALUE);
meanValue += val * weight;
wSum += weight;
}

cell.points->setPointScalarValue(i, wSum != 0.0 ? static_cast<ScalarType>(meanValue / wSum) : NAN_VALUE);

if (nProgress && !nProgress->oneStep())
return false;
if (nProgress && !nProgress->oneStep())
{
return false;
}
}

Expand Down

0 comments on commit aff0e79

Please sign in to comment.