Support for XISF

This commit is contained in:
2022-04-12 08:17:18 +02:00
parent e5cd25cc77
commit 0fb27266c7
278 changed files with 209068 additions and 7 deletions
+681
View File
@@ -0,0 +1,681 @@
// ____ ______ __
// / __ \ / ____// /
// / /_/ // / / /
// / ____// /___ / /___ PixInsight Class Library
// /_/ \____//_____/ PCL 2.4.23
// ----------------------------------------------------------------------------
// pcl/WorldTransformation.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_WorldTransformation_h
#define __PCL_WorldTransformation_h
/// \file pcl/WorldTransformation.h
#include <pcl/Defs.h>
#include <pcl/GridInterpolation.h>
#include <pcl/LinearTransformation.h>
#include <pcl/SurfaceSpline.h>
#include <pcl/WCSKeywords.h>
/*
* Based on original work contributed by Andrés del Pozo.
*/
namespace pcl
{
// ----------------------------------------------------------------------------
#define __PCL_WCS_DEFAULT_SPLINE_ORDER 2
#define __PCL_WCS_DEFAULT_SPLINE_SMOOTHNESS 0.025F
#define __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_ENABLED true
#define __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_TOLERANCE 0.25F // px
#define __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_REJECT_FRACTION 0.10F
#define __PCL_WCS_MAX_SPLINE_POINTS 2100
// ----------------------------------------------------------------------------
/*!
* \class WorldTransformation
* \brief Abstract base class of world coordinate transformations
*
* \ingroup astrometry_support
*/
class PCL_CLASS WorldTransformation
{
public:
/*!
* Default constructor.
*/
WorldTransformation() = default;
/*!
* Copy constructor.
*/
WorldTransformation( const WorldTransformation& ) = default;
/*!
* Virtual destructor.
*/
virtual ~WorldTransformation()
{
}
/*!
* Returns true iff this transformation is empty (uninitialized, invalid).
*/
virtual bool IsEmpty() const
{
return false;
}
/*!
* Returns a dynamically allocated copy of this object.
*/
virtual WorldTransformation* Clone() const = 0;
/*!
* Transforms from native spherical coordinates to image coordinates.
*
* The point \a p contains native spherical coordinates: \a p.x is the
* native longitude and \a p.y is the native latitude, both expressed in
* degrees. Returns image coordinates in pixels corresponding to \a p.
*/
virtual DPoint Direct( const DPoint& p ) const = 0;
/*!
* Transforms from image coordinates to native spherical coordinates.
*
* The specified point \a p contains image coordinates in pixels. Returns a
* point \a q where \a q.x is the native longitude and \a q.y is the native
* latitude, both expressed in degrees, corresponding to \a p.
*/
virtual DPoint Inverse( const DPoint& p ) const = 0;
/*!
* Returns an approximate linear transformation from Image to World
* coordinates.
*/
virtual const LinearTransformation& ApproximateLinearTransform() const = 0;
};
// ----------------------------------------------------------------------------
/*!
* \class LinearWorldTransformation
* \brief WCS linear world coordinate transformation
*
* \ingroup astrometry_support
*/
class PCL_CLASS LinearWorldTransformation : public WorldTransformation
{
public:
/*!
* Constructor from a linear transformation. The specified transformation
* \a transIW must transform from image coordinates to native spherical
* coordinates.
*/
LinearWorldTransformation( const LinearTransformation& transIW )
: m_transWI( transIW.Inverse() )
, m_transIW( transIW )
{
}
/*!
* Copy constructor.
*/
LinearWorldTransformation( const LinearWorldTransformation& ) = default;
/*!
* Move constructor.
*/
LinearWorldTransformation( LinearWorldTransformation&& ) = default;
/*!
* Virtual destructor.
*/
virtual ~LinearWorldTransformation()
{
}
/*!
* Returns false, since a linear WCS transformation cannot be empty.
*/
bool IsEmpty() const override
{
return false;
}
/*!
*/
WorldTransformation* Clone() const override
{
return new LinearWorldTransformation( *this );
}
/*!
*/
DPoint Direct( const DPoint& p ) const override
{
return m_transWI.Transform( p );
}
/*!
*/
DPoint Inverse( const DPoint& p ) const override
{
return m_transIW.Transform( p );
}
/*!
* Returns a reference to the internal linear transformation (from image to
* native spherical coordinates).
*/
const LinearTransformation& ApproximateLinearTransform() const override
{
return m_transIW;
}
private:
LinearTransformation m_transWI; // world -> image
LinearTransformation m_transIW; // image -> world
};
// ----------------------------------------------------------------------------
/*!
* \class SplineWorldTransformation
* \brief Surface spline world coordinate transformation
*
* %SplineWorldTransformation implements a world coordinate transform based on
* 2-D interpolating/approximating surface splines (also known as <em>thin
* plates</em>). These mathematical modeling devices allow for accurate
* representations of coordinate systems subject to arbitrary local
* distortions, which are impossible to achieve with linear transformations.
*
* The underlying implementation of this class uses the SurfaceSpline,
* PointSurfaceSpline, SurfaceSimplifier and PointGridInterpolation classes.
*
* \ingroup astrometry_support
*/
class PCL_CLASS SplineWorldTransformation : public WorldTransformation
{
public:
/*!
* Constructs a 2-D spline based world coordinate transformation.
*
* \param controlPointsW Array of world control points. Each point in this
* array must contain spherical coordinates in the
* native world coordinate system of the astrometric
* solution, expressed in degrees. For a given
* point p in this array, p.x is the native
* longitude coordinate and p.y is the latitude.
*
* \param controlPointsI Array of image control points. Each point in this
* array must contain the coordinates on the X and Y
* axes of the image plane corresponding to the same
* point in the \a controlPointsW array. In other
* words, there must be a one-to-one correspondence
* between world and image control points.
*
* \param smoothness When this parameter is greater than zero,
* approximating splines will be generated instead
* of interpolating splines. The higher this value,
* the closest will be the 2-D approximating surface
* to the reference plane of the image.
* Approximating surface splines are robust to
* outlier control points and hence recommended in
* virtually all cases. The value of this parameter
* should be relatively small if \a enableSimplifier
* is true, since the surface simplification
* algorithm already performs robust rejection of
* outliers. The default value of 0.025 is normally
* quite appropriate.
*
* \param weights When the \a smoothness parameter is greater than
* zero and this vector is not empty, it must define
* a positive weight greater than zero for each
* point defined by the \a controlPointsW and
* \a controlPointsI arrays. If \a smoothness is
* zero or negative, this parameter will be ignored.
* See the PointSurfaceSpline::Initialize() member
* function for detailed information on 2-D spline
* node weights. If \a enableSimplifier is true,
* control point weights are not used and hence the
* value of this parameter will be ignored.
*
* \param order Derivative order of continuity. The default value
* is 2, which is also the recommended value. Higher
* orders may improve adaptability to complex field
* distortions only in some special cases, but at
* the risk of leading to ill-conditioned linear
* systems, and hence to errors while building the
* surface splines.
*
* \param enableSimplifier If true, a surface simplification algorithm will
* be applied to the lists of control points for
* surface spline generation. The use of surface
* simplification greatly improves efficiency of
* surface splines by removing all redundant points
* and keeping only the control points required to
* define the coordinate transformations accurately.
* In addition, the applied surface simplification
* algorithm implements robust PCA fitting and
* outlier rejection techniques that improve the
* generated interpolation devices in terms of
* resilience to noise and invalid data in the
* underlying astrometric solution. This option is
* enabled by default. When this parameter is true,
* the \a weights parameter is ignored.
*
* \param simplifierTolerance Tolerance of the surface simplification
* algorithm in pixels. The default value is 0.25
* pixels.
*
* \param simplifierRejectFraction Fraction of rejected control points for
* simplification of surface subregions. The default
* value is 0.10.
*
* Thanks to the implemented surface simplification algorithms, we can work
* with very large sets of control points to generate astrometric solutions
* able to model strong and complex arbitrary field distortions accurately
* and efficiently. Surface simplification concentrates control points just
* where they are necessary to represent distortions, leaving undistorted
* regions of the image covered by a minimal grid.
*
* Newly constructed instances are guaranteed to be valid (in the structural
* and numerical senses; note that this does not necessarily imply that the
* underlying astrometric solution is valid). In the event of invalid input
* data or spline initialization problems, this constructor will throw an
* Error exception.
*
* After surface spline initialization, an approximate linear transformation
* will also be calculated automatically.
*/
SplineWorldTransformation( const Array<DPoint>& controlPointsW,
const Array<DPoint>& controlPointsI,
float smoothness = __PCL_WCS_DEFAULT_SPLINE_SMOOTHNESS,
const FVector& weights = FVector(),
int order = __PCL_WCS_DEFAULT_SPLINE_ORDER,
bool enableSimplifier = __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_ENABLED,
float simplifierTolerance = __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_TOLERANCE,
float simplifierRejectFraction = __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_REJECT_FRACTION )
: m_controlPointsW( controlPointsW )
, m_controlPointsI( controlPointsI )
, m_order( order )
, m_smoothness( smoothness )
, m_weights( weights )
, m_enableSimplifier( enableSimplifier )
, m_simplifierTolerance( simplifierTolerance )
, m_simplifierRejectFraction( simplifierRejectFraction )
{
InitializeSplines();
CalculateLinearApproximation();
}
/*!
* Constructs a %SplineWorldTransformation instance by deserializing the
* specified raw \a data.
*
* An approximate linear transformation will be calculated automatically.
*/
SplineWorldTransformation( const ByteArray& data )
{
Deserialize( data );
InitializeSplines();
CalculateLinearApproximation();
}
/*!
* Constructs a %SplineWorldTransformation instance by deserializing the
* specified raw \a data, with a prescribed approximate linear
* transformation \a linearTransIW.
*/
SplineWorldTransformation( const ByteArray& data, const LinearTransformation& linearTransIW )
{
Deserialize( data );
InitializeSplines();
m_linearIW = linearTransIW;
}
/*!
* Copy constructor.
*/
SplineWorldTransformation( const SplineWorldTransformation& ) = default;
/*!
* Move constructor.
*/
SplineWorldTransformation( SplineWorldTransformation&& ) = default;
/*!
* Virtual destructor.
*/
virtual ~SplineWorldTransformation()
{
}
/*!
* Copy assignment operator. Returns a reference to this object.
*/
SplineWorldTransformation& operator =( const SplineWorldTransformation& ) = default;
/*!
* Move assignment operator. Returns a reference to this object.
*/
SplineWorldTransformation& operator =( SplineWorldTransformation&& ) = default;
/*!
* Returns true iff this object has no working data.
*
* With the restrictions imposed by class constructors, this can only happen
* if this object is an xvalue after move construction or assignment.
*/
bool IsEmpty() const override
{
return m_controlPointsW.IsEmpty() || m_controlPointsI.IsEmpty();
}
/*!
* Returns a dynamically allocated copy of this object.
*/
WorldTransformation* Clone() const override
{
return new SplineWorldTransformation( *this );
}
/*!
* Transforms from native spherical coordinates to image coordinates.
*
* The point \a p contains native spherical coordinates: \a p.x is the
* native longitude and \a p.y is the native latitude, both expressed in
* degrees. Returns image coordinates in pixels corresponding to \a p.
*
* If grid interpolations have been initialized for this object, and the
* specified point \a p is included in the reference rectangle used for grid
* initialization, they will be used transparently by this member function.
* Otherwise the surface splines will be evaluated directly, which can be
* much slower, depending on the number of control points defined by the
* astrometric solution.
*
* \sa Inverse(), InitializeGridInterpolations()
*/
DPoint Direct( const DPoint& p ) const override
{
if ( m_gridWI.IsValid() )
if ( m_gridWI.ReferenceRect().IncludesFast( p ) )
return m_gridWI( p );
return m_splineWI( p );
}
/*!
* Transforms from image coordinates to native spherical coordinates.
*
* The specified point \a p contains image coordinates in pixels. Returns a
* point \a q where \a q.x is the native longitude and \a q.y is the native
* latitude, both expressed in degrees, corresponding to \a p.
*
* If grid interpolations have been initialized for this object, and the
* specified point \a p is included in the reference rectangle used for grid
* initialization, they will be used transparently by this member function.
* Otherwise the surface splines will be evaluated directly, which can be
* much slower, depending on the number of control points defined by the
* astrometric solution.
*
* \sa Direct(), InitializeGridInterpolations()
*/
DPoint Inverse( const DPoint& p ) const override
{
if ( m_gridIW.IsValid() )
if ( m_gridIW.ReferenceRect().IncludesFast( p ) )
return m_gridIW( p );
return m_splineIW( p );
}
/*!
* Returns an approximate linear transformation from image to native
* spherical coordinates, computed from the internal point surface splines.
*/
const LinearTransformation& ApproximateLinearTransform() const override
{
return m_linearIW;
}
/*!
* Initializes the internal grid interpolation devices for the specified
* reference rectangular region \a rect and grid distance \a delta in
* pixels.
*
* A grid distance of 24 pixels is applied by default. This is normally more
* than sufficient to yield accurate coordinate readouts, even for strongly
* distorted images.
*
* See GridInterpolation::Initialize() for detailed information on spline
* grid interpolation and its working parameters.
*
* \note This member function will show no console messages. If some
* feedback must be provided to the user during the potentially long
* operation, it must be given before calling this function.
*/
void InitializeGridInterpolations( const Rect& rect, int delta = 24 )
{
m_gridWI.Initialize( rect, delta, m_splineWI, false/*verbose*/ );
m_gridIW.Initialize( rect, delta, m_splineIW, false/*verbose*/ );
}
/*!
* Returns true if the internal grid interpolation devices have been
* initialized. See InitializeGridInterpolations() for information on grid
* interpolation.
*/
bool HasGridInterpolations() const
{
return m_gridWI.IsValid() && m_gridIW.IsValid();
}
/*!
* Serializes this %SplineWorldTransformation instance in raw binary format
* and stores the result in the specified \a data array.
*/
void Serialize( ByteArray& data ) const;
/*!
* Returns the number of control points employed to generate the surface
* splines used for coordinate transformations.
*
* The value returned by this function is the length of the original list of
* control points specified upon object construction or deserialization; the
* actual sets of data points being used internally by surface splines are
* usually smaller because surface simplification is enabled by default.
*
* \sa NativeControlPoints(), ImageControlPoints(), GetSplineLengths()
*/
int NumberOfControlPoints() const
{
return int( m_controlPointsW.Length() );
}
/*!
* Returns a reference to the list of control points in native spherical
* coordinates.
*
* For each point \e p in the returned array, \e p.x is the native longitude
* and \e p.y is the native latitude, both expressed in degrees.
*
* For each point \a p in the returned array, there is a corresponding point
* \a q in the array of image control points returned by the
* \a ImageControlPoints() member function, whose \e q.x and \e q.y
* components are the image coordinates in pixels corresponding to \e p.
*/
const Array<DPoint>& NativeControlPoints() const
{
return m_controlPointsW;
}
/*!
* Returns a reference to the list of control points in image coordinates.
*
* For each point \e p in the returned array, \e p.x and \e p.y are the
* components of a control point in image coordinates, expressed in pixels.
*
* For each point \a p in the returned array, there is a corresponding point
* \a q in the array of native control points returned by the
* \a NativeControlPoints() member function, whose \e q.x and \e q.y
* components are the spherical native coordinates in degrees corresponding
* to \e p.
*/
const Array<DPoint>& ImageControlPoints() const
{
return m_controlPointsI;
}
/*!
* Provides the number of data points in the internal surface splines used
* for coordinate transformations.
*
* \param[out] xWI Number of spline points used for world-to-image
* coordinate transformations on the native longitude
* direction.
*
* \param[out] yWI Number of spline points used for world-to-image
* coordinate transformations on the native latitude
* direction.
*
* \param[out] xIW Number of spline points used for image-to-world
* coordinate transformations on the X-axis direction.
*
* \param[out] yIW Number of spline points used for image-to-world
* coordinate transformations on the Y-axis direction.
*/
void GetSplineLengths( int& xWI, int& yWI, int& xIW, int& yIW ) const
{
xWI = m_splineWI.SplineX().Length();
yWI = m_splineWI.SplineY().Length();
xIW = m_splineIW.SplineX().Length();
yIW = m_splineIW.SplineY().Length();
}
/*!
* Returns true iff the lists of transformation control points were
* truncated before generation of surface splines. If surface simplification
* is enabled, truncation may happen, when necessary, after simplification.
* If no simplification is used, truncation may happen directly on the
* original lists of control points.
*
* A maximum of 2100 control points is imposed in the current implementation
* to prevent excessive execution times for surface spline generation, which
* grow approximately with O(n^3) complexity.
*/
bool TruncatedControlPoints() const
{
return m_truncated;
}
/*!
* Returns true iff the surface simplification algorithm has been enabled
* for generation of surface splines. See the class constructor for more
* information.
*/
bool IsSimplifierEnabled() const
{
return m_enableSimplifier;
}
/*!
* Returns the tolerance in pixels of the surface simplifier used for
* generation of surface splines. See the class constructor for more
* information.
*/
float SimplifierTolerance() const
{
return m_simplifierTolerance;
}
/*!
* Returns the outlier rejection fraction of the surface simplifier used for
* generation of surface splines. See the class constructor for more
* information.
*/
float SimplifierRejectFraction() const
{
return m_simplifierRejectFraction;
}
private:
Array<DPoint> m_controlPointsW;
Array<DPoint> m_controlPointsI;
int m_order = __PCL_WCS_DEFAULT_SPLINE_ORDER;
float m_smoothness = __PCL_WCS_DEFAULT_SPLINE_SMOOTHNESS;
FVector m_weights;
bool m_enableSimplifier = __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_ENABLED;
float m_simplifierTolerance = __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_TOLERANCE;
float m_simplifierRejectFraction = __PCL_WCS_SURFACE_SIMPLIFIER_DEFAULT_REJECT_FRACTION;
bool m_truncated = false;
PointSurfaceSpline<DPoint> m_splineWI;
PointSurfaceSpline<DPoint> m_splineIW;
PointGridInterpolation m_gridWI;
PointGridInterpolation m_gridIW;
LinearTransformation m_linearIW;
void Deserialize( const ByteArray& );
void InitializeSplines();
void CalculateLinearApproximation();
};
// ----------------------------------------------------------------------------
} // pcl
#endif // __PCL_WorldTransformation_h
// ----------------------------------------------------------------------------
// EOF pcl/WorldTransformation.h - Released 2022-03-12T18:59:29Z