Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

Im working a project using the gdal C api(in a block of objective-c) to slice TMS style png tiles. The code currently works, but I'm running into some trouble optimizing to run fast enough for use on mobile devices.

The target resolution for the tiles ranges from near the same res as the source images, to 1/5th the res of the source images.

My current strategy:

Open the source data(currently testing with BSB):

  • Get the transform, using GDALGetGeoTransform, and get the inverse transform
  • get coordinate transformers from dataset coordinates to lat/lon
  • store all that for when tiles are needed

When a tile is needed:

  • Determine the pixel coordinates of the source data that is needed, taking into account a clip line for the data that is not at the edge of the source image.
  • Create a new VRT

    VRTDatasetH vrtDS = VRTCreate(tileSize, tileSize);
    int nBands = GDALGetRasterCount(dataset);
    for(int j=0; j < nBands; j++) {
      GDALRasterBandH sourceBand = GDALGetRasterBand(dataset, j+1);
      GDALAddBand(vrtDS, GDALGetRasterDataType(sourceBand), NULL);
      GDALRasterBandH newBand = GDALGetRasterBand(vrtDS, j+1);
      GDALSetRasterColorInterpretation(newBand, GDALGetRasterColorInterpretation(sourceBand));
      if(GDALGetRasterColorInterpretation(sourceBand) == GCI_PaletteIndex) {
        GDALSetRasterColorTable(newBand, GDALGetRasterColorTable(sourceBand));
      }
    }
    
  • Copy data to the VRT:

    for(int j=0; j < nBands; j++) {
        GDALRasterBandH sourceBand = GDALGetRasterBand(dataset, j+1);
        VRTSourcedRasterBandH destBand = (VRTSourcedRasterBandH)GDALGetRasterBand(vrtDS, j+1);
        VRTAddSimpleSource(destBand,
                   sourceBand,
                   sourceDataRegion.origin.x,
                   sourceDataRegion.origin.y,
                   sourceDataRegion.size.width,
                   sourceDataRegion.size.height,
                   destDataRegion.origin.x,
                   destDataRegion.origin.y,
                   destDataRegion.size.width,
                   destDataRegion.size.height,
                   "NEAREST",
                   VRT_NODATA_UNSET
                   );
      }
    
  • Create a copy the VRT slice as PNG

    GDALDriverH pngDriver = GDALGetDriverByName("PNG");
    GDALDatasetH pngCopy = GDALCreateCopy(pngDriver, destinationPath, datasetToWrite, false, NULL, NULL, NULL);
    GDALClose(pngCopy);
    

Currently GDALCreateCopy is using 70% of the total CPU time

I've tried reusing the same VRT, but did not see a significant speed increase from that. That is also not an ideal solution because some of the tiles do not have source data to cover the complete tile.

Is there a more CPU efficient way to do this?

Techniques i've thought about but have not yet implemented:

  • Creating a VRT of the whole dataset warped to the target CRS using GDALAutoCreateWarpedVRT then slicing tiles from that. This could be faster, but from my experience with gdal so far, my guess is that this would be approximately the same speed.
  • Write the image out to a GeoTiff in the target CRS, then slice the GeoTiff.
  • Dumping the whole image to PNG, then doing the slicing with core-graphics. My guess is that this would use a lot more memory, because some of the my source images are 15000px*15000px

Any suggestions for optimizing this would be greatly appreciated.

Current cpu use

share|improve this question
    
don't cross post: stackoverflow.com/questions/15940957/… –  Mike T Apr 11 '13 at 8:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.