52 #ifndef __PCL_GridInterpolation_h
53 #define __PCL_GridInterpolation_h
58 #include <pcl/Diagnostics.h>
74 #ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
188 template <
class R,
class SI>
189 void Initialize(
const R& rect,
int delta,
const SI& S,
bool verbose =
true )
191 PCL_PRECONDITION( rect.IsRect() )
192 PCL_PRECONDITION( delta > 0 )
194 m_rect = rect.Ordered();
195 double width = m_rect.Width();
196 double height = m_rect.Height();
197 if ( !m_rect.IsRect() || 1 + width == 1 || 1 + height == 1 )
198 throw Error(
"GridInterpolation::Initialize(): Empty interpolation space." );
200 m_delta =
Abs( delta );
201 if ( 1 + m_delta == 1 )
202 throw Error(
"GridInterpolation::Initialize(): Zero or insignificant grid distance." );
204 int rows = 1 + int(
Ceil( height/m_delta ) );
205 int cols = 1 + int(
Ceil( width/m_delta ) );
209 #ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
214 monitor.
Initialize(
"Building surface interpolation grid", rows );
220 m_parallel ? m_maxProcessors : 1 );
223 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
224 threads.
Add(
new GridInitializationThread<SI>( data, *
this, S, n, n +
int( L[i] ) ) );
228 m_I.Initialize( m_G.Begin(), cols, rows );
264 PCL_PRECONDITION( rect.IsRect() )
265 PCL_PRECONDITION( delta > 0 )
267 m_rect =
DRect( rect.Ordered() );
268 double width = m_rect.Width();
269 double height = m_rect.Height();
270 if ( !m_rect.IsRect() || 1 + width == 1 || 1 + height == 1 )
271 throw Error(
"GridInterpolation::Initialize(): Empty interpolation space." );
273 m_delta =
Abs( delta );
274 if ( 1 + m_delta == 1 )
275 throw Error(
"GridInterpolation::Initialize(): Zero or insignificant grid distance." );
277 int rows = 1 + int(
Ceil( height/m_delta ) );
278 int cols = 1 + int(
Ceil( width/m_delta ) );
279 if ( G.Rows() != rows || G.Cols() != cols )
280 throw Error(
"GridInterpolation::Initialize(): Invalid matrix dimensions." );
283 m_I.Initialize( m_G.Begin(), cols, rows );
292 return !m_G.IsEmpty();
338 template <
typename T>
339 double operator ()( T x, T y )
const
341 double fx = (double( x ) - m_rect.x0)/m_delta;
342 double fy = (double( y ) - m_rect.y0)/m_delta;
343 return m_I( fx, fy );
349 template <
typename T>
352 return operator ()( p.
x, p.
y );
367 grid_interpolation m_I;
370 class GridInitializationThread :
public Thread
378 , m_surface( surface )
379 , m_startRow( startRow )
382 if ( m_surface.HasFastVectorEvaluation() )
391 PCL_HOT_FUNCTION
void Run()
override
395 if ( m_surface.HasFastVectorEvaluation() )
397 int i0 = m_startRow, j0 = 0, n = 0;
398 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
399 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
401 double x = m_grid.m_rect.x0;
402 for (
int j = 0; j < m_grid.m_G.Cols(); ++j, ++n, x += m_grid.m_delta )
406 m_surface.Evaluate( m_Z.Begin(), m_X.Begin(), m_Y.Begin(), n );
407 for (
int i1 = i0, k1 = 0; i1 <= i && k1 < n; ++i1, j0 = 0 )
408 for (
int j1 = j0; j1 < m_grid.m_G.Cols() && k1 < n; ++j1, ++k1 )
409 m_grid.m_G[i1][j1] = m_Z[k1];
424 m_surface.Evaluate( m_Z.Begin(), m_X.Begin(), m_Y.Begin(), n );
425 for (
int i1 = i0, k1 = 0; i1 < m_endRow; ++i1, j0 = 0 )
426 for (
int j1 = j0; j1 < m_grid.m_G.Cols(); ++j1, ++k1 )
427 m_grid.m_G[i1][j1] = m_Z[k1];
434 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
435 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
437 double x = m_grid.m_rect.x0;
438 for (
int j = 0; j < m_grid.m_G.Cols(); ++j, x += m_grid.m_delta )
439 m_grid.m_G[i][j] = m_surface( x, y );
448 const AbstractImage::ThreadData& m_data;
449 GridInterpolation& m_grid;
451 int m_startRow, m_endRow, m_N;
563 template <
class R,
class PSI>
564 void Initialize(
const R& rect,
double delta,
const PSI& PS,
bool verbose =
true )
566 PCL_PRECONDITION( rect.IsRect() )
567 PCL_PRECONDITION( delta > 0 )
569 m_rect =
DRect( rect.Ordered() );
570 double width = m_rect.
Width();
571 double height = m_rect.
Height();
572 if ( !m_rect.
IsRect() || 1 + width == 1 || 1 + height == 1 )
573 throw Error(
"PointGridInterpolation::Initialize(): Empty interpolation space." );
575 m_delta =
Abs( delta );
576 if ( 1 + m_delta == 1 )
577 throw Error(
"PointGridInterpolation::Initialize(): Zero or insignificant grid distance." );
579 int rows = 1 + int(
Ceil( height/m_delta ) );
580 int cols = 1 + int(
Ceil( width/m_delta ) );
585 #ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
590 monitor.
Initialize(
"Building surface interpolation grid", rows );
596 m_parallel ? m_maxProcessors : 1 );
599 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
600 threads.
Add(
new GridInitializationThread<PSI>( data, *
this, PS, n, n +
int( L[i] ) ) );
604 m_Ix.Initialize( m_Gx.Begin(), cols, rows );
605 m_Iy.Initialize( m_Gy.Begin(), cols, rows );
676 template <
class R,
class SI>
677 void Initialize(
const R& rect,
double delta,
const SI& Sx,
const SI& Sy,
bool verbose =
true )
679 PCL_PRECONDITION( rect.IsRect() )
680 PCL_PRECONDITION( delta > 0 )
682 m_rect =
DRect( rect.Ordered() );
683 double width = m_rect.
Width();
684 double height = m_rect.
Height();
685 if ( !m_rect.
IsRect() || 1 + width == 1 || 1 + height == 1 )
686 throw Error(
"PointGridInterpolation::Initialize(): Empty interpolation space." );
688 m_delta =
Abs( delta );
689 if ( 1 + m_delta == 1 )
690 throw Error(
"PointGridInterpolation::Initialize(): Zero or insignificant grid distance." );
692 int rows = 1 + int(
Ceil( height/m_delta ) );
693 int cols = 1 + int(
Ceil( width/m_delta ) );
698 #ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
703 monitor.
Initialize(
"Building surface interpolation grid", rows );
709 m_parallel ? m_maxProcessors : 1 );
712 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
713 threads.
Add(
new GridInitializationXYThread<SI>( data, *
this, Sx, Sy, n, n +
int( L[i] ) ) );
717 m_Ix.Initialize( m_Gx.Begin(), cols, rows );
718 m_Iy.Initialize( m_Gy.Begin(), cols, rows );
756 PCL_PRECONDITION( rect.IsRect() )
757 PCL_PRECONDITION( delta > 0 )
759 m_rect =
DRect( rect.Ordered() );
760 double width = m_rect.
Width();
761 double height = m_rect.
Height();
762 if ( !m_rect.
IsRect() || 1 + width == 1 || 1 + height == 1 )
763 throw Error(
"PointGridInterpolation::Initialize(): Empty interpolation region." );
765 m_delta =
Abs( delta );
766 if ( 1 + m_delta == 1 )
767 throw Error(
"PointGridInterpolation::Initialize(): Zero or insignificant grid distance." );
769 int rows = 1 + int(
Ceil( height/m_delta ) );
770 int cols = 1 + int(
Ceil( width/m_delta ) );
771 if ( Gx.
Rows() != rows || Gx.
Cols() != cols || Gy.
Rows() != rows || Gy.
Cols() != cols )
772 throw Error(
"PointGridInterpolation::Initialize(): Invalid matrix dimensions." );
776 m_Ix.Initialize( m_Gx.Begin(), cols, rows );
777 m_Iy.Initialize( m_Gy.Begin(), cols, rows );
784 void ApplyLocalModel(
const PSI& PS,
785 const String& message =
"Applying local interpolation model",
786 bool verbose =
true )
788 PCL_PRECONDITION( IsValid() )
793 #ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
804 m_parallel ? m_maxProcessors : 1 );
805 AbstractImage::ThreadData data( monitor, m_Gx.Rows() );
806 ReferenceArray<LocalModelThread<PSI> > threads;
807 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
808 threads.Add(
new LocalModelThread<PSI>( data, *
this, PS, n, n +
int( L[i] ) ) );
817 void ApplyLocalModel(
const SI& Sx,
const SI& Sy,
818 const String& message =
"Applying local interpolation model",
819 bool verbose =
true )
821 PCL_PRECONDITION( IsValid() )
823 throw Error( "PointGridInterpolation::ApplyLocalModel(): Uninitialized interpolation." );
825 StatusMonitor monitor;
826 #ifndef __PCL_BUILDING_PIXINSIGHT_APPLICATION
827 StandardStatus status;
830 monitor.SetCallback( &status );
831 monitor.Initialize( message, m_Gx.Rows() );
837 m_parallel ? m_maxProcessors : 1 );
838 AbstractImage::ThreadData data( monitor, m_Gx.Rows() );
839 ReferenceArray<LocalModelThread2<SI> > threads;
840 for (
int i = 0, n = 0; i < int( L.Length() ); n += int( L[i++] ) )
841 threads.Add(
new LocalModelThread2<SI>( data, *
this, Sx, Sy, n, n +
int( L[i] ) ) );
852 return !m_Gx.IsEmpty() && !m_Gy.IsEmpty();
914 template <
typename T>
917 PCL_PRECONDITION( IsValid() )
918 double fx = (double( x ) - m_rect.
x0)/m_delta;
919 double fy = (double( y ) - m_rect.
y0)/m_delta;
920 return DPoint( m_Ix( fx, fy ), m_Iy( fx, fy ) );
926 template <
typename T>
929 return operator ()( p.
x, p.
y );
944 grid_interpolation m_Ix, m_Iy;
947 class GridInitializationThread :
public Thread
955 , m_surface( surface )
956 , m_startRow( startRow )
959 if ( m_surface.HasFastVectorEvaluation() )
969 PCL_HOT_FUNCTION
void Run()
override
973 if ( m_surface.HasFastVectorEvaluation() )
975 int i0 = m_startRow, j0 = 0, n = 0;
976 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
977 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
979 double x = m_grid.m_rect.x0;
980 for (
int j = 0; j < m_grid.m_Gx.Cols(); ++j, ++n, x += m_grid.m_delta )
984 m_surface.Evaluate( m_ZX.Begin(), m_ZY.Begin(), m_X.Begin(), m_Y.Begin(), n );
985 for (
int i1 = i0, k1 = 0; i1 <= i && k1 < n; ++i1, j0 = 0 )
986 for (
int j1 = j0; j1 < m_grid.m_Gx.Cols() && k1 < n; ++j1, ++k1 )
988 m_grid.m_Gx[i1][j1] = m_ZX[k1];
989 m_grid.m_Gy[i1][j1] = m_ZY[k1];
1005 m_surface.Evaluate( m_ZX.Begin(), m_ZY.Begin(), m_X.Begin(), m_Y.Begin(), n );
1006 for (
int i1 = i0, k1 = 0; i1 < m_endRow; ++i1, j0 = 0 )
1007 for (
int j1 = j0; j1 < m_grid.m_Gx.Cols(); ++j1, ++k1 )
1009 m_grid.m_Gx[i1][j1] = m_ZX[k1];
1010 m_grid.m_Gy[i1][j1] = m_ZY[k1];
1018 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
1019 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
1021 double x = m_grid.m_rect.x0;
1022 for (
int j = 0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
1024 DPoint p = m_surface( x, y );
1025 m_grid.m_Gx[i][j] = p.x;
1026 m_grid.m_Gy[i][j] = p.y;
1036 const AbstractImage::ThreadData& m_data;
1037 PointGridInterpolation& m_grid;
1038 const PSI& m_surface;
1039 int m_startRow, m_endRow, m_N;
1044 class GridInitializationXYThread :
public Thread
1048 GridInitializationXYThread(
const AbstractImage::ThreadData& data,
1049 PointGridInterpolation& grid,
1050 const SI& surfaceX,
const SI& surfaceY,
int startRow,
int endRow )
1053 , m_surfaceX( surfaceX )
1054 , m_surfaceY( surfaceY )
1055 , m_startRow( startRow )
1056 , m_endRow( endRow )
1058 if ( m_surfaceX.HasFastVectorEvaluation() && m_surfaceY.HasFastVectorEvaluation() )
1067 PCL_HOT_FUNCTION
void Run()
override
1071 if ( m_surfaceX.HasFastVectorEvaluation() && m_surfaceY.HasFastVectorEvaluation() )
1073 int i0 = m_startRow, j0 = 0, n = 0;
1074 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
1075 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
1077 double x = m_grid.m_rect.x0;
1078 for (
int j = 0; j < m_grid.m_Gx.Cols(); ++j, ++n, x += m_grid.m_delta )
1082 m_surfaceX.Evaluate( m_Z.Begin(), m_X.Begin(), m_Y.Begin(), n );
1083 for (
int i1 = i0, jj0 = j0, k1 = 0; i1 <= i && k1 < n; ++i1, jj0 = 0 )
1084 for (
int j1 = jj0; j1 < m_grid.m_Gx.Cols() && k1 < n; ++j1, ++k1 )
1085 m_grid.m_Gx[i1][j1] = m_Z[k1];
1086 m_surfaceY.Evaluate( m_Z.Begin(), m_X.Begin(), m_Y.Begin(), n );
1087 for (
int i1 = i0, jj0 = j0, k1 = 0; i1 <= i && k1 < n; ++i1, jj0 = 0 )
1088 for (
int j1 = jj0; j1 < m_grid.m_Gx.Cols() && k1 < n; ++j1, ++k1 )
1089 m_grid.m_Gy[i1][j1] = m_Z[k1];
1104 m_surfaceX.Evaluate( m_Z.Begin(), m_X.Begin(), m_Y.Begin(), n );
1105 for (
int i1 = i0, jj0 = j0, k1 = 0; i1 < m_endRow; ++i1, jj0 = 0 )
1106 for (
int j1 = jj0; j1 < m_grid.m_Gx.Cols(); ++j1, ++k1 )
1107 m_grid.m_Gx[i1][j1] = m_Z[k1];
1108 m_surfaceY.Evaluate( m_Z.Begin(), m_X.Begin(), m_Y.Begin(), n );
1109 for (
int i1 = i0, jj0 = j0, k1 = 0; i1 < m_endRow; ++i1, jj0 = 0 )
1110 for (
int j1 = jj0; j1 < m_grid.m_Gx.Cols(); ++j1, ++k1 )
1111 m_grid.m_Gy[i1][j1] = m_Z[k1];
1118 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
1119 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
1121 double x = m_grid.m_rect.x0;
1122 for (
int j = 0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
1124 m_grid.m_Gx[i][j] = m_surfaceX( x, y );
1125 m_grid.m_Gy[i][j] = m_surfaceY( x, y );
1135 const AbstractImage::ThreadData& m_data;
1136 PointGridInterpolation& m_grid;
1137 const SI& m_surfaceX;
1138 const SI& m_surfaceY;
1139 int m_startRow, m_endRow, m_N;
1143 template <
class PSI>
1144 class LocalModelThread :
public Thread
1148 LocalModelThread(
const AbstractImage::ThreadData& data,
1149 PointGridInterpolation& grid,
const PSI& model,
int startRow,
int endRow )
1153 , m_startRow( startRow )
1154 , m_endRow( endRow )
1158 PCL_HOT_FUNCTION
void Run()
override
1162 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
1163 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
1165 double x = m_grid.m_rect.x0;
1166 for (
int j = 0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
1168 DPoint d = m_model( x, y );
1169 m_grid.m_Gx[i][j] += d.x;
1170 m_grid.m_Gy[i][j] += d.y;
1179 const AbstractImage::ThreadData& m_data;
1180 PointGridInterpolation& m_grid;
1182 int m_startRow, m_endRow;
1186 class LocalModelThread2 :
public Thread
1190 LocalModelThread2(
const AbstractImage::ThreadData& data,
1191 PointGridInterpolation& grid,
const SI& modelX,
const SI& modelY,
int startRow,
int endRow )
1194 , m_modelX( modelX )
1195 , m_modelY( modelY )
1196 , m_startRow( startRow )
1197 , m_endRow( endRow )
1201 PCL_HOT_FUNCTION
void Run()
override
1205 double y = m_grid.m_rect.y0 + m_startRow*m_grid.m_delta;
1206 for (
int i = m_startRow; i < m_endRow; ++i, y += m_grid.m_delta )
1208 double x = m_grid.m_rect.x0;
1209 for (
int j = 0; j < m_grid.m_Gx.Cols(); ++j, x += m_grid.m_delta )
1211 m_grid.m_Gx[i][j] += m_modelX( x, y );
1212 m_grid.m_Gy[i][j] += m_modelY( x, y );
1221 const AbstractImage::ThreadData& m_data;
1222 PointGridInterpolation& m_grid;
1223 const SI& m_modelX, m_modelY;
1224 int m_startRow, m_endRow;
1227 friend class SplineWorldTransformation;
static void RunThreads(ReferenceArray< thread > &threads, ThreadData &data, bool useAffinity=true)
64-bit floating-point point in the R^2 space.
64-bit floating point real vector.
A simple exception with an associated error message.
Generic dynamic matrix of arbitrary dimensions.
int Cols() const noexcept
int Rows() const noexcept
A generic point in the two-dimensional space.
component x
Abscissa (horizontal, or X-axis coordinate).
component y
Ordinate (vertical, or Y-axis coordinate).
A generic rectangle in the two-dimensional space.
bool IsRect() const noexcept
component y0
Vertical coordinate of the upper left corner.
component x0
Horizontal coordinate of the upper left corner.
component Width() const noexcept
component Height() const noexcept
Generic vector of arbitrary length.
Discretized scalar surface interpolation/approximation in two dimensions.
GridInterpolation(GridInterpolation &&)=default
void Initialize(const R &rect, double delta, const DMatrix &G)
GridInterpolation(const GridInterpolation &)=default
const DMatrix & InterpolationMatrix() const
const DRect & ReferenceRect() const
GridInterpolation()=default
void Initialize(const R &rect, int delta, const SI &S, bool verbose=true)
A process using multiple concurrent execution threads.
Discretized vector surface interpolation/approximation in two dimensions.
void Initialize(const R &rect, double delta, const SI &Sx, const SI &Sy, bool verbose=true)
const DMatrix & XInterpolationMatrix() const
void Initialize(const R &rect, double delta, const PSI &PS, bool verbose=true)
PointGridInterpolation(const PointGridInterpolation &)=default
const DMatrix & YInterpolationMatrix() const
PointGridInterpolation()=default
void Initialize(const R &rect, int delta, const DMatrix &Gx, const DMatrix &Gy)
PointGridInterpolation(PointGridInterpolation &&)=default
const DRect & ReferenceRect() const
Dynamic array of pointers to objects providing direct iteration and element access by reference.
void Destroy(iterator i, size_type n=1)
void Add(const ReferenceArray &x)
A status monitoring callback that sends progress information to the process console.
An asynchronous status monitoring system.
void SetCallback(StatusCallback *callback)
void Initialize(const String &info, size_type count=0)
Client-side interface to a PixInsight thread.
static Array< size_type > OptimalThreadLoads(size_type count, size_type overheadLimit=1u, int maxThreads=PCL_MAX_PROCESSORS)
T Abs(const Complex< T > &c) noexcept
constexpr T Ceil(T x) noexcept
#define INIT_THREAD_MONITOR()
Declares and initializes local variables used for synchronization of thread status monitoring.
#define UPDATE_THREAD_MONITOR(N)
Synchronized status monitoring of a set of image processing threads.
constexpr const T & Min(const T &a, const T &b) noexcept
Thread synchronization data for status monitoring of parallel image processing tasks.