LCOV - code coverage report
Current view: directory - alg - gdal_tps.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 95 44 46.3 %
Date: 2010-01-09 Functions: 5 3 60.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdal_tps.cpp 16861 2009-04-26 19:22:29Z 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                 : 
      35                 : CPL_CVSID("$Id: gdal_tps.cpp 16861 2009-04-26 19:22:29Z rouault $");
      36                 : 
      37                 : CPL_C_START
      38                 : CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg );
      39                 : void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree );
      40                 : CPL_C_END
      41                 : 
      42                 : typedef struct
      43                 : {
      44                 :     GDALTransformerInfo  sTI;
      45                 : 
      46                 :     VizGeorefSpline2D   *poForward;
      47                 :     VizGeorefSpline2D   *poReverse;
      48                 : 
      49                 :     int       bReversed;
      50                 : 
      51                 :     int       nGCPCount;
      52                 :     GDAL_GCP *pasGCPList;
      53                 :     
      54                 : } TPSTransformInfo;
      55                 : 
      56                 : /************************************************************************/
      57                 : /*                      GDALCreateTPSTransformer()                      */
      58                 : /************************************************************************/
      59                 : 
      60                 : /**
      61                 :  * Create Thin Plate Spline transformer from GCPs.
      62                 :  *
      63                 :  * The thin plate spline transformer produces exact transformation
      64                 :  * at all control points and smoothly varying transformations between
      65                 :  * control points with greatest influence from local control points. 
      66                 :  * It is suitable for for many applications not well modelled by polynomial
      67                 :  * transformations. 
      68                 :  *
      69                 :  * Creating the TPS transformer involves solving systems of linear equations
      70                 :  * related to the number of control points involved.  This solution is
      71                 :  * computed within this function call.  It can be quite an expensive operation
      72                 :  * for large numbers of GCPs.  For instance, for reference, it takes on the 
      73                 :  * order of 10s for 400 GCPs on a 2GHz Athlon processor. 
      74                 :  *
      75                 :  * TPS Transformers are serializable. 
      76                 :  *
      77                 :  * The GDAL Thin Plate Spline transformer is based on code provided by
      78                 :  * Gilad Ronnen on behalf of VIZRT Inc (http://www.visrt.com).  Incorporation 
      79                 :  * of the algorithm into GDAL was supported by the Centro di Ecologia Alpina 
      80                 :  * (http://www.cealp.it). 
      81                 :  *
      82                 :  * @param nGCPCount the number of GCPs in pasGCPList.
      83                 :  * @param pasGCPList an array of GCPs to be used as input.
      84                 :  * @Param bReversed 
      85                 :  * 
      86                 :  * @return the transform argument or NULL if creation fails. 
      87                 :  */
      88                 : 
      89               4 : void *GDALCreateTPSTransformer( int nGCPCount, const GDAL_GCP *pasGCPList, 
      90                 :                                 int bReversed )
      91                 : 
      92                 : {
      93                 :     TPSTransformInfo *psInfo;
      94                 :     int    iGCP;
      95                 : 
      96                 : /* -------------------------------------------------------------------- */
      97                 : /*      Allocate transform info.                                        */
      98                 : /* -------------------------------------------------------------------- */
      99               4 :     psInfo = (TPSTransformInfo *) CPLCalloc(sizeof(TPSTransformInfo),1);
     100                 : 
     101               4 :     psInfo->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
     102               4 :     psInfo->nGCPCount = nGCPCount;
     103                 : 
     104               4 :     psInfo->bReversed = bReversed;
     105               4 :     psInfo->poForward = new VizGeorefSpline2D( 2 );
     106               8 :     psInfo->poReverse = new VizGeorefSpline2D( 2 );
     107                 : 
     108               4 :     strcpy( psInfo->sTI.szSignature, "GTI" );
     109               4 :     psInfo->sTI.pszClassName = "GDALTPSTransformer";
     110               4 :     psInfo->sTI.pfnTransform = GDALTPSTransform;
     111               4 :     psInfo->sTI.pfnCleanup = GDALDestroyTPSTransformer;
     112               4 :     psInfo->sTI.pfnSerialize = GDALSerializeTPSTransformer;
     113                 : 
     114                 : /* -------------------------------------------------------------------- */
     115                 : /*      Attach all the points to the transformation.                    */
     116                 : /* -------------------------------------------------------------------- */
     117              20 :     for( iGCP = 0; iGCP < nGCPCount; iGCP++ )
     118                 :     {
     119                 :         double    afPL[2], afXY[2];
     120                 : 
     121              16 :         afPL[0] = pasGCPList[iGCP].dfGCPPixel;
     122              16 :         afPL[1] = pasGCPList[iGCP].dfGCPLine;
     123              16 :         afXY[0] = pasGCPList[iGCP].dfGCPX;
     124              16 :         afXY[1] = pasGCPList[iGCP].dfGCPY;
     125                 : 
     126              16 :         if( bReversed )
     127                 :         {
     128               0 :             psInfo->poReverse->add_point( afPL[0], afPL[1], afXY );
     129               0 :             psInfo->poForward->add_point( afXY[0], afXY[1], afPL );
     130                 :         }
     131                 :         else
     132                 :         {
     133              16 :             psInfo->poForward->add_point( afPL[0], afPL[1], afXY );
     134              16 :             psInfo->poReverse->add_point( afXY[0], afXY[1], afPL );
     135                 :         }
     136                 :     }
     137                 : 
     138               4 :     psInfo->poForward->solve();
     139               4 :     psInfo->poReverse->solve();
     140                 : 
     141               4 :     return psInfo;
     142                 : }
     143                 : 
     144                 : /************************************************************************/
     145                 : /*                     GDALDestroyTPSTransformer()                      */
     146                 : /************************************************************************/
     147                 : 
     148                 : /**
     149                 :  * Destroy TPS transformer.
     150                 :  *
     151                 :  * This function is used to destroy information about a GCP based
     152                 :  * polynomial transformation created with GDALCreateTPSTransformer(). 
     153                 :  *
     154                 :  * @param pTransformArg the transform arg previously returned by 
     155                 :  * GDALCreateTPSTransformer(). 
     156                 :  */
     157                 : 
     158               4 : void GDALDestroyTPSTransformer( void *pTransformArg )
     159                 : 
     160                 : {
     161               4 :     VALIDATE_POINTER0( pTransformArg, "GDALDestroyTPSTransformer" );
     162                 : 
     163               4 :     TPSTransformInfo *psInfo = (TPSTransformInfo *) pTransformArg;
     164                 : 
     165               4 :     delete psInfo->poForward;
     166               4 :     delete psInfo->poReverse;
     167                 : 
     168               4 :     GDALDeinitGCPs( psInfo->nGCPCount, psInfo->pasGCPList );
     169               4 :     CPLFree( psInfo->pasGCPList );
     170                 :     
     171               4 :     CPLFree( pTransformArg );
     172                 : }
     173                 : 
     174                 : /************************************************************************/
     175                 : /*                          GDALTPSTransform()                          */
     176                 : /************************************************************************/
     177                 : 
     178                 : /**
     179                 :  * Transforms point based on GCP derived polynomial model.
     180                 :  *
     181                 :  * This function matches the GDALTransformerFunc signature, and can be
     182                 :  * used to transform one or more points from pixel/line coordinates to
     183                 :  * georeferenced coordinates (SrcToDst) or vice versa (DstToSrc).
     184                 :  *
     185                 :  * @param pTransformArg return value from GDALCreateTPSTransformer(). 
     186                 :  * @param bDstToSrc TRUE if transformation is from the destination 
     187                 :  * (georeferenced) coordinates to pixel/line or FALSE when transforming
     188                 :  * from pixel/line to georeferenced coordinates.
     189                 :  * @param nPointCount the number of values in the x, y and z arrays.
     190                 :  * @param x array containing the X values to be transformed.
     191                 :  * @param y array containing the Y values to be transformed.
     192                 :  * @param z array containing the Z values to be transformed.
     193                 :  * @param panSuccess array in which a flag indicating success (TRUE) or
     194                 :  * failure (FALSE) of the transformation are placed.
     195                 :  *
     196                 :  * @return TRUE.
     197                 :  */
     198                 : 
     199             916 : int GDALTPSTransform( void *pTransformArg, int bDstToSrc, 
     200                 :                       int nPointCount, 
     201                 :                       double *x, double *y, double *z, 
     202                 :                       int *panSuccess )
     203                 : 
     204                 : {
     205             916 :     VALIDATE_POINTER1( pTransformArg, "GDALTPSTransform", 0 );
     206                 : 
     207                 :     int    i;
     208             916 :     TPSTransformInfo *psInfo = (TPSTransformInfo *) pTransformArg;
     209                 : 
     210            2641 :     for( i = 0; i < nPointCount; i++ )
     211                 :     {
     212                 :         double xy_out[2];
     213                 : 
     214            1725 :         if( bDstToSrc )
     215                 :         {
     216             712 :             psInfo->poReverse->get_point( x[i], y[i], xy_out );
     217             712 :             x[i] = xy_out[0];
     218             712 :             y[i] = xy_out[1];
     219                 :         }
     220                 :         else
     221                 :         {
     222            1013 :             psInfo->poForward->get_point( x[i], y[i], xy_out );
     223            1013 :             x[i] = xy_out[0];
     224            1013 :             y[i] = xy_out[1];
     225                 :         }
     226            1725 :         panSuccess[i] = TRUE;
     227                 :     }
     228                 : 
     229             916 :     return TRUE;
     230                 : }
     231                 : 
     232                 : /************************************************************************/
     233                 : /*                    GDALSerializeTPSTransformer()                     */
     234                 : /************************************************************************/
     235                 : 
     236               0 : CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg )
     237                 : 
     238                 : {
     239               0 :     VALIDATE_POINTER1( pTransformArg, "GDALSerializeTPSTransformer", NULL );
     240                 : 
     241                 :     CPLXMLNode *psTree;
     242               0 :     TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(pTransformArg);
     243                 : 
     244               0 :     psTree = CPLCreateXMLNode( NULL, CXT_Element, "TPSTransformer" );
     245                 : 
     246                 : /* -------------------------------------------------------------------- */
     247                 : /*      Serialize bReversed.                                            */
     248                 : /* -------------------------------------------------------------------- */
     249                 :     CPLCreateXMLElementAndValue( 
     250                 :         psTree, "Reversed", 
     251               0 :         CPLString().Printf( "%d", psInfo->bReversed ) );
     252                 :                                  
     253                 : /* -------------------------------------------------------------------- */
     254                 : /*  Attach GCP List.            */
     255                 : /* -------------------------------------------------------------------- */
     256               0 :     if( psInfo->nGCPCount > 0 )
     257                 :     {
     258                 :         int iGCP;
     259                 :         CPLXMLNode *psGCPList = CPLCreateXMLNode( psTree, CXT_Element, 
     260               0 :                                                   "GCPList" );
     261                 : 
     262               0 :         for( iGCP = 0; iGCP < psInfo->nGCPCount; iGCP++ )
     263                 :         {
     264                 :             CPLXMLNode *psXMLGCP;
     265               0 :             GDAL_GCP *psGCP = psInfo->pasGCPList + iGCP;
     266                 : 
     267               0 :             psXMLGCP = CPLCreateXMLNode( psGCPList, CXT_Element, "GCP" );
     268                 : 
     269               0 :             CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );
     270                 : 
     271               0 :             if( psGCP->pszInfo != NULL && strlen(psGCP->pszInfo) > 0 )
     272               0 :                 CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );
     273                 : 
     274                 :             CPLSetXMLValue( psXMLGCP, "#Pixel", 
     275               0 :                             CPLString().Printf( "%.4f", psGCP->dfGCPPixel ) );
     276                 : 
     277                 :             CPLSetXMLValue( psXMLGCP, "#Line", 
     278               0 :                             CPLString().Printf( "%.4f", psGCP->dfGCPLine ) );
     279                 : 
     280                 :             CPLSetXMLValue( psXMLGCP, "#X", 
     281               0 :                             CPLString().Printf( "%.12E", psGCP->dfGCPX ) );
     282                 : 
     283                 :             CPLSetXMLValue( psXMLGCP, "#Y", 
     284               0 :                             CPLString().Printf( "%.12E", psGCP->dfGCPY ) );
     285                 : 
     286               0 :             if( psGCP->dfGCPZ != 0.0 )
     287                 :                 CPLSetXMLValue( psXMLGCP, "#GCPZ", 
     288               0 :                                 CPLString().Printf( "%.12E", psGCP->dfGCPZ ) );
     289                 :         }
     290                 :     }
     291                 : 
     292               0 :     return psTree;
     293                 : }
     294                 : 
     295                 : /************************************************************************/
     296                 : /*                   GDALDeserializeTPSTransformer()                    */
     297                 : /************************************************************************/
     298                 : 
     299               0 : void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree )
     300                 : 
     301                 : {
     302               0 :     GDAL_GCP *pasGCPList = 0;
     303               0 :     int nGCPCount = 0;
     304                 :     void *pResult;
     305                 :     int bReversed;
     306                 : 
     307                 :     /* -------------------------------------------------------------------- */
     308                 :     /*      Check for GCPs.                                                 */
     309                 :     /* -------------------------------------------------------------------- */
     310               0 :     CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
     311                 : 
     312               0 :     if( psGCPList != NULL )
     313                 :     {
     314               0 :         int  nGCPMax = 0;
     315                 :         CPLXMLNode *psXMLGCP;
     316                 :          
     317                 :         // Count GCPs.
     318               0 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     319                 :              psXMLGCP = psXMLGCP->psNext )
     320               0 :             nGCPMax++;
     321                 :          
     322               0 :         pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPMax);
     323                 : 
     324               0 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     325                 :              psXMLGCP = psXMLGCP->psNext )
     326                 :         {
     327               0 :             GDAL_GCP *psGCP = pasGCPList + nGCPCount;
     328                 : 
     329               0 :             if( !EQUAL(psXMLGCP->pszValue,"GCP") || 
     330                 :                 psXMLGCP->eType != CXT_Element )
     331               0 :                 continue;
     332                 :              
     333               0 :             GDALInitGCPs( 1, psGCP );
     334                 :              
     335               0 :             CPLFree( psGCP->pszId );
     336               0 :             psGCP->pszId = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Id",""));
     337                 :              
     338               0 :             CPLFree( psGCP->pszInfo );
     339               0 :             psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
     340                 :              
     341               0 :             psGCP->dfGCPPixel = atof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
     342               0 :             psGCP->dfGCPLine = atof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
     343                 :              
     344               0 :             psGCP->dfGCPX = atof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
     345               0 :             psGCP->dfGCPY = atof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
     346               0 :             psGCP->dfGCPZ = atof(CPLGetXMLValue(psXMLGCP,"Z","0.0"));
     347               0 :             nGCPCount++;
     348                 :         }
     349                 :     }
     350                 : 
     351                 : /* -------------------------------------------------------------------- */
     352                 : /*      Get other flags.                                                */
     353                 : /* -------------------------------------------------------------------- */
     354               0 :     bReversed = atoi(CPLGetXMLValue(psTree,"Reversed","0"));
     355                 : 
     356                 : /* -------------------------------------------------------------------- */
     357                 : /*      Generate transformation.                                        */
     358                 : /* -------------------------------------------------------------------- */
     359               0 :     pResult = GDALCreateTPSTransformer( nGCPCount, pasGCPList, bReversed );
     360                 :     
     361                 : /* -------------------------------------------------------------------- */
     362                 : /*      Cleanup GCP copy.                                               */
     363                 : /* -------------------------------------------------------------------- */
     364               0 :     GDALDeinitGCPs( nGCPCount, pasGCPList );
     365               0 :     CPLFree( pasGCPList );
     366                 : 
     367               0 :     return pResult;
     368                 : }

Generated by: LCOV version 1.7