i.tasscap.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/env python
  2. #
  3. ############################################################################
  4. #
  5. # MODULE: i.tasscap
  6. # AUTHOR(S): Markus Neteler. neteler itc.it
  7. # Converted to Python by Glynn Clements
  8. # PURPOSE: At-satellite reflectance based tasseled cap transformation.
  9. # COPYRIGHT: (C) 1997-2004,2008, 2014 by the GRASS Development Team
  10. #
  11. # This program is free software under the GNU General Public
  12. # License (>=v2). Read the file COPYING that comes with GRASS
  13. # for details.
  14. #
  15. #############################################################################
  16. # References:
  17. # LANDSAT-4/LANDSAT-5:
  18. # script based on i.tasscap.tm4 from Dr. Agustin Lobo - alobo@ija.csic.es
  19. # TC-factor changed to CRIST et al. 1986, p.1467 (Markus Neteler 1/99)
  20. # Proc. IGARSS 1986
  21. #
  22. # LANDSAT-7:
  23. # TASSCAP factors cited from:
  24. # DERIVATION OF A TASSELED CAP TRANSFORMATION BASED ON LANDSAT 7 AT-SATELLITE REFLECTANCE
  25. # Chengquan Huang, Bruce Wylie, Limin Yang, Collin Homer and Gregory Zylstra Raytheon ITSS,
  26. # USGS EROS Data Center Sioux Falls, SD 57198, USA
  27. # http://landcover.usgs.gov/pdf/tasseled.pdf
  28. #
  29. # This is published as well in INT. J. OF RS, 2002, VOL 23, NO. 8, 1741-1748.
  30. # Compare discussion:
  31. # http://adis.cesnet.cz/cgi-bin/lwgate/IMAGRS-L/archives/imagrs-l.log0211/date/article-14.html
  32. #
  33. # Landsat8: Baig, M.H.A., Zhang, L., Shuai, T., Tong, Q., 2014. Derivation of a tasselled cap transformation
  34. # based on Landsat 8 at-satellite reflectance. Remote Sensing Letters 5, 423-431.
  35. # doi:10.1080/2150704X.2014.915434
  36. #
  37. # MODIS Tasselled Cap coefficients
  38. # https://gis.stackexchange.com/questions/116107/tasseled-cap-transformation-on-modis-in-grass/116110
  39. # Ref: Lobser & Cohen (2007). MODIS tasselled cap: land cover characteristics
  40. # expressed through transformed MODIS data.
  41. # International Journal of Remote Sensing, Volume 28(22), Table 3
  42. #
  43. # TODO: Check if these MODIS Tasseled Cap coefficients are different:
  44. # http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=1025776
  45. #############################################################################
  46. #
  47. #%Module
  48. #% description: Performs Tasseled Cap (Kauth Thomas) transformation.
  49. #% keywords: imagery
  50. #% keywords: transformation
  51. #% keywords: Landsat
  52. #% keywords: MODIS
  53. #% keywords: Tasseled Cap transformation
  54. #%end
  55. #%option G_OPT_R_INPUTS
  56. #% description: For Landsat4-7: bands 1, 2, 3, 4, 5, and 7; for Landsat8: bands 2, 3, 4, 5, 6, and 7
  57. #%end
  58. #%option G_OPT_R_BASENAME_OUTPUT
  59. #% label: Name for output basename raster map(s)
  60. #%end
  61. #%option
  62. #% key: sensor
  63. #% type: string
  64. #% description: Satellite sensor
  65. #% required: yes
  66. #% multiple: no
  67. #% options: landsat4_tm,landsat5_tm,landsat7_etm,landsat8,modis
  68. #% descriptions: landsat4_tm;Use transformation rules for Landsat 4 TM;landsat5_tm;Use transformation rules for Landsat 5 TM;landsat7_etm;Use transformation rules for Landsat 7 ETM;landsat8;Use transformation rules for Landsat 8;modis;Use transformation rules for MODIS
  69. #%end
  70. import grass.script as grass
  71. # weights for 6 Landsat bands: TM4, TM5, TM7, OLI
  72. # MODIS: Red, NIR1, Blue, Green, NIR2, SWIR1, SWIR2
  73. parms = [[( 0.3037, 0.2793, 0.4743, 0.5585, 0.5082, 0.1863), # Landsat TM4
  74. (-0.2848,-0.2435,-0.5435, 0.7243, 0.0840,-0.1800),
  75. ( 0.1509, 0.1973, 0.3279, 0.3406,-0.7112,-0.4572)],
  76. [( 0.2909, 0.2493, 0.4806, 0.5568, 0.4438, 0.1706, 10.3695), # Landsat TM5
  77. (-0.2728,-0.2174,-0.5508, 0.7221, 0.0733,-0.1648, -0.7310),
  78. ( 0.1446, 0.1761, 0.3322, 0.3396,-0.6210,-0.4186, -3.3828),
  79. ( 0.8461,-0.0731,-0.4640,-0.0032,-0.0492,-0.0119, 0.7879)],
  80. [( 0.3561, 0.3972, 0.3904, 0.6966, 0.2286, 0.1596), # Landsat TM7
  81. (-0.3344,-0.3544,-0.4556, 0.6966,-0.0242,-0.2630),
  82. ( 0.2626, 0.2141, 0.0926, 0.0656,-0.7629,-0.5388),
  83. ( 0.0805,-0.0498, 0.1950,-0.1327, 0.5752,-0.7775)],
  84. [( 0.3029, 0.2786, 0.4733, 0.5599, 0.5080, 0.1872), # Landsat TM8
  85. (-0.2941,-0.2430,-0.5424, 0.7276, 0.0713,-0.1608),
  86. ( 0.1511, 0.1973, 0.3283, 0.3407,-0.7117,-0.4559),
  87. (-0.8239, 0.0849, 0.4396, -0.058, 0.2013,-0.2773)],
  88. [( 0.4395, 0.5945, 0.2460, 0.3918, 0.3506, 0.2136, 0.2678), # MODIS
  89. (-0.4064, 0.5129,-0.2744,-0.2893, 0.4882,-0.0036,-0.4169),
  90. ( 0.1147, 0.2489, 0.2408, 0.3132,-0.3122,-0.6416,-0.5087)]]
  91. ordinals = ["first", "second", "third", "fourth"]
  92. names = ["Brightness", "Greenness", "Wetness", "Haze"]
  93. def calc1(out, bands, k1, k2, k3, k4, k5, k7, k0 = 0):
  94. grass.mapcalc(
  95. "$out = $k1 * $band1 + $k2 * $band2 + $k3 * $band3 + $k4 * $band4 + $k5 * $band5 + $k7 * $band7 + $k0",
  96. out = out, k1 = k1, k2 = k2, k3 = k3, k4 = k4, k5 = k5, k7 = k7, k0 = k0, **bands)
  97. grass.run_command('r.colors', map = out, color = 'grey')
  98. def calcN(outpre, bands, i, n):
  99. grass.message(_("Satellite band-%d...") % n)
  100. for j, p in enumerate(parms[i]):
  101. out = "%s.%d" % (outpre, j + 1)
  102. ord = ordinals[j]
  103. if n == 4:
  104. name = ''
  105. else:
  106. name = " (%s)" % names[j]
  107. grass.message(_("Calculating %s TC component %s%s ...") % (ord, out, name))
  108. calc1(out, bands, *p)
  109. def main():
  110. options, flags = grass.parser()
  111. satellite = options['sensor']
  112. output_basename = options['output']
  113. inputs = options['input'].split(',')
  114. num_of_bands = 6
  115. if len(inputs) != num_of_bands:
  116. grass.fatal(_("The number of input raster maps (bands) should be %s") % num_of_bands)
  117. # this is here just for the compatibility with r.mapcalc expression
  118. # remove this if not really needed in new implementation
  119. bands = {}
  120. for i, band in enumerate(inputs):
  121. band_num = i + 1
  122. if band_num == 6:
  123. band_num = 7
  124. bands['band' + str(band_num)] = band
  125. print bands
  126. if satellite == 'landsat4_tm':
  127. calcN(output_basename, bands, 0, 4)
  128. elif satellite == 'landsat5_tm':
  129. calcN(output_basename, bands, 1, 5)
  130. elif satellite == 'landsat7_etm':
  131. calcN(output_basename, bands, 2, 7)
  132. elif satellite == 'landsat8':
  133. calcN(output_basename, bands, 2, 7)
  134. elif satellite == 'modis':
  135. calcN(output_basename, bands, 3, 7)
  136. else:
  137. raise RuntimeError("Invalid satellite: " + satellite)
  138. grass.message(_("Tasseled Cap components calculated"))
  139. if __name__ == "__main__":
  140. main()