gdalwarp.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. ############################################################################
  2. #
  3. # MODULE: r.in.wms / wms_gdalwarp.py
  4. #
  5. # AUTHOR(S): Cedric Shock, 2006
  6. # Update for GRASS 7 by Martin Landa <landa.martin gmail.com>, 2009
  7. #
  8. # PURPOSE: To import data from web mapping servers
  9. # (based on Bash script by Cedric Shock)
  10. #
  11. # COPYRIGHT: (C) 2009 Martin Landa, and GRASS development team
  12. #
  13. # This program is free software under the GNU General
  14. # Public License (>=v2). Read the file COPYING that
  15. # comes with GRASS for details.
  16. #
  17. #############################################################################
  18. import os
  19. import subprocess
  20. import grass
  21. class GDALWarp():
  22. def __init__(self, flags, options):
  23. self.flags = flags
  24. self.options = options
  25. self.tmp = grass.tempfile()
  26. self.suffixes = []
  27. self.patches = []
  28. self.maplist = []
  29. self.tiler = 0
  30. if not flags['p']:
  31. # todo: check if gdalwarp is available
  32. pass
  33. # flags for r.in.gdal
  34. self.gdal_flags = ''
  35. if flags['e']:
  36. self.gdal_flags += 'e'
  37. if flags['k']:
  38. self.gdal_flags += 'k'
  39. # options for gdalwarp
  40. method_opt = options['method']
  41. if method_opt == 'nearest':
  42. self.gdal_method = '-rn'
  43. elif method_opt == 'bilinear':
  44. self.gdal_method = '-rb'
  45. elif method_opt == 'cubic':
  46. self.gdal_method = '-rc'
  47. elif method_opt == 'cubicspline':
  48. self.gdal_method = '-rcs'
  49. def run(self):
  50. # import tiles
  51. tiler = 0
  52. for input in self.options['input'].split(','):
  53. tmptilename = self.options['output'] + '_tile_' + str(tiler)
  54. if not os.path.exists(input):
  55. grass.warning("Missing input '%s'" % input)
  56. continue
  57. grass.info('Importing tile <%s>...' % os.path.basename(input))
  58. if self.flags['p']:
  59. self.nowarp_import(input, tmptilename, self.gdal_flags)
  60. else:
  61. self.warp_import(input, tmptilename, self.gdal_method)
  62. maplist.append(tmptilename)
  63. tiler += 1
  64. if tiler < 1:
  65. grass.message("Nothing imported")
  66. return 0
  67. # if there's more than one tile patch them together, otherwise
  68. # just rename that tile.
  69. if tiler == 1:
  70. if len(channel_suffixes) > 0:
  71. # multi-band
  72. for suffix in channel_suffixes:
  73. # rename tile 0 to be the output
  74. ffile = self.options['output'] + '_tile_0' + suffix
  75. tfile = self.options['output'] + suffix
  76. if grass.run_command('g.rename',
  77. quiet = True,
  78. rast = ffile + ',' + tfile) != 0:
  79. grass.fatal('g.rename failed')
  80. else: # single-band, single-tile
  81. ffile = self.options['output'] + '_tile_0' # + sfx ?
  82. tfile = self.options['output'] # + sfx ?
  83. if grass.run_command('g.rename',
  84. quiet = True,
  85. rast = ffile + ',' + tfile) != 0:
  86. grass.fatal('g.rename failed')
  87. else:
  88. # patch together each channel
  89. grass.debug('suffixes: %s' % ','.join(suffixes))
  90. if len(suffixes) > 0:
  91. # multi-band data
  92. for suffix in suffixes:
  93. suffix = suffix.replace('.', '_')
  94. # patch these together (using nulls only)
  95. grass.message("Patching '%s' channel..." % suffix)
  96. if grass.run_command('r.patch',
  97. quiet = True,
  98. input = patches, # ???
  99. output = self.options['output'] + suffix) != 0:
  100. grass.fatal('r.patch failed')
  101. # remove the temporary patches we made
  102. if grass.run_command('g.remove',
  103. quiet = True,
  104. rast = patches) != 0:
  105. grass.fatal('g.remove failed')
  106. else:
  107. # single-band data
  108. grass.info("Patching tiles (this may take some time)...")
  109. grass.debug("patch list = %s" % ','.join(maplist))
  110. # HACK: for 8bit PNG, GIF all the different tiles can have
  111. # different color tables so patches output end up all freaky.
  112. # r.mapcalc r#,g#,b# manual patching + r.composite?
  113. # or d.out.file + r.in.png + r.region?
  114. # *** there is a GDAL utility to do this: gdal_merge.py
  115. # http://www.gdal.org/gdal_merge.html
  116. for color in ('r', 'g', 'b'):
  117. maplist_color = []
  118. for map in maplist:
  119. outmap = map + '_' + color
  120. maplist_color.append(outmap)
  121. if grass.run_command('r.mapcalc',
  122. quiet = True,
  123. expression = '%s = %s#%s' % (outmap, color, map)) != 0:
  124. grass.fatal('r.mapcalc failed')
  125. if grass.run_command('r.colors',
  126. quiet = True,
  127. map = outmap,
  128. color = 'grey255') != 0:
  129. grass.fatal('r.colors failed')
  130. if grass.run_command('r.null',
  131. quiet = True,
  132. map = outmap,
  133. setnull = 255) != 0:
  134. grass.fatal('r.null failed')
  135. if grass.run_command('r.patch',
  136. input = ','.join(maplist_color),
  137. output = outmap + '_all') != 0:
  138. grass.fatal('r.patch failed')
  139. if grass.run_command('r.composite',
  140. quiet = True,
  141. red = map + '_r_all',
  142. green = map + '_g_all',
  143. blue = map + '_b_all',
  144. output = self.options['output']) != 0:
  145. grass.fatal('r.composite failed')
  146. if grass.run_command('g.mremove',
  147. quiet = True,
  148. flags = 'f',
  149. rast = map + '*') != 0:
  150. grass.fatal('g.remove failed')
  151. # there's already a no suffix, can't make colors
  152. # can only go up from here ;)
  153. colors = 4 # ???
  154. for suffix in suffixes:
  155. if suffix in ('.red', '.green', '.blue'):
  156. colors += 1
  157. # make a composite image if asked for and colors exist
  158. if colors == 3 or self.flags['c']:
  159. grass.message("Building color image <%s>..." % self.options['output'])
  160. if grass.run_command('r.composite',
  161. quiet = True,
  162. red = self.options['output'] + '.red',
  163. green = self.options['output'] + '.green',
  164. blue = self.options['output'] + '.blue',
  165. output = option['output']) != 0:
  166. grass.fatal('r.composite failed')
  167. return 0
  168. def warp_import(self, file, map, method):
  169. """Wrap raster file using gdalwarp and import wrapped file
  170. into GRASS"""
  171. warpfile = self.tmp + 'warped.geotiff'
  172. tmpmapname = map + '_tmp'
  173. t_srs = grass.read_command('g.proj',
  174. quiet = True,
  175. flags = 'wf')
  176. if not t_srs:
  177. grass.fatal('g.proj failed')
  178. grass.debug('gdalwarp -s_srs "%s" -t_srs "%s" "%s" "%s" %s %s' % \
  179. (self.options['srs'], t_srs, file,
  180. warpfile, self.options['warpoptions'], method))
  181. grass.verbose("Warping input file '%s'..." % file)
  182. ps = subprocess.Popen(['gdalwarp',
  183. '-s_srs', self.options['srs'],
  184. '-t_srs', t_srs,
  185. file, warpfile,
  186. self.options['warpoptions'],
  187. method])
  188. if ps.wait() != 0:
  189. grass.fatal('gdalwarp failed')
  190. # import it into a temporary map
  191. grass.info('Importing temporary raster map...')
  192. if grass.run_command('r.in.gdal',
  193. quiet = True,
  194. flags = gdal_flags,
  195. input = warpfile,
  196. output = tmpmapname) != 0:
  197. grass.fatal('r.in.gdal failed')
  198. os.remove(warpfile)
  199. # get list of channels
  200. pattern = tmpmapfile + '*'
  201. grass.debug('Pattern: %s' % pattern)
  202. mapset = grass.gisenv()['MAPSET']
  203. channel_list = grass.mlist_grouped(type = 'rast', pattern = pattern, mapset = mapset)
  204. grass.debug('Channel list: %s' % ','.join(channel_list))
  205. if len(channel_list) < 2: # test for single band data
  206. channel_suffixes = []
  207. else:
  208. channel_suffixes = channel_list # ???
  209. grass.debug('Channel suffixes: %s', ','.join(channel_suffixes))
  210. # add to the list of all suffixes
  211. self.suffixes = self.suffixes + channel_suffixes
  212. self.suffixes.sort()
  213. # get last suffix
  214. if len(channel_suffixes) > 0:
  215. last_suffix = channel_suffixes[-1]
  216. else:
  217. last_suffix = ''
  218. # find the alpha layer
  219. if self.flags['k']:
  220. alphalayer = tmpmapname + last_suffix
  221. else:
  222. alphalayer = tmpmapname + '.alpha'
  223. # test to see if the alpha map exists
  224. if not grass.find_file(element = 'cell', file = alphalayer)['name']:
  225. alphalayer = ''
  226. # calculate the new maps:
  227. for suffix in channel_suffixes:
  228. grass.debug("alpha=%s MAPsfx=%s% tmpname=%s%s" % \
  229. (alphalayer, map, suffix, tmpmapname, suffix))
  230. if alphalayer:
  231. # Use alpha channel for nulls: problem: I've seen a map
  232. # where alpha was 1-255; 1 being transparent. what to do?
  233. # (Geosci Australia Gold layer, format=tiff)
  234. if grass.run_command('r.mapcalc',
  235. quiet = True,
  236. expression = "%s%s = if(%s, %s%s, null())" % \
  237. (map, sfx, alphalayer, tmpmapname, sfx)) != 0:
  238. grass.fatal('r.mapcalc failed')
  239. else:
  240. if grass.run_command('g.copy',
  241. quiet = True,
  242. rast = "%s%s,%s%s" % \
  243. (tmpmapname, suffix, map, suffix)) != 0:
  244. grass.fatal('g.copy failed')
  245. # copy the color tables
  246. if grass.run_command('r.colors',
  247. quiet = True,
  248. map = map + suffix,
  249. rast = tmpmapname + suffix) != 0:
  250. grass.fatal('g.copy failed')
  251. # make patch lists
  252. suffix = suffix.replace('.', '_')
  253. # this is a hack to make the patch lists empty:
  254. if self.tiler == 0:
  255. self.patches = []
  256. self.patches = self.patches.append(map + suffix)
  257. # if no suffix, processing is simple (e.g. elevation has only 1
  258. # band)
  259. if len(channel_list) < 1:
  260. # run r.mapcalc to crop to region
  261. if grass.run_command('r.mapcalc',
  262. quiet = True,
  263. expression = "%s = %s" % \
  264. (map, tmpmapname)) != 0:
  265. grass.fatal('r.mapcalc failed')
  266. if grass.run_command('r.colors',
  267. quiet = True,
  268. map = map,
  269. rast = tmpmapname) != 0:
  270. grass.fatal('r.colors failed')
  271. # remove the old channels
  272. if grass.run_command('g.remove',
  273. quiet = True,
  274. rast = ','.channel_list) != 0:
  275. grass.fatal('g.remove failed')
  276. def nowarp_import(self, file, map, gdal_flags):
  277. """Import raster file into GRASS"""
  278. if grass.run_command('r.in.gdal',
  279. quiet = True,
  280. flags = 'o' + gdal_flags,
  281. input = file,
  282. output = map) != 0:
  283. grass.fatal('r.in.gdal failed')
  284. # get a list of channels:
  285. pattern = map + '*'
  286. grass.debug("pattern: %s" % ','.join(pattern))
  287. mapset = grass.gisenv()['MAPSET']
  288. channel_list = grass.mlist_grouped(type = 'rast', pattern = pattern, mapset = mapset)
  289. grass.debug("channel list: %s" % ','.join(channel_list))
  290. if len(channel_list) < 2:
  291. # test for single band data
  292. channel_suffixes = []
  293. else:
  294. channel_suffixes = channel_list # ???
  295. # add to the list of all suffixes:
  296. self.suffixes = self.suffixes + channel.suffixes
  297. self.suffixes.sort()
  298. for suffix in channel_suffixes:
  299. # make patch lists
  300. suffix = suffix.replace('.', '_')
  301. # this is a hack to make the patch lists empty
  302. if self.tiler == 0:
  303. self.patches = []
  304. self.patches = self.patches.append(map + suffix)