i.in.spotvgt.py 8.5 KB

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