LCOV - code coverage report
Current view: directory - alg - gdalmatching.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 82 0 0.0 %
Date: 2012-12-26 Functions: 2 0 0.0 %

       1                 : /******************************************************************************
       2                 :  * $Id$
       3                 :  *
       4                 :  * Project:  GDAL
       5                 :  * Purpose:  GDAL Wrapper for image matching via corellation algorithm.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  * Author:   Andrew Migal, migal.drew@gmail.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2012, Frank Warmerdam
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "gdal_alg.h"
      32                 : #include "gdal_simplesurf.h"
      33                 : 
      34                 : CPL_CVSID("$Id");
      35                 : 
      36                 : /**
      37                 :  * @file
      38                 :  * @author Andrew Migal migal.drew@gmail.com
      39                 :  * @brief Algorithms for searching corresponding points on images.
      40                 :  * @details This implementation is  based on an simplified version
      41                 :  * of SURF algorithm (Speeded Up Robust Features).
      42                 :  * Provides capability for detection feature points
      43                 :  * and finding equal points on different images.
      44                 :  * As original, this realization is scale invariant, but sensitive to rotation.
      45                 :  * Images should have similar rotation angles (maximum difference is up to 10-15 degrees),
      46                 :  * otherwise algorithm produces incorrect and very unstable results.
      47                 :  */
      48                 : 
      49                 : /**
      50                 :  * Detect feature points on provided image. Please carefully read documentation below.
      51                 :  *
      52                 :  * @param poDataset Image on which feature points will be detected
      53                 :  * @param panBands Array of 3 raster bands numbers, for Red, Green, Blue bands (in that order)
      54                 :  * @param nOctaveStart Number of bottom octave. Octave numbers starts from one.
      55                 :  * This value directly and strongly affects to amount of recognized points
      56                 :  * @param nOctaveEnd Number of top octave. Should be equal or greater than octaveStart
      57                 :  * @param dfThreshold Value from 0 to 1. Threshold for feature point recognition.
      58                 :  * Number of detected points is larger if threshold is lower
      59                 :  *
      60                 :  * @see GDALFeaturePoint, GDALSimpleSURF class for detailes.
      61                 :  *
      62                 :  * @note Every octave finds points in specific size. For small images
      63                 :  * use small octave numbers, for high resolution - large.
      64                 :  * For 1024x1024 images it's normal to use any octave numbers from range 1-6.
      65                 :  * (for example, octave start - 1, octave end - 3, or octave start - 2, octave end - 2.)
      66                 :  * For larger images, try 1-10 range or even higher.
      67                 :  * Pay attention that number of detected point decreases quickly per octave
      68                 :  * for particular image. Algorithm finds more points in case of small octave number.
      69                 :  * If method detects nothing, reduce octave start value.
      70                 :  * In addition, if many feature points are required (the largest possible amount),
      71                 :  * use the lowest octave start value (1) and wide octave range.
      72                 :  *
      73                 :  * @note Typical threshold's value is 0,001. It's pretty good for all images.
      74                 :  * But this value depends on image's nature and may be various in each particular case.
      75                 :  * For example, value can be 0,002 or 0,005.
      76                 :  * Notice that number of detected points is larger if threshold is lower.
      77                 :  * But with high threshold feature points will be better - "stronger", more "unique" and distinctive.
      78                 :  *
      79                 :  * Feel free to experiment with parameters, because character, robustness and number of points
      80                 :  * entirely depend on provided range of octaves and threshold.
      81                 :  *
      82                 :  * NOTICE that every octave requires time to compute. Use a little range
      83                 :  * or only one octave, if execution time is significant.
      84                 :  *
      85                 :  * @return CE_None or CE_Failure if error occurs.
      86                 :  */
      87                 : 
      88                 : static std::vector<GDALFeaturePoint> *
      89               0 : GatherFeaturePoints(GDALDataset* poDataset, int* panBands,
      90                 :                     int nOctaveStart, int nOctaveEnd, double dfThreshold)
      91                 : {
      92               0 :     if (poDataset == NULL)
      93                 :     {
      94               0 :         CPLError(CE_Failure, CPLE_AppDefined, "GDALDataset isn't specified");
      95               0 :         return NULL;
      96                 :     }
      97                 : 
      98               0 :     if (panBands == NULL)
      99                 :     {
     100                 :         CPLError(CE_Failure, CPLE_AppDefined,
     101               0 :                  "Raster bands are not specified");
     102               0 :         return NULL;
     103                 :     }
     104                 : 
     105               0 :     if (nOctaveStart <= 0 || nOctaveEnd < 0 ||
     106                 :         nOctaveStart > nOctaveEnd)
     107                 :     {
     108                 :         CPLError(CE_Failure, CPLE_AppDefined,
     109               0 :                  "Octave numbers are invalid");
     110               0 :         return NULL;
     111                 :     }
     112                 : 
     113               0 :     if (dfThreshold < 0)
     114                 :     {
     115                 :         CPLError(CE_Failure, CPLE_AppDefined,
     116               0 :                  "Threshold have to be greater than zero");
     117               0 :         return NULL;
     118                 :     }
     119                 : 
     120               0 :     GDALRasterBand *poRstRedBand = poDataset->GetRasterBand(panBands[0]);
     121               0 :     GDALRasterBand *poRstGreenBand = poDataset->GetRasterBand(panBands[1]);
     122               0 :     GDALRasterBand *poRstBlueBand = poDataset->GetRasterBand(panBands[2]);
     123                 : 
     124               0 :     int nWidth = poRstRedBand->GetXSize();
     125               0 :     int nHeight = poRstRedBand->GetYSize();
     126                 : 
     127                 :     // Allocate memory for grayscale image
     128               0 :     double **padfImg = NULL;
     129               0 :     padfImg = new double*[nHeight];
     130               0 :     for (int i = 0; i < nHeight; i++)
     131               0 :         padfImg[i] = new double[nWidth];
     132                 : 
     133                 :     // Create grayscale image
     134                 :     GDALSimpleSURF::ConvertRGBToLuminosity(
     135                 :         poRstRedBand, poRstGreenBand, poRstBlueBand, nWidth, nHeight,
     136               0 :         padfImg, nHeight, nWidth);
     137                 : 
     138                 :     // Prepare integral image
     139               0 :     GDALIntegralImage *poImg = new GDALIntegralImage();
     140               0 :     poImg->Initialize((const double**)padfImg, nHeight, nWidth);
     141                 : 
     142                 :     // Get feature points
     143               0 :     GDALSimpleSURF *poSurf = new GDALSimpleSURF(nOctaveStart, nOctaveEnd);
     144                 :     
     145                 :     std::vector<GDALFeaturePoint> *poCollection = 
     146               0 :         poSurf->ExtractFeaturePoints(poImg, dfThreshold);
     147                 : 
     148                 :     // Clean up
     149               0 :     delete poImg;
     150               0 :     delete poSurf;
     151                 : 
     152               0 :     for (int i = 0; i < nHeight; i++)
     153               0 :         delete[] padfImg[i];
     154                 : 
     155               0 :     delete[] padfImg;
     156                 : 
     157               0 :     return poCollection;
     158                 : }
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                     GDALComputeMatchingPoints()                      */
     162                 : /************************************************************************/
     163                 : 
     164                 : GDAL_GCP CPL_DLL *
     165               0 : GDALComputeMatchingPoints( GDALDatasetH hFirstImage,
     166                 :                            GDALDatasetH hSecondImage,
     167                 :                            char **papszOptions,
     168                 :                            int *pnGCPCount )
     169                 : {
     170               0 :     *pnGCPCount = 0;
     171                 : 
     172                 : /* -------------------------------------------------------------------- */
     173                 : /*      Override default algorithm parameters.                          */
     174                 : /* -------------------------------------------------------------------- */
     175                 :     int nOctaveStart, nOctaveEnd;
     176                 :     double dfSURFThreshold;
     177               0 :     double dfMatchingThreshold = 0.015;
     178                 : 
     179               0 :     nOctaveStart =atoi(CSLFetchNameValueDef(papszOptions, "OCTAVE_START", "2"));
     180               0 :     nOctaveEnd = atoi(CSLFetchNameValueDef(papszOptions, "OCTAVE_END", "2"));
     181                 : 
     182                 :     dfSURFThreshold = CPLAtof(
     183               0 :         CSLFetchNameValueDef(papszOptions, "SURF_THRESHOLD", "0.001"));
     184                 :     dfMatchingThreshold = CPLAtof(
     185               0 :         CSLFetchNameValueDef(papszOptions, "MATCHING_THRESHOLD", "0.015"));
     186                 : 
     187                 : /* -------------------------------------------------------------------- */
     188                 : /*      Identify the bands to use.  For now we are effectively          */
     189                 : /*      limited to using RGB input so if we have one band only treat    */
     190                 : /*      it as red=green=blue=band 1.  Disallow non eightbit imagery.    */
     191                 : /* -------------------------------------------------------------------- */
     192                 :     int anBandMap1[3], anBandMap2[3];
     193                 : 
     194               0 :     if( GDALGetRasterCount(hFirstImage) >= 3 )
     195                 :     {
     196               0 :         anBandMap1[0] = 1;
     197               0 :         anBandMap1[1] = 2;
     198               0 :         anBandMap1[2] = 3;
     199                 :     }
     200                 :     else
     201                 :     { 
     202               0 :         anBandMap1[0] = anBandMap1[1] = anBandMap1[2] = 1;
     203                 :     }
     204                 : 
     205               0 :     if( GDALGetRasterCount(hSecondImage) >= 3 )
     206                 :     {
     207               0 :         anBandMap2[0] = 1;
     208               0 :         anBandMap2[1] = 2;
     209               0 :         anBandMap2[2] = 3;
     210                 :     }
     211                 :     else
     212                 :     { 
     213               0 :         anBandMap2[0] = anBandMap2[1] = anBandMap2[2] = 1;
     214                 :     }
     215                 : 
     216                 : /* -------------------------------------------------------------------- */
     217                 : /*      Collect reference points on each image.                         */
     218                 : /* -------------------------------------------------------------------- */
     219                 :     std::vector<GDALFeaturePoint> *poFPCollection1 =
     220                 :         GatherFeaturePoints((GDALDataset *) hFirstImage, anBandMap1, 
     221               0 :                             nOctaveStart, nOctaveEnd, dfSURFThreshold);
     222               0 :     if( poFPCollection1 == NULL )
     223               0 :         return NULL;
     224                 : 
     225                 :     std::vector<GDALFeaturePoint> *poFPCollection2 = 
     226                 :         GatherFeaturePoints((GDALDataset *) hSecondImage, anBandMap2, 
     227                 :                             nOctaveStart, nOctaveEnd, 
     228               0 :                             dfSURFThreshold);
     229                 :     
     230               0 :     if( poFPCollection2 == NULL )
     231               0 :         return NULL;
     232                 : 
     233                 :     
     234                 : /* -------------------------------------------------------------------- */
     235                 : /*      Try to find corresponding locations.                            */
     236                 : /* -------------------------------------------------------------------- */
     237                 :     CPLErr eErr;
     238               0 :     std::vector<GDALFeaturePoint *> oMatchPairs;
     239                 : 
     240                 :     eErr = GDALSimpleSURF::MatchFeaturePoints(
     241                 :         &oMatchPairs, poFPCollection1, poFPCollection2,
     242               0 :         dfMatchingThreshold );
     243                 : 
     244               0 :     if( eErr != CE_None )
     245               0 :         return NULL;
     246                 : 
     247                 :     
     248               0 :     *pnGCPCount = oMatchPairs.size() / 2;
     249                 : 
     250                 : /* -------------------------------------------------------------------- */
     251                 : /*      Translate these into GCPs - but with the output coordinate      */
     252                 : /*      system being pixel/line on the second image.                    */
     253                 : /* -------------------------------------------------------------------- */
     254               0 :     GDAL_GCP *pasGCPList = (GDAL_GCP*) CPLCalloc(*pnGCPCount, sizeof(GDAL_GCP));
     255                 : 
     256               0 :     GDALInitGCPs(*pnGCPCount, pasGCPList);
     257                 : 
     258               0 :     for (int i=0; i < *pnGCPCount; i++) 
     259                 :     {
     260               0 :         GDALFeaturePoint *poPoint1 = oMatchPairs[i*2  ];
     261               0 :         GDALFeaturePoint *poPoint2 = oMatchPairs[i*2+1];
     262                 : 
     263               0 :         pasGCPList[i].dfGCPPixel = poPoint1->GetX() + 0.5;
     264               0 :         pasGCPList[i].dfGCPLine = poPoint1->GetY() + 0.5;
     265                 :         
     266               0 :         pasGCPList[i].dfGCPX = poPoint2->GetX() + 0.5;
     267               0 :         pasGCPList[i].dfGCPY = poPoint2->GetY() + 0.5;
     268               0 :         pasGCPList[i].dfGCPZ = 0.0;
     269                 :     }
     270                 : 
     271                 :     // Cleanup the feature point lists.
     272               0 :     delete poFPCollection1;
     273               0 :     delete poFPCollection2;
     274                 :     
     275                 : /* -------------------------------------------------------------------- */
     276                 : /*      Optionally transform into the georef coordinates of the         */
     277                 : /*      output image.                                                   */
     278                 : /* -------------------------------------------------------------------- */
     279                 :     int bGeorefOutput = 
     280               0 :         CSLTestBoolean(CSLFetchNameValueDef(papszOptions,"OUTPUT_GEOREF","NO"));
     281                 : 
     282               0 :     if( bGeorefOutput )
     283                 :     {
     284                 :         double adfGeoTransform[6];
     285                 : 
     286               0 :         GDALGetGeoTransform( hSecondImage, adfGeoTransform );
     287                 : 
     288               0 :         for (int i=0; i < *pnGCPCount; i++) 
     289                 :         {
     290                 :             GDALApplyGeoTransform(adfGeoTransform, 
     291               0 :                                   pasGCPList[i].dfGCPX,
     292               0 :                                   pasGCPList[i].dfGCPY,
     293               0 :                                   &(pasGCPList[i].dfGCPX),
     294               0 :                                   &(pasGCPList[i].dfGCPY));
     295                 :         }
     296                 :     }
     297                 : 
     298               0 :     return pasGCPList;
     299                 : }

Generated by: LCOV version 1.7