123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- #!/usr/bin/env python3
- ############################################################################
- #
- # MODULE: i.in.spot
- #
- # AUTHOR(S): Markus Neteler
- # Converted to Python by Glynn Clements
- #
- # PURPOSE: Import SPOT VEGETATION data into a GRASS raster map
- # SPOT Vegetation (1km, global) data:
- # http://free.vgt.vito.be/
- #
- # COPYRIGHT: (c) 2004-2011 GRASS Development Team
- #
- # This program is free software under the GNU General Public
- # License (>=v2). Read the file COPYING that comes with GRASS
- # for details.
- #
- #############################################################################
- #
- # REQUIREMENTS:
- # - gdal: http://www.gdal.org
- #
- # Notes:
- # * According to the faq (http://www.vgt.vito.be/faq/faq.html), SPOT vegetation
- # coordinates refer to the center of a pixel.
- # * GDAL coordinates refer to the corner of a pixel
- # -> correction of 0001/0001_LOG.TXT coordinates by 0.5 pixel
- #############################################################################
- # %module
- # % description: Imports SPOT VGT NDVI data into a raster map.
- # % keyword: imagery
- # % keyword: import
- # % keyword: NDVI
- # % keyword: SPOT
- # %end
- # %flag
- # % key: a
- # % description: Also import quality map (SM status map layer) and filter NDVI map
- # %end
- # %option G_OPT_F_INPUT
- # % description: Name of input SPOT VGT NDVI HDF file
- # %end
- # % option G_OPT_R_OUTPUT
- # % required : no
- # %end
- import os
- import atexit
- import string
- import grass.script as gscript
- from grass.exceptions import CalledModuleError
- vrt = """<VRTDataset rasterXSize="$XSIZE" rasterYSize="$YSIZE">
- <SRS>GEOGCS["wgs84",DATUM["WGS_1984",SPHEROID["wgs84",6378137,298.257223563],TOWGS84[0.000,0.000,0.000]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]]</SRS>
- <GeoTransform>$WESTCORNER, $RESOLUTION, 0.0000000000000000e+00, $NORTHCORNER, 0.0000000000000e+00, -$RESOLUTION</GeoTransform>
- <VRTRasterBand dataType="Byte" band="1">
- <NoDataValue>0.00000000000000E+00</NoDataValue>
- <ColorInterp>Gray</ColorInterp>
- <SimpleSource>
- <SourceFilename>$FILENAME</SourceFilename>
- <SourceBand>1</SourceBand>
- <SrcRect xOff="0" yOff="0" xSize="$XSIZE" ySize="$YSIZE"/>
- <DstRect xOff="0" yOff="0" xSize="$XSIZE" ySize="$YSIZE"/>
- </SimpleSource>
- </VRTRasterBand>
- </VRTDataset>"""
- # a function for writing VRT files
- def create_VRT_file(projfile, vrtfile, infile):
- fh = open(projfile)
- kv = {}
- for line in fh:
- f = line.rstrip("\r\n").split()
- if f < 2:
- continue
- kv[f[0]] = f[1]
- fh.close()
- north_center = kv["CARTO_UPPER_LEFT_Y"]
- # south_center = kv['CARTO_LOWER_LEFT_Y']
- # east_center = kv['CARTO_UPPER_RIGHT_X']
- west_center = kv["CARTO_UPPER_LEFT_X"]
- map_proj_res = kv["MAP_PROJ_RESOLUTION"]
- xsize = kv["IMAGE_UPPER_RIGHT_COL"]
- ysize = kv["IMAGE_LOWER_RIGHT_ROW"]
- resolution = float(map_proj_res)
- north_corner = float(north_center) + resolution / 2
- # south_corner = float(south_center) - resolution / 2
- # east_corner = float(east_center) + resolution / 2
- west_corner = float(west_center) - resolution / 2
- t = string.Template(vrt)
- s = t.substitute(
- NORTHCORNER=north_corner,
- WESTCORNER=west_corner,
- XSIZE=xsize,
- YSIZE=ysize,
- RESOLUTION=map_proj_res,
- FILENAME=infile,
- )
- outf = open(vrtfile, "w")
- outf.write(s)
- outf.close()
- def cleanup():
- # clean up the mess
- gscript.try_remove(vrtfile)
- gscript.try_remove(tmpfile)
- def main():
- global vrtfile, tmpfile
- infile = options["input"]
- rast = options["output"]
- also = flags["a"]
- # check for gdalinfo (just to check if installation is complete)
- if not gscript.find_program("gdalinfo", "--help"):
- gscript.fatal(
- _("'gdalinfo' not found, install GDAL tools first " "(http://www.gdal.org)")
- )
- pid = str(os.getpid())
- tmpfile = gscript.tempfile()
- # let's go
- spotdir = os.path.dirname(infile)
- spotname = gscript.basename(infile, "hdf")
- if rast:
- name = rast
- else:
- name = spotname
- if not gscript.overwrite() and gscript.find_file(name)["file"]:
- gscript.fatal(_("<%s> already exists. Aborting.") % name)
- # still a ZIP file? (is this portable?? see the r.in.srtm script for
- # ideas)
- if infile.lower().endswith(".zip"):
- gscript.fatal(_("Please extract %s before import.") % infile)
- try:
- p = gscript.Popen(["file", "-ib", infile], stdout=gscript.PIPE)
- s = p.communicate()[0]
- if s == "application/x-zip":
- gscript.fatal(_("Please extract %s before import.") % infile)
- except:
- pass
- # create VRT header for NDVI
- projfile = os.path.join(spotdir, "0001_LOG.TXT")
- vrtfile = tmpfile + ".vrt"
- # first process the NDVI:
- gscript.try_remove(vrtfile)
- create_VRT_file(projfile, vrtfile, infile)
- # let's import the NDVI map...
- gscript.message(_("Importing SPOT VGT NDVI map..."))
- try:
- gscript.run_command("r.in.gdal", input=vrtfile, output=name)
- except CalledModuleError:
- gscript.fatal(_("An error occurred. Stop."))
- gscript.message(_("Imported SPOT VEGETATION NDVI map <%s>.") % name)
- #################
- # http://www.vgt.vito.be/faq/FAQS/faq19.html
- # What is the relation between the digital number and the real NDVI ?
- # Real NDVI =coefficient a * Digital Number + coefficient b
- # = a * DN +b
- #
- # Coefficient a = 0.004
- # Coefficient b = -0.1
- # clone current region
- # switch to a temporary region
- gscript.use_temp_region()
- gscript.run_command("g.region", raster=name, quiet=True)
- gscript.message(_("Remapping digital numbers to NDVI..."))
- tmpname = "%s_%s" % (name, pid)
- gscript.mapcalc("$tmpname = 0.004 * $name - 0.1", tmpname=tmpname, name=name)
- gscript.run_command("g.remove", type="raster", name=name, quiet=True, flags="f")
- gscript.run_command("g.rename", raster=(tmpname, name), quiet=True)
- # write cmd history:
- gscript.raster_history(name)
- # apply color table:
- gscript.run_command("r.colors", map=name, color="ndvi", quiet=True)
- ##########################
- # second, optionally process the SM quality map:
- # SM Status Map
- # http://nieuw.vgt.vito.be/faq/FAQS/faq22.html
- # Data about
- # Bit NR 7: Radiometric quality for B0 coded as 0 if bad and 1 if good
- # Bit NR 6: Radiometric quality for B2 coded as 0 if bad and 1 if good
- # Bit NR 5: Radiometric quality for B3 coded as 0 if bad and 1 if good
- # Bit NR 4: Radiometric quality for MIR coded as 0 if bad and 1 if good
- # Bit NR 3: land code 1 or water code 0
- # Bit NR 2: ice/snow code 1 , code 0 if there is no ice/snow
- # Bit NR 1: 0 0 1 1
- # Bit NR 0: 0 1 0 1
- # clear shadow uncertain cloud
- #
- # Note:
- # pos 7 6 5 4 3 2 1 0 (bit position)
- # 128 64 32 16 8 4 2 1 (values for 8 bit)
- #
- #
- # Bit 4-7 should be 1: their sum is 240
- # Bit 3 land code, should be 1, sum up to 248 along with higher bits
- # Bit 2 ice/snow code
- # Bit 0-1 should be 0
- #
- # A good map threshold: >= 248
- if also:
- gscript.message(_("Importing SPOT VGT NDVI quality map..."))
- gscript.try_remove(vrtfile)
- qname = spotname.replace("NDV", "SM")
- qfile = os.path.join(spotdir, qname)
- create_VRT_file(projfile, vrtfile, qfile)
- # let's import the SM quality map...
- smfile = name + ".sm"
- try:
- gscript.run_command("r.in.gdal", input=vrtfile, output=smfile)
- except CalledModuleError:
- gscript.fatal(_("An error occurred. Stop."))
- # some of the possible values:
- rules = [
- r + "\n"
- for r in [
- "8 50 50 50",
- "11 70 70 70",
- "12 90 90 90",
- "60 grey",
- "155 blue",
- "232 violet",
- "235 red",
- "236 brown",
- "248 orange",
- "251 yellow",
- "252 green",
- ]
- ]
- gscript.write_command("r.colors", map=smfile, rules="-", stdin=rules)
- gscript.message(_("Imported SPOT VEGETATION SM quality map <%s>.") % smfile)
- gscript.message(
- _(
- "Note: A snow map can be extracted by category "
- "252 (d.rast %s cat=252)"
- )
- % smfile
- )
- gscript.message("")
- gscript.message(_("Filtering NDVI map by Status Map quality layer..."))
- filtfile = "%s_filt" % name
- gscript.mapcalc(
- "$filtfile = if($smfile % 4 == 3 || "
- "($smfile / 16) % 16 == 0, null(), $name)",
- filtfile=filtfile,
- smfile=smfile,
- name=name,
- )
- gscript.run_command("r.colors", map=filtfile, color="ndvi", quiet=True)
- gscript.message(_("Filtered SPOT VEGETATION NDVI map <%s>.") % filtfile)
- # write cmd history:
- gscript.raster_history(smfile)
- gscript.raster_history(filtfile)
- gscript.message(_("Done."))
- if __name__ == "__main__":
- options, flags = gscript.parser()
- atexit.register(cleanup)
- main()
|