LCOV - code coverage report
Current view: directory - alg - gdal_tps.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 102 92 90.2 %
Date: 2012-12-26 Functions: 6 5 83.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdal_tps.cpp 25304 2012-12-13 21:03:58Z rouault $
       3                 :  *
       4                 :  * Project:  High Performance Image Reprojector
       5                 :  * Purpose:  Thin Plate Spline transformer (GDAL wrapper portion)
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "thinplatespline.h"
      31                 : #include "gdal_alg.h"
      32                 : #include "cpl_conv.h"
      33                 : #include "cpl_string.h"
      34                 : #include "cpl_atomic_ops.h"
      35                 : 
      36                 : CPL_CVSID("$Id: gdal_tps.cpp 25304 2012-12-13 21:03:58Z rouault $");
      37                 : 
      38                 : CPL_C_START
      39                 : CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg );
      40                 : void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree );
      41                 : CPL_C_END
      42                 : 
      43                 : typedef struct
      44                 : {
      45                 :     GDALTransformerInfo  sTI;
      46                 : 
      47                 :     VizGeorefSpline2D   *poForward;
      48                 :     VizGeorefSpline2D   *poReverse;
      49                 : 
      50                 :     int       bReversed;
      51                 : 
      52                 :     int       nGCPCount;
      53                 :     GDAL_GCP *pasGCPList;
      54                 :     
      55                 :     volatile int nRefCount;
      56                 :     
      57                 : } TPSTransformInfo;
      58                 : 
      59                 : /************************************************************************/
      60                 : /*                       GDALCloneTPSTransformer()                      */
      61                 : /************************************************************************/
      62                 : 
      63               0 : void* GDALCloneTPSTransformer( void *hTransformArg )
      64                 : {
      65               0 :     VALIDATE_POINTER1( hTransformArg, "GDALCloneTPSTransformer", NULL );
      66                 : 
      67                 :     TPSTransformInfo *psInfo = 
      68               0 :         (TPSTransformInfo *) hTransformArg;
      69                 : 
      70                 :     /* We can just use a ref count, since using the source transformation */
      71                 :     /* is thread-safe */
      72               0 :     CPLAtomicInc(&(psInfo->nRefCount));
      73                 : 
      74               0 :     return psInfo;
      75                 : }
      76                 : 
      77                 : /************************************************************************/
      78                 : /*                      GDALCreateTPSTransformer()                      */
      79                 : /************************************************************************/
      80                 : 
      81                 : /**
      82                 :  * Create Thin Plate Spline transformer from GCPs.
      83                 :  *
      84                 :  * The thin plate spline transformer produces exact transformation
      85                 :  * at all control points and smoothly varying transformations between
      86                 :  * control points with greatest influence from local control points. 
      87                 :  * It is suitable for for many applications not well modelled by polynomial
      88                 :  * transformations. 
      89                 :  *
      90                 :  * Creating the TPS transformer involves solving systems of linear equations
      91                 :  * related to the number of control points involved.  This solution is
      92                 :  * computed within this function call.  It can be quite an expensive operation
      93                 :  * for large numbers of GCPs.  For instance, for reference, it takes on the 
      94                 :  * order of 10s for 400 GCPs on a 2GHz Athlon processor. 
      95                 :  *
      96                 :  * TPS Transformers are serializable. 
      97                 :  *
      98                 :  * The GDAL Thin Plate Spline transformer is based on code provided by
      99                 :  * Gilad Ronnen on behalf of VIZRT Inc (http://www.visrt.com).  Incorporation 
     100                 :  * of the algorithm into GDAL was supported by the Centro di Ecologia Alpina 
     101                 :  * (http://www.cealp.it). 
     102                 :  *
     103                 :  * @param nGCPCount the number of GCPs in pasGCPList.
     104                 :  * @param pasGCPList an array of GCPs to be used as input.
     105                 :  * @param bReversed set it to TRUE to compute the reversed transformation.
     106                 :  * 
     107                 :  * @return the transform argument or NULL if creation fails. 
     108                 :  */
     109                 : 
     110               6 : void *GDALCreateTPSTransformer( int nGCPCount, const GDAL_GCP *pasGCPList, 
     111                 :                                 int bReversed )
     112                 : 
     113                 : {
     114                 :     TPSTransformInfo *psInfo;
     115                 :     int    iGCP;
     116                 : 
     117                 : /* -------------------------------------------------------------------- */
     118                 : /*      Allocate transform info.                                        */
     119                 : /* -------------------------------------------------------------------- */
     120               6 :     psInfo = (TPSTransformInfo *) CPLCalloc(sizeof(TPSTransformInfo),1);
     121                 : 
     122               6 :     psInfo->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
     123               6 :     psInfo->nGCPCount = nGCPCount;
     124                 : 
     125               6 :     psInfo->bReversed = bReversed;
     126               6 :     psInfo->poForward = new VizGeorefSpline2D( 2 );
     127              12 :     psInfo->poReverse = new VizGeorefSpline2D( 2 );
     128                 : 
     129               6 :     strcpy( psInfo->sTI.szSignature, "GTI" );
     130               6 :     psInfo->sTI.pszClassName = "GDALTPSTransformer";
     131               6 :     psInfo->sTI.pfnTransform = GDALTPSTransform;
     132               6 :     psInfo->sTI.pfnCleanup = GDALDestroyTPSTransformer;
     133               6 :     psInfo->sTI.pfnSerialize = GDALSerializeTPSTransformer;
     134                 : 
     135                 : /* -------------------------------------------------------------------- */
     136                 : /*      Attach all the points to the transformation.                    */
     137                 : /* -------------------------------------------------------------------- */
     138              29 :     for( iGCP = 0; iGCP < nGCPCount; iGCP++ )
     139                 :     {
     140                 :         double    afPL[2], afXY[2];
     141                 : 
     142              23 :         afPL[0] = pasGCPList[iGCP].dfGCPPixel;
     143              23 :         afPL[1] = pasGCPList[iGCP].dfGCPLine;
     144              23 :         afXY[0] = pasGCPList[iGCP].dfGCPX;
     145              23 :         afXY[1] = pasGCPList[iGCP].dfGCPY;
     146                 : 
     147              23 :         if( bReversed )
     148                 :         {
     149               0 :             psInfo->poReverse->add_point( afPL[0], afPL[1], afXY );
     150               0 :             psInfo->poForward->add_point( afXY[0], afXY[1], afPL );
     151                 :         }
     152                 :         else
     153                 :         {
     154              23 :             psInfo->poForward->add_point( afPL[0], afPL[1], afXY );
     155              23 :             psInfo->poReverse->add_point( afXY[0], afXY[1], afPL );
     156                 :         }
     157                 :     }
     158                 : 
     159               6 :     psInfo->nRefCount = 1;
     160                 : 
     161               6 :     psInfo->poForward->solve();
     162               6 :     psInfo->poReverse->solve();
     163                 : 
     164               6 :     return psInfo;
     165                 : }
     166                 : 
     167                 : /************************************************************************/
     168                 : /*                     GDALDestroyTPSTransformer()                      */
     169                 : /************************************************************************/
     170                 : 
     171                 : /**
     172                 :  * Destroy TPS transformer.
     173                 :  *
     174                 :  * This function is used to destroy information about a GCP based
     175                 :  * polynomial transformation created with GDALCreateTPSTransformer(). 
     176                 :  *
     177                 :  * @param pTransformArg the transform arg previously returned by 
     178                 :  * GDALCreateTPSTransformer(). 
     179                 :  */
     180                 : 
     181               6 : void GDALDestroyTPSTransformer( void *pTransformArg )
     182                 : 
     183                 : {
     184               6 :     VALIDATE_POINTER0( pTransformArg, "GDALDestroyTPSTransformer" );
     185                 : 
     186               6 :     TPSTransformInfo *psInfo = (TPSTransformInfo *) pTransformArg;
     187                 : 
     188               6 :     if( CPLAtomicDec(&(psInfo->nRefCount)) == 0 )
     189                 :     {
     190               6 :         delete psInfo->poForward;
     191               6 :         delete psInfo->poReverse;
     192                 : 
     193               6 :         GDALDeinitGCPs( psInfo->nGCPCount, psInfo->pasGCPList );
     194               6 :         CPLFree( psInfo->pasGCPList );
     195                 :         
     196               6 :         CPLFree( pTransformArg );
     197                 :     }
     198                 : }
     199                 : 
     200                 : /************************************************************************/
     201                 : /*                          GDALTPSTransform()                          */
     202                 : /************************************************************************/
     203                 : 
     204                 : /**
     205                 :  * Transforms point based on GCP derived polynomial model.
     206                 :  *
     207                 :  * This function matches the GDALTransformerFunc signature, and can be
     208                 :  * used to transform one or more points from pixel/line coordinates to
     209                 :  * georeferenced coordinates (SrcToDst) or vice versa (DstToSrc).
     210                 :  *
     211                 :  * @param pTransformArg return value from GDALCreateTPSTransformer(). 
     212                 :  * @param bDstToSrc TRUE if transformation is from the destination 
     213                 :  * (georeferenced) coordinates to pixel/line or FALSE when transforming
     214                 :  * from pixel/line to georeferenced coordinates.
     215                 :  * @param nPointCount the number of values in the x, y and z arrays.
     216                 :  * @param x array containing the X values to be transformed.
     217                 :  * @param y array containing the Y values to be transformed.
     218                 :  * @param z array containing the Z values to be transformed.
     219                 :  * @param panSuccess array in which a flag indicating success (TRUE) or
     220                 :  * failure (FALSE) of the transformation are placed.
     221                 :  *
     222                 :  * @return TRUE.
     223                 :  */
     224                 : 
     225            1826 : int GDALTPSTransform( void *pTransformArg, int bDstToSrc, 
     226                 :                       int nPointCount, 
     227                 :                       double *x, double *y, double *z, 
     228                 :                       int *panSuccess )
     229                 : 
     230                 : {
     231            1826 :     VALIDATE_POINTER1( pTransformArg, "GDALTPSTransform", 0 );
     232                 : 
     233                 :     int    i;
     234            1826 :     TPSTransformInfo *psInfo = (TPSTransformInfo *) pTransformArg;
     235                 : 
     236            4390 :     for( i = 0; i < nPointCount; i++ )
     237                 :     {
     238                 :         double xy_out[2];
     239                 : 
     240            2564 :         if( bDstToSrc )
     241                 :         {
     242            1423 :             psInfo->poReverse->get_point( x[i], y[i], xy_out );
     243            1423 :             x[i] = xy_out[0];
     244            1423 :             y[i] = xy_out[1];
     245                 :         }
     246                 :         else
     247                 :         {
     248            1141 :             psInfo->poForward->get_point( x[i], y[i], xy_out );
     249            1141 :             x[i] = xy_out[0];
     250            1141 :             y[i] = xy_out[1];
     251                 :         }
     252            2564 :         panSuccess[i] = TRUE;
     253                 :     }
     254                 : 
     255            1826 :     return TRUE;
     256                 : }
     257                 : 
     258                 : /************************************************************************/
     259                 : /*                    GDALSerializeTPSTransformer()                     */
     260                 : /************************************************************************/
     261                 : 
     262               1 : CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg )
     263                 : 
     264                 : {
     265               1 :     VALIDATE_POINTER1( pTransformArg, "GDALSerializeTPSTransformer", NULL );
     266                 : 
     267                 :     CPLXMLNode *psTree;
     268               1 :     TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(pTransformArg);
     269                 : 
     270               1 :     psTree = CPLCreateXMLNode( NULL, CXT_Element, "TPSTransformer" );
     271                 : 
     272                 : /* -------------------------------------------------------------------- */
     273                 : /*      Serialize bReversed.                                            */
     274                 : /* -------------------------------------------------------------------- */
     275                 :     CPLCreateXMLElementAndValue( 
     276                 :         psTree, "Reversed", 
     277               1 :         CPLString().Printf( "%d", psInfo->bReversed ) );
     278                 :                                  
     279                 : /* -------------------------------------------------------------------- */
     280                 : /*  Attach GCP List.            */
     281                 : /* -------------------------------------------------------------------- */
     282               1 :     if( psInfo->nGCPCount > 0 )
     283                 :     {
     284                 :         int iGCP;
     285                 :         CPLXMLNode *psGCPList = CPLCreateXMLNode( psTree, CXT_Element, 
     286               1 :                                                   "GCPList" );
     287                 : 
     288               5 :         for( iGCP = 0; iGCP < psInfo->nGCPCount; iGCP++ )
     289                 :         {
     290                 :             CPLXMLNode *psXMLGCP;
     291               4 :             GDAL_GCP *psGCP = psInfo->pasGCPList + iGCP;
     292                 : 
     293               4 :             psXMLGCP = CPLCreateXMLNode( psGCPList, CXT_Element, "GCP" );
     294                 : 
     295               4 :             CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );
     296                 : 
     297               4 :             if( psGCP->pszInfo != NULL && strlen(psGCP->pszInfo) > 0 )
     298               0 :                 CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );
     299                 : 
     300                 :             CPLSetXMLValue( psXMLGCP, "#Pixel", 
     301               4 :                             CPLString().Printf( "%.4f", psGCP->dfGCPPixel ) );
     302                 : 
     303                 :             CPLSetXMLValue( psXMLGCP, "#Line", 
     304               8 :                             CPLString().Printf( "%.4f", psGCP->dfGCPLine ) );
     305                 : 
     306                 :             CPLSetXMLValue( psXMLGCP, "#X", 
     307               8 :                             CPLString().Printf( "%.12E", psGCP->dfGCPX ) );
     308                 : 
     309                 :             CPLSetXMLValue( psXMLGCP, "#Y", 
     310               8 :                             CPLString().Printf( "%.12E", psGCP->dfGCPY ) );
     311                 : 
     312               4 :             if( psGCP->dfGCPZ != 0.0 )
     313                 :                 CPLSetXMLValue( psXMLGCP, "#GCPZ", 
     314               0 :                                 CPLString().Printf( "%.12E", psGCP->dfGCPZ ) );
     315                 :         }
     316                 :     }
     317                 : 
     318               1 :     return psTree;
     319                 : }
     320                 : 
     321                 : /************************************************************************/
     322                 : /*                   GDALDeserializeTPSTransformer()                    */
     323                 : /************************************************************************/
     324                 : 
     325               1 : void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree )
     326                 : 
     327                 : {
     328               1 :     GDAL_GCP *pasGCPList = 0;
     329               1 :     int nGCPCount = 0;
     330                 :     void *pResult;
     331                 :     int bReversed;
     332                 : 
     333                 :     /* -------------------------------------------------------------------- */
     334                 :     /*      Check for GCPs.                                                 */
     335                 :     /* -------------------------------------------------------------------- */
     336               1 :     CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
     337                 : 
     338               1 :     if( psGCPList != NULL )
     339                 :     {
     340               1 :         int  nGCPMax = 0;
     341                 :         CPLXMLNode *psXMLGCP;
     342                 :          
     343                 :         // Count GCPs.
     344               5 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     345                 :              psXMLGCP = psXMLGCP->psNext )
     346               4 :             nGCPMax++;
     347                 :          
     348               1 :         pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPMax);
     349                 : 
     350               5 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     351                 :              psXMLGCP = psXMLGCP->psNext )
     352                 :         {
     353               4 :             GDAL_GCP *psGCP = pasGCPList + nGCPCount;
     354                 : 
     355               4 :             if( !EQUAL(psXMLGCP->pszValue,"GCP") || 
     356                 :                 psXMLGCP->eType != CXT_Element )
     357               0 :                 continue;
     358                 :              
     359               4 :             GDALInitGCPs( 1, psGCP );
     360                 :              
     361               4 :             CPLFree( psGCP->pszId );
     362               4 :             psGCP->pszId = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Id",""));
     363                 :              
     364               4 :             CPLFree( psGCP->pszInfo );
     365               4 :             psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
     366                 :              
     367               4 :             psGCP->dfGCPPixel = atof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
     368               4 :             psGCP->dfGCPLine = atof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
     369                 :              
     370               4 :             psGCP->dfGCPX = atof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
     371               4 :             psGCP->dfGCPY = atof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
     372               4 :             psGCP->dfGCPZ = atof(CPLGetXMLValue(psXMLGCP,"Z","0.0"));
     373               4 :             nGCPCount++;
     374                 :         }
     375                 :     }
     376                 : 
     377                 : /* -------------------------------------------------------------------- */
     378                 : /*      Get other flags.                                                */
     379                 : /* -------------------------------------------------------------------- */
     380               1 :     bReversed = atoi(CPLGetXMLValue(psTree,"Reversed","0"));
     381                 : 
     382                 : /* -------------------------------------------------------------------- */
     383                 : /*      Generate transformation.                                        */
     384                 : /* -------------------------------------------------------------------- */
     385               1 :     pResult = GDALCreateTPSTransformer( nGCPCount, pasGCPList, bReversed );
     386                 :     
     387                 : /* -------------------------------------------------------------------- */
     388                 : /*      Cleanup GCP copy.                                               */
     389                 : /* -------------------------------------------------------------------- */
     390               1 :     GDALDeinitGCPs( nGCPCount, pasGCPList );
     391               1 :     CPLFree( pasGCPList );
     392                 : 
     393               1 :     return pResult;
     394                 : }

Generated by: LCOV version 1.7