i.fusion.brovey.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: i.fusion.brovey
  5. # AUTHOR(S): Markus Neteler. <neteler itc it>
  6. # Converted to Python by Glynn Clements
  7. # PURPOSE: Brovey transform to merge
  8. # - LANDSAT-7 MS (2, 4, 5) and pan (high res)
  9. # - SPOT MS and pan (high res)
  10. # - QuickBird MS and pan (high res)
  11. #
  12. # COPYRIGHT: (C) 2002-2008 by the GRASS Development Team
  13. #
  14. # This program is free software under the GNU General Public
  15. # License (>=v2). Read the file COPYING that comes with GRASS
  16. # for details.
  17. #
  18. # REFERENCES:
  19. # (?) Roller, N.E.G. and Cox, S., 1980. Comparison of Landsat MSS
  20. # and merged MSS/RBV data for analysis of natural vegetation.
  21. # Proc. of the 14th International Symposium on Remote Sensing
  22. # of Environment, San Jose, Costa Rica, 23-30 April, pp. 1001-1007.
  23. #
  24. # for LANDSAT 5: see Pohl, C 1996 and others
  25. #
  26. # TODO: add overwrite test at beginning of the script
  27. #############################################################################
  28. #%Module
  29. #% description: Brovey transform to merge multispectral and high-res panchromatic channels
  30. #% keywords: raster, imagery, fusion
  31. #%End
  32. #%Flag
  33. #% key: l
  34. #% description: sensor: LANDSAT
  35. #%END
  36. #%Flag
  37. #% key: q
  38. #% description: sensor: QuickBird
  39. #%END
  40. #%Flag
  41. #% key: s
  42. #% description: sensor: SPOT
  43. #%END
  44. #%option
  45. #% key: ms1
  46. #% type: string
  47. #% gisprompt: old,cell,raster
  48. #% description: raster input map (green: tm2 | qbird_green | spot1)
  49. #% required : yes
  50. #%end
  51. #%option
  52. #% key: ms2
  53. #% type: string
  54. #% gisprompt: old,cell,raster
  55. #% description: raster input map (NIR: tm4 | qbird_nir | spot2)
  56. #% required : yes
  57. #%end
  58. #%option
  59. #% key: ms3
  60. #% type: string
  61. #% gisprompt: old,cell,raster
  62. #% description: raster input map (MIR; tm5 | qbird_red | spot3)
  63. #% required : yes
  64. #%end
  65. #%option
  66. #% key: pan
  67. #% type: string
  68. #% gisprompt: old,cell,raster
  69. #% description: raster input map (etmpan | qbird_pan | spotpan)
  70. #% required : yes
  71. #%end
  72. #%option
  73. #% key: outputprefix
  74. #% type: string
  75. #% gisprompt: new,cell,raster
  76. #% description: raster output map prefix (e.g. 'brov')
  77. #% required : yes
  78. #%end
  79. import sys
  80. import os
  81. import string
  82. import grass
  83. def main():
  84. global tmp
  85. landsat = flags['l']
  86. quickbird = flags['q']
  87. spot = flags['s']
  88. ms1 = options['ms1']
  89. ms2 = options['ms2']
  90. ms3 = options['ms3']
  91. pan = options['pan']
  92. out = options['outputprefix']
  93. tmp = str(os.getpid())
  94. if not landsat and not quickbird and not spot:
  95. grass.fatal("Please select a flag to specify the satellite sensor")
  96. #get PAN resolution:
  97. s = grass.read_command('r.info', flags = 's', map = pan)
  98. kv = grass.parse_key_val(s)
  99. nsres = float(kv['nsres'])
  100. ewres = float(kv['ewres'])
  101. panres = (nsres + ewres) / 2
  102. # clone current region
  103. grass.use_temp_region()
  104. grass.message("Using resolution from PAN: %f" % panres)
  105. grass.run_command('g.region', flags = 'a', res = panres)
  106. grass.message("Performing Brovey transformation...")
  107. # The formula was originally developed for LANDSAT-TM5 and SPOT,
  108. # but it also works well with LANDSAT-TM7
  109. # LANDSAT formula:
  110. # r.mapcalc "brov.red=1. * tm.5 / (tm.2 + tm.4 + tm.5) * etmpan"
  111. # r.mapcalc "brov.green=1. * tm.4 /(tm.2 + tm.4 + tm.5) * etmpan"
  112. # r.mapcalc "brov.blue=1. * tm.2 / (tm.2 + tm.4 + tm.5) * etmpan"
  113. #
  114. # SPOT formula:
  115. # r.mapcalc "brov.red= 1. * spot.ms.3 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p"
  116. # r.mapcalc "brov.green=1. * spot.ms.2 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p"
  117. # r.mapcalc "brov.blue= 1. * spot.ms.1 / (spot.ms.1 + spot.ms.2 + spot.ms.3) * spot.p"
  118. # note: for RGB composite then revert brov.red and brov.green!
  119. grass.message("Calculating %s.{red,green,blue}: ..." % out)
  120. t = string.Template(
  121. '''eval(k = float("$pan") / ("$ms1" + "$ms2" + "$ms3"))
  122. "$out.red" = "$ms3" * k
  123. "$out.green" = "$ms2" * k
  124. "$out.blue" = "$ms1" * k''')
  125. e = t.substitute(out = out, pan = pan, ms1 = ms1, ms2 = ms2, ms3 = ms3)
  126. if grass.run_command('r.mapcalc', expression = e) != 0:
  127. grass.fatal("An error occurred while running r.mapcalc")
  128. # Maybe?
  129. #r.colors $GIS_OPT_OUTPUTPREFIX.red col=grey
  130. #r.colors $GIS_OPT_OUTPUTPREFIX.green col=grey
  131. #r.colors $GIS_OPT_OUTPUTPREFIX.blue col=grey
  132. #to blue-ish, therefore we modify
  133. #r.colors $GIS_OPT_OUTPUTPREFIX.blue col=rules << EOF
  134. #5 0 0 0
  135. #20 200 200 200
  136. #40 230 230 230
  137. #67 255 255 255
  138. #EOF
  139. if spot:
  140. #apect table is nice for SPOT:
  141. grass.message("Assigning color tables for SPOT ...")
  142. for ch in ['red', 'green', 'blue']:
  143. grass.run_command('r.colors', map = "%s.%s" % (out, ch), col = 'aspect')
  144. grass.message("Fixing output names...")
  145. for s, d in [('green','tmp'),('red','green'),('tmp','red')]:
  146. src = "%s.%s" % (out, s)
  147. dst = "%s.%s" % (out, d)
  148. grass.run_command('g.rename', rast = (src, dst), quiet = True)
  149. else:
  150. #aspect table is nice for LANDSAT and QuickBird:
  151. grass.message("Assigning color tables for LANDSAT or QuickBird ...")
  152. for ch in ['red', 'green', 'blue']:
  153. grass.run_command('r.colors', map = "%s.%s" % (out, ch), col = 'aspect')
  154. grass.message("Following pan-sharpened output maps have been generated:")
  155. for ch in ['red', 'green', 'blue']:
  156. grass.message("%s.%s" % (out, ch))
  157. grass.message("To visualize output, run:")
  158. grass.message("g.region -p rast=%s.red" % out)
  159. grass.message("d.rgb r=%s.red g=%s.green b=%s.blue" % (out, out, out))
  160. grass.message("If desired, combine channels with 'r.composite' to a single map.")
  161. # write cmd history:
  162. for ch in ['red', 'green', 'blue']:
  163. grass.raster_history("%s.%s" % (out, ch))
  164. if __name__ == "__main__":
  165. options, flags = grass.parser()
  166. main()