gdalwarp.py 14 KB

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