i.in.spotvgt.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: i.in.spot
  5. #
  6. # AUTHOR(S): Markus Neteler
  7. # Converted to Python by Glynn Clements
  8. #
  9. # PURPOSE: Import SPOT VEGETATION data into a GRASS raster map
  10. # SPOT Vegetation (1km, global) data:
  11. # http://free.vgt.vito.be/
  12. #
  13. # COPYRIGHT: (c) 2004-2011 GRASS Development Team
  14. #
  15. # This program is free software under the GNU General Public
  16. # License (>=v2). Read the file COPYING that comes with GRASS
  17. # for details.
  18. #
  19. #############################################################################
  20. #
  21. # REQUIREMENTS:
  22. # - gdal: http://www.gdal.org
  23. #
  24. # Notes:
  25. # * According to the faq (http://www.vgt.vito.be/faq/faq.html), SPOT vegetation
  26. # coordinates refer to the center of a pixel.
  27. # * GDAL coordinates refer to the corner of a pixel
  28. # -> correction of 0001/0001_LOG.TXT coordinates by 0.5 pixel
  29. #############################################################################
  30. #%module
  31. #% description: Imports SPOT VGT NDVI data into a raster map.
  32. #% keywords: imagery
  33. #% keywords: import
  34. #%end
  35. #%flag
  36. #% key: a
  37. #% description: Also import quality map (SM status map layer) and filter NDVI map
  38. #%end
  39. #%option G_OPT_F_INPUT
  40. #% description: Name of input SPOT VGT NDVI HDF file
  41. #%end
  42. #% option G_OPT_R_OUTPUT
  43. #% required : no
  44. #%end
  45. import sys
  46. import os
  47. import atexit
  48. import string
  49. import grass.script as grass
  50. vrt = """<VRTDataset rasterXSize="$XSIZE" rasterYSize="$YSIZE">
  51. <SRS>GEOGCS[&quot;wgs84&quot;,DATUM[&quot;WGS_1984&quot;,SPHEROID[&quot;wgs84&quot;,6378137,298.257223563],TOWGS84[0.000,0.000,0.000]],PRIMEM[&quot;Greenwich&quot;,0],UNIT[&quot;degree&quot;,0.0174532925199433]]</SRS>
  52. <GeoTransform>$WESTCORNER, $RESOLUTION, 0.0000000000000000e+00, $NORTHCORNER, 0.0000000000000e+00, -$RESOLUTION</GeoTransform>
  53. <VRTRasterBand dataType="Byte" band="1">
  54. <NoDataValue>0.00000000000000E+00</NoDataValue>
  55. <ColorInterp>Gray</ColorInterp>
  56. <SimpleSource>
  57. <SourceFilename>$FILENAME</SourceFilename>
  58. <SourceBand>1</SourceBand>
  59. <SrcRect xOff="0" yOff="0" xSize="$XSIZE" ySize="$YSIZE"/>
  60. <DstRect xOff="0" yOff="0" xSize="$XSIZE" ySize="$YSIZE"/>
  61. </SimpleSource>
  62. </VRTRasterBand>
  63. </VRTDataset>"""
  64. #### a function for writing VRT files
  65. def create_VRT_file(projfile, vrtfile, infile):
  66. fh = file(projfile)
  67. kv = {}
  68. for l in fh:
  69. f = l.rstrip('\r\n').split()
  70. if f < 2:
  71. continue
  72. kv[f[0]] = f[1]
  73. fh.close()
  74. north_center = kv['CARTO_UPPER_LEFT_Y']
  75. south_center = kv['CARTO_LOWER_LEFT_Y']
  76. east_center = kv['CARTO_UPPER_RIGHT_X']
  77. west_center = kv['CARTO_UPPER_LEFT_X']
  78. map_proj_res = kv['MAP_PROJ_RESOLUTION']
  79. xsize = kv['IMAGE_UPPER_RIGHT_COL']
  80. ysize = kv['IMAGE_LOWER_RIGHT_ROW']
  81. resolution = float(map_proj_res)
  82. north_corner = float(north_center) + resolution / 2
  83. south_corner = float(south_center) - resolution / 2
  84. east_corner = float(east_center ) + resolution / 2
  85. west_corner = float(west_center ) - resolution / 2
  86. t = string.Template(vrt)
  87. s = t.substitute(NORTHCORNER = north_corner, WESTCORNER = west_corner,
  88. XSIZE = xsize, YSIZE = ysize, RESOLUTION = map_proj_res,
  89. FILENAME = infile)
  90. outf = file(vrtfile, 'w')
  91. outf.write(s)
  92. outf.close()
  93. def cleanup():
  94. #### clean up the mess
  95. grass.try_remove(vrtfile)
  96. grass.try_remove(tmpfile)
  97. def main():
  98. global vrtfile, tmpfile
  99. infile = options['input']
  100. rast = options['output']
  101. also = flags['a']
  102. #### check for gdalinfo (just to check if installation is complete)
  103. if not grass.find_program('gdalinfo', '--help'):
  104. grass.fatal(_("'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)"))
  105. pid = str(os.getpid())
  106. tmpfile = grass.tempfile()
  107. ################### let's go
  108. spotdir = os.path.dirname(infile)
  109. spotname = grass.basename(infile, 'hdf')
  110. if rast:
  111. name = rast
  112. else:
  113. name = spotname
  114. if not grass.overwrite() and grass.find_file(name)['file']:
  115. grass.fatal(_("<%s> already exists. Aborting.") % name)
  116. # still a ZIP file? (is this portable?? see the r.in.srtm script for ideas)
  117. if infile.lower().endswith('.zip'):
  118. grass.fatal(_("Please extract %s before import.") % infile)
  119. try:
  120. p = grass.Popen(['file', '-ib', infile], stdout = grass.PIPE)
  121. s = p.communicate()[0]
  122. if s == "application/x-zip":
  123. grass.fatal(_("Please extract %s before import.") % infile)
  124. except:
  125. pass
  126. ### create VRT header for NDVI
  127. projfile = os.path.join(spotdir, "0001_LOG.TXT")
  128. vrtfile = tmpfile + '.vrt'
  129. # first process the NDVI:
  130. grass.try_remove(vrtfile)
  131. create_VRT_file(projfile, vrtfile, infile)
  132. ## let's import the NDVI map...
  133. grass.message(_("Importing SPOT VGT NDVI map..."))
  134. if grass.run_command('r.in.gdal', input = vrtfile, output = name) != 0:
  135. grass.fatal(_("An error occurred. Stop."))
  136. grass.message(_("Imported SPOT VEGETATION NDVI map <%s>.") % name)
  137. #################
  138. ## http://www.vgt.vito.be/faq/FAQS/faq19.html
  139. # What is the relation between the digital number and the real NDVI ?
  140. # Real NDVI =coefficient a * Digital Number + coefficient b
  141. # = a * DN +b
  142. #
  143. # Coefficient a = 0.004
  144. # Coefficient b = -0.1
  145. # clone current region
  146. # switch to a temporary region
  147. grass.use_temp_region()
  148. grass.run_command('g.region', rast = name, quiet = True)
  149. grass.message(_("Remapping digital numbers to NDVI..."))
  150. tmpname = "%s_%s" % (name, pid)
  151. grass.mapcalc("$tmpname = 0.004 * $name - 0.1", tmpname = tmpname, name = name)
  152. grass.run_command('g.remove', rast = name, quiet = True)
  153. grass.run_command('g.rename', rast = (tmpname, name), quiet = True)
  154. # write cmd history:
  155. grass.raster_history(name)
  156. #apply color table:
  157. grass.run_command('r.colors', map = name, color = 'ndvi', quiet = True)
  158. ##########################
  159. # second, optionally process the SM quality map:
  160. #SM Status Map
  161. # http://nieuw.vgt.vito.be/faq/FAQS/faq22.html
  162. #Data about
  163. # Bit NR 7: Radiometric quality for B0 coded as 0 if bad and 1 if good
  164. # Bit NR 6: Radiometric quality for B2 coded as 0 if bad and 1 if good
  165. # Bit NR 5: Radiometric quality for B3 coded as 0 if bad and 1 if good
  166. # Bit NR 4: Radiometric quality for MIR coded as 0 if bad and 1 if good
  167. # Bit NR 3: land code 1 or water code 0
  168. # Bit NR 2: ice/snow code 1 , code 0 if there is no ice/snow
  169. # Bit NR 1: 0 0 1 1
  170. # Bit NR 0: 0 1 0 1
  171. # clear shadow uncertain cloud
  172. #
  173. #Note:
  174. # pos 7 6 5 4 3 2 1 0 (bit position)
  175. # 128 64 32 16 8 4 2 1 (values for 8 bit)
  176. #
  177. #
  178. # Bit 4-7 should be 1: their sum is 240
  179. # Bit 3 land code, should be 1, sum up to 248 along with higher bits
  180. # Bit 2 ice/snow code
  181. # Bit 0-1 should be 0
  182. #
  183. # A good map threshold: >= 248
  184. if also:
  185. grass.message(_("Importing SPOT VGT NDVI quality map..."))
  186. grass.try_remove(vrtfile)
  187. qname = spotname.replace('NDV','SM')
  188. qfile = os.path.join(spotdir, qname)
  189. create_VRT_file(projfile, vrtfile, qfile)
  190. ## let's import the SM quality map...
  191. smfile = name + '.sm'
  192. if grass.run_command('r.in.gdal', input = vrtfile, output = smfile) != 0:
  193. grass.fatal(_("An error occurred. Stop."))
  194. # some of the possible values:
  195. rules = [r + '\n' for r in [
  196. '8 50 50 50',
  197. '11 70 70 70',
  198. '12 90 90 90',
  199. '60 grey',
  200. '155 blue',
  201. '232 violet',
  202. '235 red',
  203. '236 brown',
  204. '248 orange',
  205. '251 yellow',
  206. '252 green'
  207. ]]
  208. grass.write_command('r.colors', map = smfile, rules = '-', stdin = rules)
  209. grass.message(_("Imported SPOT VEGETATION SM quality map <%s>.") % smfile)
  210. grass.message(_("Note: A snow map can be extracted by category 252 (d.rast %s cat=252)") % smfile)
  211. grass.message("")
  212. grass.message(_("Filtering NDVI map by Status Map quality layer..."))
  213. filtfile = "%s_filt" % name
  214. grass.mapcalc("$filtfile = if($smfile % 4 == 3 || ($smfile / 16) % 16 == 0, null(), $name)",
  215. filtfile = filtfile, smfile = smfile, name = name)
  216. grass.run_command('r.colors', map = filtfile, color = 'ndvi', quiet = True)
  217. grass.message(_("Filtered SPOT VEGETATION NDVI map <%s>.") % filtfile)
  218. # write cmd history:
  219. grass.raster_history(smfile)
  220. grass.raster_history(filtfile)
  221. grass.message(_("Done."))
  222. if __name__ == "__main__":
  223. options, flags = grass.parser()
  224. atexit.register(cleanup)
  225. main()