Files
tenmon/3rdparty/include/pcl/GridInterpolation.h
T
2022-04-12 08:17:18 +02:00

988 lines
34 KiB
C++

// ____ ______ __
// / __ \ / ____// /
// / /_/ // / / /
// / ____// /___ / /___ PixInsight Class Library
// /_/ \____//_____/ PCL 2.4.23
// ----------------------------------------------------------------------------
// pcl/GridInterpolation.h - Released 2022-03-12T18:59:29Z
// ----------------------------------------------------------------------------
// This file is part of the PixInsight Class Library (PCL).
// PCL is a multiplatform C++ framework for development of PixInsight modules.
//
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
//
// Redistribution and use in both source and binary forms, with or without
// modification, is permitted provided that the following conditions are met:
//
// 1. All redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. All redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
// of their contributors, may be used to endorse or promote products derived
// from this software without specific prior written permission. For written
// permission, please contact info@pixinsight.com.
//
// 4. All products derived from this software, in any form whatsoever, must
// reproduce the following acknowledgment in the end-user documentation
// and/or other materials provided with the product:
//
// "This product is based on software from the PixInsight project, developed
// by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
//
// Alternatively, if that is where third-party acknowledgments normally
// appear, this acknowledgment must be reproduced in the product itself.
//
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------
#ifndef __PCL_GridInterpolation_h
#define __PCL_GridInterpolation_h
/// \file pcl/GridInterpolation.h
#include <pcl/Defs.h>
#include <pcl/Diagnostics.h>
#include <pcl/AbstractImage.h>
#include <pcl/BicubicInterpolation.h>
#include <pcl/Matrix.h>
#include <pcl/ParallelProcess.h>
#include <pcl/Rectangle.h>
#include <pcl/ReferenceArray.h>
#include <pcl/Thread.h>
#ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
# include <pcl/Console.h>
# include <pcl/StandardStatus.h>
#endif
namespace pcl
{
// ----------------------------------------------------------------------------
/*!
* \class GridInterpolation
* \brief Discretized scalar surface interpolation/approximation in two
* dimensions.
*
* This class performs the same tasks as a surface interpolation device, such
* as SurfaceSpline or ShepardInterpolation, but allows for much faster
* interpolation with negligible accuracy loss in most applications.
*
* Interpolation from discrete grids can be orders of magnitude faster than
* direct evaluation of surface interpolation/approximation devices, depending
* on the number of input data points.
*/
class PCL_CLASS GridInterpolation : public ParallelProcess
{
public:
/*!
* Default constructor. Yields an empty instance that cannot be used without
* initialization.
*/
GridInterpolation() = default;
/*!
* Copy constructor.
*/
GridInterpolation( const GridInterpolation& ) = default;
/*!
* Move constructor.
*/
GridInterpolation( GridInterpolation&& ) = default;
/*!
* Copy assignment operator. Returns a reference to this object.
*/
GridInterpolation& operator =( const GridInterpolation& ) = default;
/*!
* Move assignment operator. Returns a reference to this object.
*/
GridInterpolation& operator =( GridInterpolation&& ) = default;
/*!
* Initializes this %GridInterpolation object for the specified input data
* and interpolation parameters.
*
* \param rect Reference rectangle. Interpolation will be initialized
* within the boundaries of this rectangle at discrete
* \a delta coordinate intervals.
*
* \param delta Grid distance for calculation of discrete function values.
* Must be > 0.
*
* \param S Reference to a surface interpolation/approximation object
* that will be used to evaluate function values at discrete
* coordinate intervals. This object must have been
* previously initialized and must be valid.
*
* \param verbose If true, this function will write information to the
* standard PixInsight console to provide some feedback to
* the user during the (potentially long) initialization
* process. If false, no feedback will be provided.
*
* The template parameter SI must provide a member function of the form:
*
* double SI::operator ()( int x, int y ) const
*
* or an equivalent operator member function whose return value can be
* statically casted to double, with two by-value parameters that can be
* statically casted from the int type. This function will be called
* multiple times to evaluate the approximated surface at discrete grid
* coordinate pairs {x,y}. The implementation of this member function must
* be thread-safe if parallel processing has been enabled and allowed for
* this object.
*
* If parallel processing is allowed, this function executes the
* initialization process using multiple concurrent threads. See
* EnableParallelProcessing() for additional information.
*/
template <class SI>
void Initialize( const Rect& rect, int delta, const SI& S, bool verbose = true )
{
PCL_PRECONDITION( rect.IsRect() )
PCL_PRECONDITION( delta > 0 )
m_rect = rect.Ordered();
if ( !m_rect.IsRect() )
throw Error( "GridInterpolation::Initialize(): Empty interpolation space." );
m_delta = Abs( delta );
if ( m_delta == 0 )
throw Error( "GridInterpolation::Initialize(): Zero grid distance." );
int w = rect.Width();
int h = rect.Height();
int rows = 1 + h/m_delta + ((h%m_delta) ? 1 : 0);
int cols = 1 + w/m_delta + ((w%m_delta) ? 1 : 0);
m_G = DMatrix( rows, cols );
StatusMonitor monitor;
#ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
StandardStatus status;
if ( verbose )
{
monitor.SetCallback( &status );
monitor.Initialize( "Building surface interpolation grid", rows );
}
#endif
Array<size_type> L = Thread::OptimalThreadLoads( rows,
1/*overheadLimit*/,
m_parallel ? m_maxProcessors : 1 );
AbstractImage::ThreadData data( monitor, rows );
ReferenceArray<GridInitializationThread<SI> > threads;
for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
threads.Add( new GridInitializationThread<SI>( data, *this, S, n, n + int( L[i] ) ) );
AbstractImage::RunThreads( threads, data );
threads.Destroy();
m_I.Initialize( m_G.Begin(), cols, rows );
}
/*!
* Initializes this %GridInterpolation object with a prescribed discrete
* interpolation matrix.
*
* \param rect Reference rectangle. Interpolation will be initialized
* within the boundaries of this rectangle at discrete
* \a delta coordinate intervals.
*
* \param delta Grid distance for calculation of discrete function values.
* Must be > 0.
*
* \param G interpolation matrix.
*
* The specified \a G matrix must have \a n rows and \a m columns, which are
* given by:
*
* n = 1 + Ceil( rect.Height()/delta )\n
* m = 1 + Ceil( rect.Width()/delta )
*
* If the dimensions of the specified matrix are different from the values
* defined above, this function will throw an Error exception.
*
* Matrix elements must be function values computed at discrete \a delta
* intervals within \a rect boundaries. For a given matrix row \a r and
* matrix column \a c, the corresponding matrix element must be a function
* value computed at coordinates {\a x,\a y} given by:
*
* x = rect.x0 + c*delta\n
* y = rect.y0 + r*delta
*/
void Initialize( const Rect& rect, int delta, const DMatrix& G )
{
PCL_PRECONDITION( rect.IsRect() )
PCL_PRECONDITION( delta > 0 )
m_rect = rect.Ordered();
if ( !m_rect.IsRect() )
throw Error( "GridInterpolation::Initialize(): Empty interpolation space." );
m_delta = Abs( delta );
if ( m_delta == 0 )
throw Error( "GridInterpolation::Initialize(): Zero grid distance." );
int w = rect.Width();
int h = rect.Height();
int rows = 1 + h/m_delta + ((h%m_delta) ? 1 : 0);
int cols = 1 + w/m_delta + ((w%m_delta) ? 1 : 0);
if ( G.Rows() != rows || G.Cols() != cols )
throw Error( "GridInterpolation::Initialize(): Invalid matrix dimensions." );
m_G = G;
m_I.Initialize( m_G.Begin(), cols, rows );
}
/*!
* Returns true iff this is a valid, initialized object ready for
* interpolation.
*/
bool IsValid() const
{
return !m_G.IsEmpty();
}
/*!
* Deallocates internal structures, yielding an empty object that cannot be
* used before a new call to Initialize().
*/
void Clear()
{
m_I.Clear();
m_G.Clear();
}
/*!
* Returns the current interpolation reference rectangle. See Initialize()
* for more information.
*/
const Rect& ReferenceRect() const
{
return m_rect;
}
/*!
* Returns the current grid distance for calculation of discrete function
* values. See Initialize() for more information.
*/
int Delta() const
{
return m_delta;
}
/*!
* Returns a reference to the discrete matrix used for interpolation of
* function values.
*
* If this object has not been initialized, this member function returns a
* reference to an empty matrix.
*/
const DMatrix& InterpolationMatrix() const
{
return m_G;
}
/*!
* Returns an interpolated function value at the specified coordinates.
*/
template <typename T>
double operator ()( T x, T y ) const
{
double fx = (double( x ) - m_rect.x0)/m_delta;
double fy = (double( y ) - m_rect.y0)/m_delta;
return m_I( fx, fy );
}
/*!
* Returns an interpolated function value at \a p.x and \a p.y coordinates.
*/
template <typename T>
double operator ()( const GenericPoint<T>& p ) const
{
return operator ()( p.x, p.y );
}
private:
/*!
* N.B.: Here we need a smooth interpolation function without negative
* lobes, in order to prevent small-scale oscillations. Other options are
* BilinearInterpolation and CubicBSplineFilter.
*/
typedef BicubicBSplineInterpolation<double> grid_interpolation;
Rect m_rect;
int m_delta;
DMatrix m_G;
grid_interpolation m_I;
template <class SI>
class GridInitializationThread : public Thread
{
public:
GridInitializationThread( const AbstractImage::ThreadData& data,
GridInterpolation& grid, const SI& surface, int startRow, int endRow )
: m_data( data )
, m_grid( grid )
, m_surface( surface )
, m_startRow( startRow )
, m_endRow( endRow )
{
}
PCL_HOT_FUNCTION void Run() override
{
INIT_THREAD_MONITOR()
for ( int i = m_startRow, y = m_grid.m_rect.y0 + i*m_grid.m_delta; i < m_endRow; ++i, y += m_grid.m_delta )
{
for ( int j = 0, x = m_grid.m_rect.x0; j < m_grid.m_G.Cols(); ++j, x += m_grid.m_delta )
m_grid.m_G[i][j] = m_surface( x, y );
UPDATE_THREAD_MONITOR( 32 )
}
}
private:
const AbstractImage::ThreadData& m_data;
GridInterpolation& m_grid;
const SI& m_surface;
int m_startRow, m_endRow;
};
};
// ----------------------------------------------------------------------------
/*!
* \class PointGridInterpolation
* \brief Discretized vector surface interpolation/approximation in two
* dimensions.
*
* This class performs the same tasks as a point surface interpolation device,
* such as PointSurfaceSpline or PointShepardInterpolation, but allows for much
* faster interpolation with negligible accuracy loss in most applications.
*
* Interpolation from discrete grids can be orders of magnitude faster than
* direct evaluation of surface interpolation/approximation devices, depending
* on the number of input data points.
*/
class PCL_CLASS PointGridInterpolation : public ParallelProcess
{
public:
/*!
* Default constructor. Yields an empty instance that cannot be used without
* initialization.
*/
PointGridInterpolation() = default;
/*!
* Copy constructor.
*/
PointGridInterpolation( const PointGridInterpolation& ) = default;
/*!
* Move constructor.
*/
PointGridInterpolation( PointGridInterpolation&& ) = default;
/*!
* Copy assignment operator. Returns a reference to this object.
*/
PointGridInterpolation& operator =( const PointGridInterpolation& ) = default;
/*!
* Move assignment operator. Returns a reference to this object.
*/
PointGridInterpolation& operator =( PointGridInterpolation&& ) = default;
/*!
* Initializes a %PointGridInterpolation object with a point surface
* interpolation/approximation.
*
* \param rect Reference rectangle. Interpolation will be initialized
* within the boundaries of this rectangle at discrete
* \a delta coordinate intervals.
*
* \param delta Grid distance for calculation of discrete function values.
* Must be > 0.
*
* \param PS Reference to a point surface interpolation/approximation
* object that will be used to evaluate function values at
* discrete coordinate intervals. This object must have been
* previously initialized and must be valid.
*
* \param verbose If true, this function will write information to the
* standard PixInsight console to provide some feedback to
* the user during the (potentially long) initialization
* process. If false, no feedback will be provided.
*
* The template parameter PSI must provide a member function of the form:
*
* DPoint PSI::operator ()( int x, int y ) const
*
* or an equivalent operator member function whose return value can be
* statically casted to DPoint, with two by-value parameters that can be
* statically casted from the int type. This function will be called
* multiple times to evaluate the approximated surface at discrete grid
* coordinate pairs {x,y}. The implementation of this member function must
* be thread-safe if parallel processing has been enabled and allowed for
* this object.
*
* If parallel processing is allowed, this function executes the
* initialization process using multiple concurrent threads. See
* EnableParallelProcessing() for additional information.
*/
template <class PSI>
void Initialize( const Rect& rect, int delta, const PSI& PS, bool verbose = true )
{
PCL_PRECONDITION( rect.IsRect() )
PCL_PRECONDITION( delta > 0 )
m_rect = rect.Ordered();
if ( !m_rect.IsRect() )
throw Error( "PointGridInterpolation::Initialize(): Empty interpolation space." );
m_delta = Abs( delta );
if ( m_delta == 0 )
throw Error( "PointGridInterpolation::Initialize(): Zero grid distance." );
int w = rect.Width();
int h = rect.Height();
int rows = 1 + h/m_delta + ((h%m_delta) ? 1 : 0);
int cols = 1 + w/m_delta + ((w%m_delta) ? 1 : 0);
m_Gx = DMatrix( rows, cols );
m_Gy = DMatrix( rows, cols );
StatusMonitor monitor;
#ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
StandardStatus status;
if ( verbose )
{
monitor.SetCallback( &status );
monitor.Initialize( "Building surface interpolation grid", rows );
}
#endif
Array<size_type> L = Thread::OptimalThreadLoads( rows,
1/*overheadLimit*/,
m_parallel ? m_maxProcessors : 1 );
AbstractImage::ThreadData data( monitor, rows );
ReferenceArray<GridInitializationThread<PSI> > threads;
for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
threads.Add( new GridInitializationThread<PSI>( data, *this, PS, n, n + int( L[i] ) ) );
AbstractImage::RunThreads( threads, data );
threads.Destroy();
m_Ix.Initialize( m_Gx.Begin(), cols, rows );
m_Iy.Initialize( m_Gy.Begin(), cols, rows );
}
/*!
* Initializes a %PointGridInterpolation object with separate surface
* interpolations/approximations for the X and Y directions.
*
* \param rect Reference rectangle. Interpolation will be initialized
* within the boundaries of this rectangle at discrete
* \a delta coordinate intervals.
*
* \param delta Grid distance for calculation of discrete function values.
* Must be > 0.
*
* \param Sx Reference to a surface interpolation/approximation object
* that will be used to evaluate function values at discrete
* coordinate intervals on the X axis. This object must have
* been previously initialized and must be valid.
*
* \param Sy Reference to a surface interpolation/approximation object
* that will be used to evaluate function values at discrete
* coordinate intervals on the Y axis. This object must have
* been previously initialized and must be valid.
*
* \param verbose If true, this function will write information to the
* standard PixInsight console to provide some feedback to
* the user during the (potentially long) initialization
* process. If false, no feedback will be provided.
*
* The template parameter SI must provide a member function of the form:
*
* double SI::operator ()( int x, int y ) const
*
* or an equivalent operator member function whose return value can be
* statically casted to double, with two by-value parameters that can be
* statically casted from the int type. This function will be called
* multiple times for the \a Sx and \a Sy objects to evaluate the
* approximated surface at discrete grid coordinate pairs {x,y},
* respectively on the X and Y plane directions. The implementation of this
* member function must be thread-safe if parallel processing has been
* enabled and allowed for this object.
*
* If parallel processing is allowed, this function executes the
* initialization process using multiple concurrent threads. See
* EnableParallelProcessing() for additional information.
*/
template <class SI>
void Initialize( const Rect& rect, int delta, const SI& Sx, const SI& Sy, bool verbose = true )
{
PCL_PRECONDITION( rect.IsRect() )
PCL_PRECONDITION( delta > 0 )
m_rect = rect.Ordered();
if ( !m_rect.IsRect() )
throw Error( "PointGridInterpolation::Initialize(): Empty interpolation space." );
m_delta = Abs( delta );
if ( m_delta == 0 )
throw Error( "PointGridInterpolation::Initialize(): Zero grid distance." );
int w = rect.Width();
int h = rect.Height();
int rows = 1 + h/m_delta + ((h%m_delta) ? 1 : 0);
int cols = 1 + w/m_delta + ((w%m_delta) ? 1 : 0);
m_Gx = DMatrix( rows, cols );
m_Gy = DMatrix( rows, cols );
StatusMonitor monitor;
#ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
StandardStatus status;
if ( verbose )
{
monitor.SetCallback( &status );
monitor.Initialize( "Building surface interpolation grid", rows );
}
#endif
Array<size_type> L = Thread::OptimalThreadLoads( rows,
1/*overheadLimit*/,
m_parallel ? m_maxProcessors : 1 );
AbstractImage::ThreadData data( monitor, rows );
ReferenceArray<GridInitializationXYThread<SI> > threads;
for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
threads.Add( new GridInitializationXYThread<SI>( data, *this, Sx, Sy, n, n + int( L[i] ) ) );
AbstractImage::RunThreads( threads, data );
threads.Destroy();
m_Ix.Initialize( m_Gx.Begin(), cols, rows );
m_Iy.Initialize( m_Gy.Begin(), cols, rows );
}
/*!
* Initializes this %PointGridInterpolation object with prescribed
* interpolation matrices.
*
* \param rect Reference rectangle. Interpolation will be initialized
* within the boundaries of this rectangle at discrete
* \a delta coordinate intervals.
*
* \param delta Grid distance for calculation of discrete function values.
* Must be > 0.
*
* \param Gx interpolation matrix in the X direction.
*
* \param Gy Interpolation matrix in the Y direction.
*
* Both \a Gx and \a Gy matrices must have \a n rows and \a m columns, which
* are given by:
*
* n = 1 + Ceil( rect.Height()/delta )\n
* m = 1 + Ceil( rect.Width()/delta )
*
* If one or both matrices have different dimensions, this function will
* throw an Error exception.
*
* Matrix elements must be function values computed at discrete \a delta
* intervals within \a rect boundaries. For a given matrix row \a r and
* matrix column \a c, the corresponding matrix element must be a function
* value computed at coordinates {\a x,\a y} given by:
*
* x = rect.x0 + c*delta\n
* y = rect.y0 + r*delta
*/
void Initialize( const Rect& rect, int delta, const DMatrix& Gx, const DMatrix& Gy )
{
PCL_PRECONDITION( rect.IsRect() )
PCL_PRECONDITION( delta > 0 )
m_rect = rect.Ordered();
if ( !m_rect.IsRect() )
throw Error( "PointGridInterpolation::Initialize(): Empty interpolation space." );
m_delta = Abs( delta );
if ( m_delta == 0 )
throw Error( "PointGridInterpolation::Initialize(): Zero grid distance." );
int w = rect.Width();
int h = rect.Height();
int rows = 1 + h/m_delta + ((h%m_delta) ? 1 : 0);
int cols = 1 + w/m_delta + ((w%m_delta) ? 1 : 0);
if ( Gx.Rows() != rows || Gx.Cols() != cols || Gy.Rows() != rows || Gy.Cols() != cols )
throw Error( "PointGridInterpolation::Initialize(): Invalid matrix dimensions." );
m_Gx = Gx;
m_Gy = Gy;
m_Ix.Initialize( m_Gx.Begin(), cols, rows );
m_Iy.Initialize( m_Gy.Begin(), cols, rows );
}
/*!
*
*/
template <class PSI>
void ApplyLocalModel( const PSI& PS,
const String& message = "Applying local interpolation model",
bool verbose = true )
{
PCL_PRECONDITION( IsValid() )
if ( !IsValid() )
throw Error( "PointGridInterpolation::ApplyLocalModel(): Uninitialized interpolation." );
StatusMonitor monitor;
#ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
StandardStatus status;
if ( verbose )
{
monitor.SetCallback( &status );
monitor.Initialize( message, m_Gx.Rows() );
}
#endif
Array<size_type> L = Thread::OptimalThreadLoads( m_Gx.Rows(),
1/*overheadLimit*/,
m_parallel ? m_maxProcessors : 1 );
AbstractImage::ThreadData data( monitor, m_Gx.Rows() );
ReferenceArray<LocalModelThread<PSI> > threads;
for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
threads.Add( new LocalModelThread<PSI>( data, *this, PS, n, n + int( L[i] ) ) );
AbstractImage::RunThreads( threads, data );
threads.Destroy();
}
/*!
*
*/
template <class SI>
void ApplyLocalModel( const SI& Sx, const SI& Sy,
const String& message = "Applying local interpolation model",
bool verbose = true )
{
PCL_PRECONDITION( IsValid() )
if ( !IsValid() )
throw Error( "PointGridInterpolation::ApplyLocalModel(): Uninitialized interpolation." );
StatusMonitor monitor;
#ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
StandardStatus status;
if ( verbose )
{
monitor.SetCallback( &status );
monitor.Initialize( message, m_Gx.Rows() );
}
#endif
Array<size_type> L = Thread::OptimalThreadLoads( m_Gx.Rows(),
1/*overheadLimit*/,
m_parallel ? m_maxProcessors : 1 );
AbstractImage::ThreadData data( monitor, m_Gx.Rows() );
ReferenceArray<LocalModelThread2<SI> > threads;
for ( int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
threads.Add( new LocalModelThread2<SI>( data, *this, Sx, Sy, n, n + int( L[i] ) ) );
AbstractImage::RunThreads( threads, data );
threads.Destroy();
}
/*!
* Returns true iff this is a valid, initialized object ready for
* interpolation.
*/
bool IsValid() const
{
return !m_Gx.IsEmpty() && !m_Gy.IsEmpty();
}
/*!
* Deallocates internal structures, yielding an empty object that cannot be
* used before a new call to Initialize().
*/
void Clear()
{
m_Ix.Clear();
m_Iy.Clear();
m_Gx.Clear();
m_Gy.Clear();
}
/*!
* Returns the current interpolation reference rectangle. See Initialize()
* for more information.
*
* The returned rectangle is ordered (see pcl::IsOrderedRect()).
*/
const Rect& ReferenceRect() const
{
return m_rect;
}
/*!
* Returns the current grid distance for calculation of discrete function
* values. See Initialize() for more information.
*/
int Delta() const
{
return m_delta;
}
/*!
* Returns a reference to the discrete matrix used for interpolation of
* function values in the X direction.
*
* If this object has not been initialized, this member function returns a
* reference to an empty matrix.
*/
const DMatrix& XInterpolationMatrix() const
{
return m_Gx;
}
/*!
* Returns a reference to the discrete matrix used for interpolation of
* function values in the Y direction.
*
* If this object has not been initialized, this member function returns a
* reference to an empty matrix.
*/
const DMatrix& YInterpolationMatrix() const
{
return m_Gy;
}
/*!
* Returns an interpolated point at the specified coordinates.
*/
template <typename T>
DPoint operator ()( T x, T y ) const
{
PCL_PRECONDITION( IsValid() )
double fx = (double( x ) - m_rect.x0)/m_delta;
double fy = (double( y ) - m_rect.y0)/m_delta;
return DPoint( m_Ix( fx, fy ), m_Iy( fx, fy ) );
}
/*!
* Returns an interpolated point at the given \a p.x and \a p.y coordinates.
*/
template <typename T>
DPoint operator ()( const GenericPoint<T>& p ) const
{
return operator ()( p.x, p.y );
}
private:
/*!
* N.B.: Here we need a smooth interpolation function without negative
* lobes, in order to prevent small-scale oscillations. Other options are
* BilinearInterpolation and CubicBSplineFilter.
*/
typedef BicubicBSplineInterpolation<double> grid_interpolation;
Rect m_rect;
int m_delta;
DMatrix m_Gx, m_Gy;
grid_interpolation m_Ix, m_Iy;
template <class PSI>
class GridInitializationThread : public Thread
{
public:
GridInitializationThread( const AbstractImage::ThreadData& data,
PointGridInterpolation& grid, const PSI& surface, int startRow, int endRow )
: m_data( data )
, m_grid( grid )
, m_surface( surface )
, m_startRow( startRow )
, m_endRow( endRow )
{
}
PCL_HOT_FUNCTION void Run() override
{
INIT_THREAD_MONITOR()
for ( int i = m_startRow, y = m_grid.m_rect.y0 + i*m_grid.m_delta; i < m_endRow; ++i, y += m_grid.m_delta )
{
for ( int j = 0, x = m_grid.m_rect.x0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
{
DPoint p = m_surface( x, y );
m_grid.m_Gx[i][j] = p.x;
m_grid.m_Gy[i][j] = p.y;
}
UPDATE_THREAD_MONITOR( 32 )
}
}
private:
const AbstractImage::ThreadData& m_data;
PointGridInterpolation& m_grid;
const PSI& m_surface;
int m_startRow, m_endRow;
};
template <class SI>
class GridInitializationXYThread : public Thread
{
public:
GridInitializationXYThread( const AbstractImage::ThreadData& data,
PointGridInterpolation& grid,
const SI& surfaceX, const SI& surfaceY, int startRow, int endRow )
: m_data( data )
, m_grid( grid )
, m_surfaceX( surfaceX )
, m_surfaceY( surfaceY )
, m_startRow( startRow )
, m_endRow( endRow )
{
}
PCL_HOT_FUNCTION void Run() override
{
INIT_THREAD_MONITOR()
for ( int i = m_startRow, y = m_grid.m_rect.y0 + i*m_grid.m_delta; i < m_endRow; ++i, y += m_grid.m_delta )
{
for ( int j = 0, x = m_grid.m_rect.x0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
{
m_grid.m_Gx[i][j] = m_surfaceX( x, y );
m_grid.m_Gy[i][j] = m_surfaceY( x, y );
}
UPDATE_THREAD_MONITOR( 32 )
}
}
private:
const AbstractImage::ThreadData& m_data;
PointGridInterpolation& m_grid;
const SI& m_surfaceX;
const SI& m_surfaceY;
int m_startRow, m_endRow;
};
template <class PSI>
class LocalModelThread : public Thread
{
public:
LocalModelThread( const AbstractImage::ThreadData& data,
PointGridInterpolation& grid, const PSI& model, int startRow, int endRow )
: m_data( data )
, m_grid( grid )
, m_model( model )
, m_startRow( startRow )
, m_endRow( endRow )
{
}
PCL_HOT_FUNCTION void Run() override
{
INIT_THREAD_MONITOR()
for ( int i = m_startRow, y = m_grid.m_rect.y0 + i*m_grid.m_delta; i < m_endRow; ++i, y += m_grid.m_delta )
{
for ( int j = 0, x = m_grid.m_rect.x0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
{
DPoint d = m_model( x, y );
m_grid.m_Gx[i][j] += d.x;
m_grid.m_Gy[i][j] += d.y;
}
UPDATE_THREAD_MONITOR( 32 )
}
}
private:
const AbstractImage::ThreadData& m_data;
PointGridInterpolation& m_grid;
const PSI& m_model;
int m_startRow, m_endRow;
};
template <class SI>
class LocalModelThread2 : public Thread
{
public:
LocalModelThread2( const AbstractImage::ThreadData& data,
PointGridInterpolation& grid, const SI& modelX, const SI& modelY, int startRow, int endRow )
: m_data( data )
, m_grid( grid )
, m_modelX( modelX )
, m_modelY( modelY )
, m_startRow( startRow )
, m_endRow( endRow )
{
}
PCL_HOT_FUNCTION void Run() override
{
INIT_THREAD_MONITOR()
for ( int i = m_startRow, y = m_grid.m_rect.y0 + i*m_grid.m_delta; i < m_endRow; ++i, y += m_grid.m_delta )
{
for ( int j = 0, x = m_grid.m_rect.x0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
{
m_grid.m_Gx[i][j] += m_modelX( x, y );
m_grid.m_Gy[i][j] += m_modelY( x, y );
}
UPDATE_THREAD_MONITOR( 32 )
}
}
private:
const AbstractImage::ThreadData& m_data;
PointGridInterpolation& m_grid;
const SI& m_modelX, m_modelY;
int m_startRow, m_endRow;
};
};
// ----------------------------------------------------------------------------
} // pcl
#endif // __PCL_GridInterpolation_h
// ----------------------------------------------------------------------------
// EOF pcl/GridInterpolation.h - Released 2022-03-12T18:59:29Z