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

407 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ____ ______ __
// / __ \ / ____// /
// / /_/ // / / /
// / ____// /___ / /___ PixInsight Class Library
// /_/ \____//_____/ PCL 2.4.23
// ----------------------------------------------------------------------------
// pcl/Homography.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_Homography_h
#define __PCL_Homography_h
/// \file pcl/Homography.h
#include <pcl/Defs.h>
#include <pcl/Diagnostics.h>
#include <pcl/Algebra.h>
#include <pcl/Array.h>
#include <pcl/Matrix.h>
#include <pcl/Point.h>
namespace pcl
{
// ----------------------------------------------------------------------------
/*!
* \class Homography
* \brief Homography geometric transformation.
*
* A two-dimensional projective transformation, or \e homography, is a
* line-preserving geometric transformation between two sets of points in the
* plane. More formally, if P represents the set of points in the plane, a
* homography is an invertible mapping H from P^2 to itself such that three
* points p1, p2, p3 are collinear if and only if H(p1), H(p2), H(p3) do.
*
* Homographies have important practical applications in the field of computer
* vision. On the PixInsight platform, this class is an essential component of
* image registration and astrometry processes.
*/
template <class P = DPoint>
class PCL_CLASS Homography
{
public:
/*!
* Represents a reference point in two dimensions.
*/
typedef P point;
/*!
* Represents a list of two-dimensional reference points involved in a
* homography transformation.
*/
typedef Array<point> point_list;
/*!
* Default constructor. Constructs a no-op transformation with a unit matrix
* transformation matrix.
*/
Homography()
: m_H( Matrix::UnitMatrix( 3 ) )
{
}
/*!
* Constructor from a given homography matrix.
*/
Homography( const Matrix& H )
: m_H( H )
{
}
/*!
* Constructor from two 2D point lists.
*
* Computes a homography transformation to generate a list \a P2 of
* transformed points from a list \a P1 of original points. In other words,
* the computed homography H works as follows:
*
* P2 = H( P1 )
*
* The transformation matrix is calculated by the Direct Linear
* Transformation (DLT) method. Both point lists must contain at least four
* points.
*
* If one of the specified point lists contains less than four points, or if
* no homography can be estimated from the specified point lists (which
* leads to a singular transformation matrix), this constructor throws an
* appropriate Error exception.
*
* \b References
*
* R. Hartley, <em>In defense of the eight-point algorithm.</em> IEEE
* Transactions on Pattern Analysis and Machine Intelligence, vol. 19, pp.
* 580593, June 1997.
*/
Homography( const point_list& P1, const point_list& P2 )
: m_H( DLT( P1, P2 ) )
{
}
/*!
* Copy constructor.
*/
Homography( const Homography& ) = default;
/*!
* Copy assignment operator.
*/
Homography& operator =( const Homography& ) = default;
/*!
* Move constructor.
*/
Homography( Homography&& ) = default;
/*!
* Move assignment operator.
*/
Homography& operator =( Homography&& ) = default;
/*!
* Coordinate transformation operator. Applies the homography matrix to the
* specified \a x and \a y coordinates. Returns the transformed point as a
* two-dimensional point with real coordinates.
*/
template <typename T>
DPoint operator ()( T x, T y ) const
{
double w = m_H[2][0]*x + m_H[2][1]*y + m_H[2][2];
PCL_CHECK( 1 + w != 1 )
return DPoint( (m_H[0][0]*x + m_H[0][1]*y + m_H[0][2])/w,
(m_H[1][0]*x + m_H[1][1]*y + m_H[1][2])/w );
}
/*!
* Point transformation operator. Applies the homography matrix to the
* coordinates of the specified point \a p. Returns the transformed point as
* a two-dimensional point with real coordinates.
*/
template <typename T>
DPoint operator ()( const GenericPoint<T>& p ) const
{
return operator ()( p.x, p.y );
}
/*!
* Returns the inverse of this homography transformation.
*
* If this transformation has been computed from two point lists \a P1 and
* \a P2:
*
* P2 = H( P1 )
*
* then this function returns a transformation H1 such that:
*
* P1 = H1( P2 )
*/
Homography Inverse() const
{
return Homography( m_H.Inverse() );
}
/*!
* Returns the homography transformation matrix.
*/
operator const Matrix&() const
{
return m_H;
}
/*!
* Returns true iff this transformation has been initialized and is valid.
*/
bool IsValid() const
{
return !m_H.IsEmpty();
}
/*!
* Returns true iff this is an affine homography transformation.
*
* An affine homography is a special type of a general homography where the
* last row of the 3x3 transformation matrix is equal to (0, 0, 1). This
* function verifies that this property holds for the current transformation
* matrix (if it is valid) up to the machine epsilon for the \c double
* numeric type.
*/
bool IsAffine() const
{
return IsValid()
&& Abs( m_H[2][0] ) <= std::numeric_limits<double>::epsilon()
&& Abs( m_H[2][1] ) <= std::numeric_limits<double>::epsilon()
&& 1 - Abs( m_H[2][2] ) <= std::numeric_limits<double>::epsilon();
}
/*!
* Ensures that the transformation uniquely references its internal matrix
* data.
*/
void EnsureUnique()
{
m_H.EnsureUnique();
}
private:
Matrix m_H;
/*
* Normalization of reference points.
*/
struct NormalizedPoints
{
Array<DPoint> N; // the normalized points
Matrix T; // 3x3 normalization matrix
NormalizedPoints( const point_list& points )
{
/*
* Calculate the centroid of the input set of points.
*/
DPoint centroid( 0 );
for ( const auto& p : points )
centroid += p;
centroid /= points.Length();
/*
* Calculate mean centroid distance and move origin to the centroid.
*/
double d0 = 0;
for ( const auto& p : points )
{
double x = p.x - centroid.x;
double y = p.y - centroid.y;
N << DPoint( x, y );
d0 += Sqrt( x*x + y*y );
}
d0 /= points.Length();
/*
* Scale point coordinates.
*/
double scale = Const<double>::sqrt2()/d0;
for ( auto& p : N )
p *= scale;
/*
* Form the normalization matrix.
*/
T = Matrix( scale, 0.0, -scale*centroid.x,
0.0, scale, -scale*centroid.y,
0.0, 0.0, 1.0 );
}
};
/*
* Implementation of the Direct Linear Transformation (DLT) method to
* compute a normalized homography matrix.
*/
static Matrix DLT( const point_list& P1, const point_list& P2 )
{
int n = Min( P1.Length(), P2.Length() );
if ( n < 4 )
throw Error( "Homography::DLT(): Less than four points specified." );
/*
* Normalize all points.
*/
NormalizedPoints p1( P1 );
NormalizedPoints p2( P2 );
/*
* Setup cross product matrix A.
*/
Matrix A( 2*n, 9 );
for ( int i = 0; i < n; ++i )
{
double x1 = p1.N[i].x;
double y1 = p1.N[i].y;
double x2 = p2.N[i].x;
double y2 = p2.N[i].y;
double* A0 = A[2*i];
double* A1 = A[2*i + 1];
//double* A2 = A[3*i + 2]; <-- linearly dependent eqn.
A0[0] = A0[1] = A0[2] = 0;
A0[3] = -x1;
A0[4] = -y1;
A0[5] = -1;
A0[6] = y2*x1;
A0[7] = y2*y1;
A0[8] = y2;
A1[0] = x1;
A1[1] = y1;
A1[2] = 1;
A1[3] = A1[4] = A1[5] = 0;
A1[6] = -x2*x1;
A1[7] = -x2*y1;
A1[8] = -x2;
/* <-- linearly dependent eqn.
A2[0] = -y2*x1;
A2[1] = -y2*y1;
A2[2] = -y2;
A2[3] = x2*x1;
A2[4] = x2*y1;
A2[5] = x2;
A2[6] = A2[7] = A2[8] = 0;
*/
}
/*
* SVD of cross product matrix.
*/
InPlaceSVD svd( A );
/*
* For sanity, set to zero all insignificant singular values.
*/
for ( int i = 0; i < svd.W.Length(); ++i )
if ( Abs( svd.W[i] ) <= std::numeric_limits<double>::epsilon() )
svd.W[i] = 0;
/*
* Locate the smallest nonzero singular value.
*/
int i = svd.IndexOfSmallestSingularValue();
/*
* The components of the homography matrix are those of the smallest
* eigenvector, i.e. the column vector of V corresponding to the smallest
* singular value.
*/
Matrix H( svd.V[0][i], svd.V[1][i], svd.V[2][i],
svd.V[3][i], svd.V[4][i], svd.V[5][i],
svd.V[6][i], svd.V[7][i], svd.V[8][i] );
if ( Abs( H[2][2] ) <= std::numeric_limits<double>::epsilon() )
throw Error( "Homography::DLT(): Singular matrix." );
/*
* Denormalize matrix components.
*/
H = p2.T.Inverse() * H * p1.T;
/*
* Normalize matrix so that H[2][2] = 1.
*/
return H *= 1/H[2][2];
}
};
// ----------------------------------------------------------------------------
} // pcl
#endif // __PCL_Homography_h
// ----------------------------------------------------------------------------
// EOF pcl/Homography.h - Released 2022-03-12T18:59:29Z