Skip to content
Permalink
Browse files

Add resume option to gdal_retile.py (#1703)

  • Loading branch information...
gramnation authored and rouault committed Jul 11, 2019
1 parent 076e21b commit 5e7f3d5026a35017fc5d1f31438e28cbecdca53a
Showing with 66 additions and 26 deletions.
  1. +5 −1 gdal/doc/source/programs/gdal_retile.rst
  2. +61 −25 gdal/swig/python/scripts/gdal_retile.py
@@ -24,7 +24,7 @@ Synopsis
[-s_srs srs_def] [-pyramidOnly]
[-r {near/bilinear/cubic/cubicspline/lanczos}]
-levels numberoflevels
[-useDirForEachRow]
[-useDirForEachRow] [-resume]
-targetDir TileDirectory input_files

Description
@@ -117,6 +117,10 @@ If your number of input tiles exhausts the command line buffer, use the general
only the tiles for one row for a specific level. For large images a performance improvement
of a factor N could be achieved.

.. option:: -resume

Resume mode. Generate only missing files.

.. note::

gdal_retile.py is a Python script, and will only work if GDAL was built
@@ -31,6 +31,7 @@

import os
import sys
import shutil

from osgeo import gdal
from osgeo import ogr
@@ -355,7 +356,8 @@ def tileImage(minfo, ti):
if offsetY + height > ti.height:
height = ti.height - offsetY

createTile(minfo, offsetX, offsetY, width, height, tilename, OGRDS)
feature_only = Resume and os.path.exists(tilename)
createTile(minfo, offsetX, offsetY, width, height, tilename, OGRDS, feature_only)

if not Quiet and not Verbose:
processed += 1
@@ -418,23 +420,28 @@ def copyTileIndexToCSV(OGRDS, fileName):
csvfile.close()


def createPyramidTile(levelMosaicInfo, offsetX, offsetY, width, height, tileName, OGRDS):
def createPyramidTile(levelMosaicInfo, offsetX, offsetY, width, height, tileName, OGRDS, feature_only):

temp_tilename = tileName + '.tmp'

sx = levelMosaicInfo.scaleX * 2
sy = levelMosaicInfo.scaleY * 2

dec = AffineTransformDecorator([levelMosaicInfo.ulx + offsetX * sx, sx, 0,
levelMosaicInfo.uly + offsetY * sy, 0, sy])

if OGRDS is not None:
points = dec.pointsFor(width, height)
addFeature(OGRDS, tileName, points[0], points[1])

if feature_only:
return

s_fh = levelMosaicInfo.getDataSet(dec.ulx, dec.uly + height * dec.scaleY,
dec.ulx + width * dec.scaleX, dec.uly)
if s_fh is None:
return

if OGRDS is not None:
points = dec.pointsFor(width, height)
addFeature(OGRDS, tileName, points[0], points[1])

if BandType is None:
bt = levelMosaicInfo.band_type
else:
@@ -445,9 +452,9 @@ def createPyramidTile(levelMosaicInfo, offsetX, offsetY, width, height, tileName
bands = levelMosaicInfo.bands

if MemDriver is None:
t_fh = Driver.Create(tileName, width, height, bands, bt, CreateOptions)
t_fh = Driver.Create(temp_tilename, width, height, bands, bt, CreateOptions)
else:
t_fh = MemDriver.Create(tileName, width, height, bands, bt)
t_fh = MemDriver.Create('', width, height, bands, bt)

if t_fh is None:
print('Creation failed, terminating gdal_tile.')
@@ -469,26 +476,35 @@ def createPyramidTile(levelMosaicInfo, offsetX, offsetY, width, height, tileName

res = gdal.ReprojectImage(s_fh, t_fh, None, None, ResamplingMethod)
if res != 0:
print("Reprojection failed for %s, error %d" % (tileName, res))
print("Reprojection failed for %s, error %d" % (temp_tilename, res))
sys.exit(1)

levelMosaicInfo.closeDataSet(s_fh)

if MemDriver is not None:
tt_fh = Driver.CreateCopy(tileName, t_fh, 0, CreateOptions)
if MemDriver is None:
t_fh.FlushCache()
else:
tt_fh = Driver.CreateCopy(temp_tilename, t_fh, 0, CreateOptions)
tt_fh.FlushCache()
tt_fh = None

t_fh = None

if os.path.exists(tileName):
os.remove(tileName)
shutil.move(temp_tilename, tileName)

if Verbose:
print(tileName + " : " + str(offsetX) + "|" + str(offsetY) + "-->" + str(width) + "-" + str(height))


def createTile(minfo, offsetX, offsetY, width, height, tilename, OGRDS):
def createTile(minfo, offsetX, offsetY, width, height, tilename, OGRDS, feature_only):
"""
Create tile
return name of created tile
"""
temp_tilename = tilename + '.tmp'

if BandType is None:
bt = minfo.band_type
@@ -497,12 +513,6 @@ def createTile(minfo, offsetX, offsetY, width, height, tilename, OGRDS):

dec = AffineTransformDecorator([minfo.ulx, minfo.scaleX, 0, minfo.uly, 0, minfo.scaleY])

s_fh = minfo.getDataSet(dec.ulx + offsetX * dec.scaleX, dec.uly + offsetY * dec.scaleY + height * dec.scaleY,
dec.ulx + offsetX * dec.scaleX + width * dec.scaleX,
dec.uly + offsetY * dec.scaleY)
if s_fh is None:
return

geotransform = [dec.ulx + offsetX * dec.scaleX, dec.scaleX, 0,
dec.uly + offsetY * dec.scaleY, 0, dec.scaleY]

@@ -511,12 +521,21 @@ def createTile(minfo, offsetX, offsetY, width, height, tilename, OGRDS):
points = dec2.pointsFor(width, height)
addFeature(OGRDS, tilename, points[0], points[1])

if feature_only:
return

s_fh = minfo.getDataSet(dec.ulx + offsetX * dec.scaleX, dec.uly + offsetY * dec.scaleY + height * dec.scaleY,
dec.ulx + offsetX * dec.scaleX + width * dec.scaleX,
dec.uly + offsetY * dec.scaleY)
if s_fh is None:
return

bands = minfo.bands

if MemDriver is None:
t_fh = Driver.Create(tilename, width, height, bands, bt, CreateOptions)
t_fh = Driver.Create(temp_tilename, width, height, bands, bt, CreateOptions)
else:
t_fh = MemDriver.Create(tilename, width, height, bands, bt)
t_fh = MemDriver.Create('', width, height, bands, bt)

if t_fh is None:
print('Creation failed, terminating gdal_tile.')
@@ -542,9 +561,18 @@ def createTile(minfo, offsetX, offsetY, width, height, tilename, OGRDS):

minfo.closeDataSet(s_fh)

if MemDriver is not None:
tt_fh = Driver.CreateCopy(tilename, t_fh, 0, CreateOptions)
if MemDriver is None:
t_fh.FlushCache()
else:
tt_fh = Driver.CreateCopy(temp_tilename, t_fh, 0, CreateOptions)
tt_fh.FlushCache()
tt_fh = None

t_fh = None

if os.path.exists(tilename):
os.remove(tilename)
shutil.move(temp_tilename, tilename)

if Verbose:
print(tilename + " : " + str(offsetX) + "|" + str(offsetY) + "-->" + str(width) + "-" + str(height))
@@ -643,8 +671,10 @@ def buildPyramidLevel(levelMosaicInfo, levelOutputTileInfo, level):
height = levelOutputTileInfo.height - offsetY

tilename = getTileName(levelMosaicInfo, levelOutputTileInfo, xIndex, yIndex, level)
createPyramidTile(levelMosaicInfo, offsetX, offsetY, width, height, tilename, OGRDS)

feature_only = Resume and os.path.exists(tilename)
createPyramidTile(levelMosaicInfo, offsetX, offsetY, width, height, tilename, OGRDS, feature_only)

if TileIndexName is not None:
shapeName = getTargetDir(level) + TileIndexName
copyTileIndexToDisk(OGRDS, shapeName)
@@ -711,7 +741,7 @@ def Usage():
print(' [ -csv fileName [-csvDelim delimiter]]')
print(' [-s_srs srs_def] [-pyramidOnly] -levels numberoflevels')
print(' [-r {near/bilinear/cubic/cubicspline/lanczos}]')
print(' [-useDirForEachRow]')
print(' [-useDirForEachRow] [-resume]')
print(' -targetDir TileDirectory input_files')

# =============================================================================
@@ -748,6 +778,7 @@ def main(args=None):
global Levels
global PyramidOnly
global UseDirForEachRow
global Resume

gdal.AllRegister()

@@ -852,6 +883,8 @@ def main(args=None):
CsvDelimiter = argv[i]
elif arg == '-useDirForEachRow':
UseDirForEachRow = True
elif arg == "-resume":
Resume = True
elif arg[:1] == '-':
print('Unrecognized command option: %s' % arg)
Usage()
@@ -964,6 +997,7 @@ def initGlobals():
global PyramidOnly
global LastRowIndx
global UseDirForEachRow
global Resume

Verbose = False
CreateOptions = []
@@ -989,6 +1023,7 @@ def initGlobals():
PyramidOnly = False
LastRowIndx = -1
UseDirForEachRow = False
Resume = False


# global vars
@@ -1016,6 +1051,7 @@ def initGlobals():
PyramidOnly = False
LastRowIndx = -1
UseDirForEachRow = False
Resume = False


if __name__ == '__main__':

0 comments on commit 5e7f3d5

Please sign in to comment.
You can’t perform that action at this time.