[GRASS-SVN] r65935 - in grass-addons/grass7/imagery: . i.histo.match i.nightlights.intercalibration i.segment.hierarchical
svn_grass at osgeo.org
svn_grass at osgeo.org
Fri Aug 14 13:40:21 PDT 2015
Author: nikosa
Date: 2015-08-14 13:40:21 -0700 (Fri, 14 Aug 2015)
New Revision: 65935
Added:
grass-addons/grass7/imagery/i.nightlights.intercalibration/
grass-addons/grass7/imagery/i.nightlights.intercalibration/Makefile
grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.html
grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.py
grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_coefficients.py
grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_equations.py
grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_models.py
grass-addons/grass7/imagery/i.nightlights.intercalibration/test_intercalibration_models.py
Modified:
grass-addons/grass7/imagery/i.histo.match/i.histo.match.py
grass-addons/grass7/imagery/i.segment.hierarchical/Makefile
Log:
?\206?\153nter-satellite calibration on DMSP-OLS Nighttime Lights Time Series
Modified: grass-addons/grass7/imagery/i.histo.match/i.histo.match.py
===================================================================
--- grass-addons/grass7/imagery/i.histo.match/i.histo.match.py 2015-08-14 16:14:42 UTC (rev 65934)
+++ grass-addons/grass7/imagery/i.histo.match/i.histo.match.py 2015-08-14 20:40:21 UTC (rev 65935)
@@ -1,32 +1,35 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-############################################################################
-#
-# MODULE: i.histo.match
-# AUTHOR(S): Luca Delucchi, Fondazione E. Mach (Italy)
-# original PERL code was developed by:
-# Laura Zampa (2004) student of Dipartimento di Informatica e
-# Telecomunicazioni, Facoltà di Ingegneria,
-# University of Trento and ITC-irst, Trento (Italy)
-#
-# PURPOSE: Calculate histogram matching of several images
-# COPYRIGHT: (C) 2011 by the 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.
-#
-# TODO: use "BEGIN TRANSACTION" etc?
-#############################################################################
+
+"""
+ MODULE: i.histo.match
+ AUTHOR(S): Luca Delucchi, Fondazione E. Mach (Italy)
+ original PERL code was developed by:
+ Laura Zampa (2004) student of Dipartimento di Informatica e
+ Telecomunicazioni, Facoltà di Ingegneria,
+ University of Trento and ITC-irst, Trento (Italy)
+
+ PURPOSE: Calculate histogram matching of several images
+ COPYRIGHT: (C) 2011 by the 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.
+
+ TODO: use "BEGIN TRANSACTION" etc?
+"""
+
#%module
#% description: Calculate histogram matching of several images.
#% keyword: imagery
#% keyword: histogram matching
#%end
+
#%option G_OPT_R_INPUTS
#% description: Name of raster maps to analize
#% required: yes
#%end
+
#%option
#% key: suffix
#% type: string
@@ -35,14 +38,17 @@
#% required: no
#% answer: match
#%end
+
#%option G_OPT_R_OUTPUT
#% description: Name for mosaic output map
#% required: no
#%end
+
#%option G_OPT_DB_DATABASE
#% required : no
#% answer: $GISDBASE/$LOCATION_NAME/$MAPSET/histo.db
#%end
+
#%option
#% key: max
#% type: integer
Added: grass-addons/grass7/imagery/i.nightlights.intercalibration/Makefile
===================================================================
--- grass-addons/grass7/imagery/i.nightlights.intercalibration/Makefile (rev 0)
+++ grass-addons/grass7/imagery/i.nightlights.intercalibration/Makefile 2015-08-14 20:40:21 UTC (rev 65935)
@@ -0,0 +1,10 @@
+MODULE_TOPDIR = ../..
+
+PGM = i.nightlights.intercalibration
+
+ETCFILES = intercalibration_equations intercalibration_coefficients intercalibration_models
+
+include $(MODULE_TOPDIR)/include/Make/Script.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+
+default: script
Added: grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.html
===================================================================
--- grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.html (rev 0)
+++ grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.html 2015-08-14 20:40:21 UTC (rev 65935)
@@ -0,0 +1,105 @@
+<h2 id="description">DESCRIPTION</h2>
+<p><em>i.nightlights.intercalibration</em> is a GRASS-GIS module performing inter-satellite calibration on DMSP-OLS nighttime lights time series. Based on "well known" emprirical regression models, it calibrates average visible band Digital Number values.</p>
+<p><strong>Note</strong>, the module is still under testing. Eventually minor, but important, changes might be applied to the intercalibration process.</p>
+<h3 id="overview">Overview</h3>
+<pre><code> +----------------------------------------------------------------------+
+ | |
+ | +-----------------+ |
+ | DN +--> |Calibration Model| +--> Calibrated DN |
+ | +---^-------------+ ^ |
+ | | | |
+ | | +--Evaluation+Methods-------------------+ |
+ | | | | |
+ | | | ? | |
+ | | | | |
+ | | +---------------------------------------+ |
+ | | |
+ | +--Regression+Models-----------------------------------------------+ |
+ | | | |
+ | | Elvidge, 2009/2014: DNc = C0 + C1×DN + C2×DNv2 | |
+ | | | |
+ | | Liu, 2012: based on Elvidge's model + optimal threshold method | |
+ | | | |
+ | | Wu, 2014: DNc + 1 = a×(DN + 1)^b | |
+ | | | |
+ | | Others? | |
+ | | | |
+ | +------------------------------------------------------------------+ |
+ | |
+ +----------------------------------------------------------------------+</code></pre>
+<h3 id="details">Details</h3>
+<p>From a review paper:</p>
+<blockquote>
+<p>"Several methods were proposed to overcome the lack of inter-satellite calibration. These include the invariant region and the quadratic regression method proposed by Elvidge et al. [23], the second-order regression and optimal threshold method proposed by Liu et al. [24], and a power-law regression method proposed by Wu et al. [25]. Although studies based on these calibration methods showed performance improvement after the rectification [24,25], the assumption that the nighttime light remains stableover time in a particular area requires a careful choice of the invariant region manually." [Huang 2014]</p>
+</blockquote>
+<p>References above are: [23]: [Elvidge 2009] [24]: [Liu 2012], [25]: [Wu 2013]</p>
+<h2 id="notes">NOTES</h2>
+<p>?</p>
+<h2 id="examples">EXAMPLES</h2>
+<p>Given all maps are imported in GRASS' data base, which are:</p>
+<div class="code">
+<p>g.list rast pattern=F* sep=,</p>
+<p>F101992,F101993,F101994,F121994,F121995,F121996,F121997,F121998,F121999,F141997, F141998,F141999,F142000,F142001,F142002,F142003,F152000,F152001,F152002,F152003, F152004,F152005,F152006,F152007,F162004,F162005,F162006,F162007,F162008, F162009,F182010,F182011,F182012</p>
+</div>
+<p>the "default" inter-calibration, based on [Elvidge 2014] can be performed as:</p>
+<div class="code">
+<p>i.nightlights.intercalibration.py image=<code>g.list rast pattern=F* sep=,</code> model=wu2013 output=l --o</p>
+</div>
+<h2 id="remarks">Remarks</h2>
+<p>The calibration models do <em>not</em> include regression coefficients for all of the yearly products. In such a case, the module will fail and inform with an error message like:</p>
+<div class="code">
+<p>i.nightlights.intercalibration image=<code>g.list rast pattern=F?????? sep=,</code> model=liu2012 --v</p>
+<p>... ValueError: The selected model does not know about this combination of Satellite + Year!</p>
+</div>
+<h3 id="example-figures">Example figures</h3>
+<div class="figure">
+<p>To add...</p>
+</div>
+<h2 id="todo">TODO</h2>
+<p>in general:</p>
+<ul>
+<li><p>Fix html manual!</p></li>
+<li><p>improve missing key handling and error reporting</p></li>
+<li><p>code deduplication</p></li>
+<li><p>test -- will it compile in other systems?</p></li>
+</ul>
+<p>in <code>i.nightlights.intercalibration.py</code>:</p>
+<ul>
+<li>use <code>*args</code> or <code>**kwargs</code> where appropriate</li>
+</ul>
+<p>in <code>calibration_models.py</code>:</p>
+<ul>
+<li><p>improve checks for missing combinations of Satellite + Year in models</p></li>
+<li><p>separate test_function from this "module"</p></li>
+</ul>
+<p>another module?</p>
+<ul>
+<li>Accuracy assessment of inter-calibrated nighttime lights time series [Wu 2013]: TLI= Σi DNi × Ci where DNi is the grey value of i-level pixels and Ci is the number of i-level pixels</li>
+</ul>
+<h2 id="references">REFERENCES</h2>
+<p>[Review paper(s)]</p>
+<ul>
+<li>Application of DMSP⁄OLS Nighttime Light Images A Meta-Analysis and a Systematic Literature Review [Huang 2014]</li>
+</ul>
+<p>[Empirical second order regression model by Elvidge, 2009 | Y = C0 + C1*X + C2*X^2 ]</p>
+<ul>
+<li><p>Estimating Land Development Time Lags in China Using DMSP⁄OLS Nighttime Light Image [Zhang 2015]</p></li>
+<li><p>National Trends in Satellite-Observed Lighting 1992–2012 [Elvidge 2014]</p></li>
+<li><p>Comparative Estimation of Urban Development in China’s Cities Using socioeconomic and DMSP⁄OLS Night Light Data [Fan 2014]</p></li>
+<li><p>The Integrated Use of DMSP-OLS Nighttime Light and MODIS Data for Monitoring Large-Scale Impervious Surface Dynamics A Case Study in the Yangtze River Delta [Shao & Liu 2014]</p></li>
+<li><p>Characterizing Spatio-Temporal Dynamics of Urbanization in China Using Time Series of DMSP⁄OLS Night Light Data [Xu 2014]</p></li>
+<li><p>Night on Earth Mapping decadal changes of anthropogenic night light in Asia [Small & Elvidge 2013]</p></li>
+</ul>
+<p>[Second order regression model & optimal threshold method by Liu, 2012]</p>
+<ul>
+<li><p>Modeling In-Use Steel Stock in China's Buildings and Civil Engineering Infrastructure Using Time-Series of DMSP⁄OLS Nighttime Lights [Liang 2014]</p></li>
+<li><p>Dynamics of Urbanization Levels in China from 1992 to 2012 Perspective from DMSP⁄OLS Nighttime Light Data] [?]</p></li>
+</ul>
+<p>[Non-linear, power regression model]</p>
+<ul>
+<li>Intercalibration of DMSP-OLS night-time light data by the invariant region method [Wu 2013]</li>
+</ul>
+<h2 id="see-also">SEE ALSO</h2>
+<p>?</p>
+<h2 id="authors">AUTHORS</h2>
+<p>Nikos Alexandris</p>
Added: grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.py
===================================================================
--- grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.py (rev 0)
+++ grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.py 2015-08-14 20:40:21 UTC (rev 65935)
@@ -0,0 +1,525 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+MODULE: i.nightlights.intercalibration
+
+AUTHOR: Nikos Alexandris <nik at nikosalexandris.net> Trikala, March 2015
+
+PURPOSE: Performing inter-satellite calibration on DMSP-OLS Nighttime
+ Lights Time Series (cleaned up average visible band) based on
+ regression models proposed by Elvidge (2009/2014), Liu (2012)
+ and Wu (2013).
+
+ - Elvidge (2009)
+
+ Empirical second order polynomial regression model:
+ DN adj. = C0 + C1 × DN + C2 × DN^2
+
+ where:
+
+ - DN adj.: Adjusted Digital Numbers
+ - DN Raw Digital Number
+ - C0: First polynomial constant
+ - C1: Second polynomial constant
+ - C2: Third polynomial constant
+
+
+ - Elvidge (2014)
+
+ Same model as in 2009, improved coefficients
+
+
+ - Liu (2012)
+
+ Empirical second order polynomial regression model & optimal
+ threshold method: DNc = a * DN^2 + b * DN + c
+
+ where:
+
+ - DNc: Calibrated Digital Number
+ - DN: Raw Digital Number
+ - a: First polynomial constant
+ - b: Second polynomial constant
+ - c: Third polynomial constant
+
+
+ - Wu (2013)
+
+ Power calibration model: DNc + 1 = a * (DN + 1)^b
+
+ where:
+
+ - DNc: Calibrated Digital Number
+ - DN: Raw Digital Number
+ - a: Constant
+ - b: Power
+
+ Overview
+
+ +----------------------------------------------------------------------+
+ | |
+ | +-----------------+ |
+ | DN +--> |Calibration Model| +--> Calibrated DN |
+ | +---^-------------+ ^ |
+ | | | |
+ | | +--Evaluation+Methods-------------------+ |
+ | | | | |
+ | | | ? Not Implemented | |
+ | | | | |
+ | | +---------------------------------------+ |
+ | | |
+ | +--Regression+Models-----------------------------------------------+ |
+ | | | |
+ | | Elvidge, 2009/2014: DNc = C0 + C1×DN + C2×DNv2 | |
+ | | | |
+ | | Liu, 2012: based on Elvidge's model + optimal threshold method | |
+ | | | |
+ | | Wu, 2014: DNc + 1 = a×(DN + 1)^b | |
+ | | | |
+ | | Others? | |
+ | | | |
+ | +------------------------------------------------------------------+ |
+ | http://asciiflow.com |
+ +----------------------------------------------------------------------+
+
+
+ Sources
+
+ - <http://ngdc.noaa.gov/eog/dmsp.html>
+
+ - <http://ngdc.noaa.gov/eog/dmsp/downloadV4composites.html>
+
+ - Metadata on DMSP-OLS:
+ <https://catalog.data.gov/harvest/object/e84ef28f-7935-4ca2-b9c7-7a77cb156c4c/html>
+
+ - From <http://ngdc.noaa.gov/eog/gcv4_readme.txt> on the data
+ this module is meant to process:
+
+ F1?YYYY_v4b_stable_lights.avg_vis.tif: The cleaned up avg_vis
+ contains the lights from cities, towns, and other sites with
+ persistent lighting, including gas flares. Ephemeral events,
+ such as fires have been discarded. Then the background noise
+ was identified and replaced with values of zero. Data values
+ range from 1-63. Areas with zero cloud-free observations are
+ represented by the value 255.
+
+
+ COPYRIGHT: (C) 2014 by the 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.
+"""
+
+#%Module
+#% description: Performs inter-satellite calibration on DMSP-OLS Nighttime Lights Time Series
+#% keywords: imagery
+#% keywords: inter-satellite
+#% keywords: calibration
+#% keywords: nighttime lights
+#% keywords: time series
+#% keywords: DMSP-OLS
+#%End
+
+#%flag
+#% key: i
+#% description: Print out calibration equations
+#%end
+
+#% flag
+#% key: e
+#% description: Evaluation based on the Normalised Difference Index
+#% end
+
+#% flag
+#% key: g
+#% description: Print in shell script style (currently only NDI via -e)
+#% end
+
+#%flag
+#% key: k
+#% description: Keep current computational region settings
+#%end
+
+#%flag
+#% key: z
+#% description: Exclude zero values from the analysis (retain zero cells in output)
+#%end
+
+#%flag
+#% key: n
+#% description: Exclude zero values from the analysis (set zero cells to NULL in output)
+#%end
+
+#%flag
+#% key: t
+#% description: Do not try to transfer timestamps (for input without timestamp)
+#%end
+
+#% rules
+#% exclusive: -z,-n
+#% end
+
+#%option G_OPT_R_INPUTS
+#% key: image
+#% key_desc: name
+#% description: Clean average DMSP-OLS visible band digital number image(s)
+#% required : yes
+#% multiple : yes
+#%end
+
+#%option G_OPT_R_BASENAME_OUTPUT
+#% key: suffix
+#% key_desc: suffix
+#% type: string
+#% label: output file(s) suffix
+#% description: Suffix for calibrated average digital number output image(s)
+#% required: yes
+#% answer: c
+#%end
+
+#%option
+#% key: model
+#% key_desc: author
+#% type: string
+#% label: Calibration model
+#% description: Inter-satellite calibration model for average DMSP-OLS nighttime lights time series
+#% descriptions: Elvidge (2009 or 2014), Liu 2012, Wu 2013
+#% options: elvidge2009,elvidge2014,liu2012,wu2013
+#% required: yes
+#% answer: elvidge2014
+#% guisection: Calibration Model
+#% multiple : no
+#%end
+
+
+# required librairies -------------------------------------------------------
+import os
+import sys
+sys.path.insert(1, os.path.join(os.path.dirname(sys.path[0]),
+ 'etc', 'i.nightlights.intercalibration'))
+
+import atexit
+import grass.script as grass
+from grass.exceptions import CalledModuleError
+from grass.pygrass.modules.shortcuts import general as g
+#from grass.pygrass.modules.shortcuts import raster as r
+#from grass.pygrass.raster.abstract import Info
+
+from intercalibration_models import Elvidge, Liu2012, Wu2013
+
+
+# any constants? -------------------------------------------------------------
+MODELS = {'elvidge': Elvidge, 'liu2012': Liu2012, 'wu2013' : Wu2013}
+
+# helper functions ----------------------------------------------------------
+def cleanup():
+ """
+ Clean up temporary maps
+ """
+ grass.run_command('g.remove', flags='f', type="rast",
+ pattern='tmp.{pid}*'.format(pid=os.getpid()), quiet=True)
+
+def run(cmd, **kwargs):
+ """
+ Pass required arguments to grass commands (?)
+ """
+ grass.run_command(cmd, quiet=True, **kwargs)
+
+#def model_description(model_class):
+# """
+# Model's generic function
+# """
+# return model.equation
+
+def retrieve_model_parameters(model_class, *args, **kwargs):
+ """
+ Run the user-requested calibration model and return model class objects
+ from which the calibration coefficients, the associated RMSE, and the
+ mapcalc formula of interest will be retrieved.
+ """
+ model = model_class(*args, **kwargs)
+ citation = model.citation
+ coefficients = model.coefficients
+ coefficients_r2 = model.report_r2()
+ mapcalc_formula = model.mapcalc
+ return citation, coefficients, coefficients_r2, mapcalc_formula
+
+def total_light_index(ntl_image):
+ """
+ Evaluation index (TLI) which represents the sum of grey values in an area.
+ """
+ univar = grass.parse_command("r.univar",
+ map=ntl_image,
+ flags='g',
+ parse=(grass.parse_key_val,
+ {'sep': '='}))
+ return float(univar['sum'])
+
+def normalised_difference_index(tli_one, tli_two):
+ """
+ Normalised Difference Index based on the total light indices of two
+ satellite images in a certain year.
+ """
+ return abs(tli_one - tli_two) / (tli_one + tli_two)
+
+def main():
+ """
+ Main program: get nameds for input, output suffix, options and flags
+ """
+ input_list = options['image'].split(',')
+ outputsuffix = options['suffix']
+
+ # Select model based on author
+ author_year = options['model']
+ if 'elvidge' in author_year:
+ version = author_year[7:]
+ author_year = 'elvidge'
+ else:
+ version = None
+ Model = MODELS[author_year]
+ # ----------------------------
+
+ # flags
+ info = flags['i']
+ keep_region = flags['k']
+ timestamps = not(flags['t'])
+ zero = flags['z']
+ null = flags['n'] ### either zero or null, not both --- FixMe! ###
+ evaluation = flags['e']
+ shell = flags['g']
+
+ # ----------------------------------------------------------------------
+ # Get working...
+ # ----------------------------------------------------------------------
+ msg = ("|i Inter-satellite calibration of DMSP-OLS Nighttime Stable "
+ "Lights")
+ g.message(msg)
+
+ # -----------------------------------------------------------------------
+ # Temporary Region and Files
+ # -----------------------------------------------------------------------
+
+ if not keep_region:
+ grass.use_temp_region() # to safely modify the region
+ tmpfile = grass.tempfile() # Temporary file - replace with os.getpid?
+ tmp = "tmp." + grass.basename(tmpfile) # use its basename
+
+ # -----------------------------------------------------------------------
+ # Loop over list of input images
+ # -----------------------------------------------------------------------
+
+ for image in input_list:
+
+ satellite = image[0:3]
+ year = image[3:8]
+
+ # -------------------------------------------------------------------
+ # Match region to input image if... ?
+ # -------------------------------------------------------------------
+
+ if not keep_region:
+ run('g.region', rast=image) # ## FixMe?
+ msg = "\n|! Matching region extent to map {name}"
+ msg = msg.format(name=image)
+ g.message(msg)
+
+ elif keep_region:
+ grass.warning(_('Operating on current region'))
+
+ # -------------------------------------------------------------------
+ # Retrieve coefficients
+ # -------------------------------------------------------------------
+
+ msg = "\n|> Calibrating average visible Digital Number values "
+ g.message(msg)
+
+ # if "version" == True use Elvidge, else use Liu2012 or Wu2013
+ args = (satellite, year, version) if version else (satellite, year)
+ model_parameters = retrieve_model_parameters(Model, *args)
+
+# # print model's generic equation?
+# if info:
+# print this
+# print that
+
+
+ # split parameters in usable variables
+ citation, coefficients, r2, mapcalc_formula = model_parameters
+
+ msg = " Regression coefficients: " + str(coefficients) + ' | '
+ msg += r2
+ g.message(msg)
+
+ # Temporary Map
+ tmp_cdn = "{prefix}.Calibrated".format(prefix=tmp)
+
+ # -------------------------------------------------------------------
+ # Formula for mapcalc
+ # -------------------------------------------------------------------
+
+ equation = "{out} = {inputs}"
+ calibration_formula = equation.format(out=tmp_cdn, inputs=mapcalc_formula)
+
+ # alternatives
+ if zero:
+ zcf = "{out} = if(Input == 0, 0, {formula})"
+ calibration_formula = zcf.format(out=tmp_cdn, formula=mapcalc_formula)
+ msg = "\n|i Excluding zero cells from the analysis"
+ g.message(msg)
+
+ elif null:
+ ncf = "{out} = if(Input == 0, null(), {formula})"
+ calibration_formula = ncf.format(out=tmp_cdn, formula=mapcalc_formula)
+ msg = "\n|i Setting zero cells to NULL"
+ g.message(msg)
+
+ # Compress even more? -----------------------------------------------
+# if zero or null:
+# zero = 0 if zero else ('null()')
+# equation = "{out} = if(Input == 0, {zn}, {formula})"
+# calibration_formula = equation.format(out=tmp_cdn, zero, formula=mapcalc_formula)
+ # ----------------------------------------------- Compress even more?
+
+ # replace the "dummy" string...
+ calibration_formula = calibration_formula.replace("Input", image)
+
+ # -------------------------------------------------------------------
+ # Calibrate
+ # -------------------------------------------------------------------
+ if info:
+ print "\n|i Mapcalc formula: ", mapcalc_formula
+
+ grass.mapcalc(calibration_formula, overwrite=True)
+
+ # -------------------------------------------------------------------
+ # Transfer timestamps, if any
+ # -------------------------------------------------------------------
+
+ if timestamps:
+
+ try:
+ datetime = grass.read_command("r.timestamp", map=image)
+ run("r.timestamp", map=tmp_cdn, date=datetime)
+
+ msg = "\n|i Timestamping: {stamp}".format(stamp=datetime)
+ g.message(msg)
+
+ except CalledModuleError:
+ grass.fatal(_('\n|* Timestamp is missing! '
+ 'Please add one to the input map if further times series '
+ 'analysis is important. '
+ 'If you don\'t need it, you may use the -t flag.'))
+
+ else:
+ grass.warning(_('As requested, timestamp transferring not attempted.'))
+
+ # -------------------------------------------------------------------------
+ # add timestamps and register to spatio-temporal raster data set
+ # -------------------------------------------------------------------------
+
+# ToDo -- borrowed from r.sun.daily
+# - change flag for "don't timestamp", see above
+# - use '-t' for temporal, makes more sense
+# - adapt following
+
+ # temporal = flags['t']
+ # if temporal:
+ # core.info(_("Registering created maps into temporal dataset..."))
+ # import grass.temporal as tgis
+
+ # def registerToTemporal(basename, suffixes, mapset, start_day, day_step,
+ # title, desc):
+ # """
+ # Register daily output maps in spatio-temporal raster data set
+ # """
+ # maps = ','.join([basename + suf + '@' + mapset for suf in suffixes])
+ # tgis.open_new_stds(basename, type='strds', temporaltype='relative',
+ # title=title, descr=desc, semantic='sum',
+ # dbif=None, overwrite=grass.overwrite())
+
+ # tgis.register_maps_in_space_time_dataset(type='rast',
+ # name=basename, maps=maps,
+ # start=start_day, end=None,
+ # unit='days',
+ # increment=day_step,
+ # dbif=None, interval=False)
+
+ # -------------------------------------------------------------------
+ # Normalised Difference Index (NDI), if requested
+ # -------------------------------------------------------------------
+
+ ndi = float()
+ if evaluation:
+
+ # total light indices for input, tmp_cdn images
+ tli_image = total_light_index(image)
+ tli_tmp_cdn = total_light_index(tmp_cdn)
+
+ # build
+ ndi = normalised_difference_index(tli_image, tli_tmp_cdn)
+
+ # verbosity
+ msg = '\n|i NDI for {dn}: {index}'.format(dn=image, index=round(ndi, 3))
+ g.message(msg)
+
+ # report if -g
+ if shell:
+ print 'ndi={index}'.format(index=round(ndi,3))
+
+ # else, report
+ else:
+ print '\n|i Normalised Difference Index: {index}'.format(index=round(ndi,3))
+
+ # -------------------------------------------------------------------
+ # Strings for metadata
+ # -------------------------------------------------------------------
+
+ history_calibration = 'Regression model: '
+ history_calibration += mapcalc_formula
+ if ndi:
+ history_calibration += '(NDI: {ndi})'.format(ndi=ndi)
+ title_calibration = 'Calibrated DMSP-OLS Stable Lights'
+ description_calibration = ('Inter-satellite calibrated average '
+ 'Digital Number values')
+ units_calibration = 'Digital Numbers (Calibrated)'
+
+ source1_calibration = citation
+ source2_calibration = ''
+
+ # history entry
+ run("r.support", map=tmp_cdn, title=title_calibration,
+ units=units_calibration, description=description_calibration,
+ source1=source1_calibration, source2=source2_calibration,
+ history=history_calibration)
+
+ # -------------------------------------------------------------------
+ # Add suffix to basename & rename end product
+ # -------------------------------------------------------------------
+ name = "{prefix}.{suffix}"
+ name = name.format(prefix=image.split('@')[0], suffix=outputsuffix)
+ calibrated_name = name
+ run("g.rename", rast=(tmp_cdn, calibrated_name))
+
+ # -------------------------------------------------------------------
+ # Restore region
+ # -------------------------------------------------------------------
+
+ if not keep_region:
+ grass.del_temp_region() # restoring previous region settings
+ g.message("|! Original Region restored")
+
+
+ # -------------------------------------------------------------------
+ # Things left to do... ?
+ # -------------------------------------------------------------------
+
+ # model equations (and citation?)
+ #if info:
+ #print "\n|citation:\n ", citation
+
+if __name__ == "__main__":
+ options, flags = grass.parser()
+ atexit.register(cleanup)
+ sys.exit(main())
Property changes on: grass-addons/grass7/imagery/i.nightlights.intercalibration/i.nightlights.intercalibration.py
___________________________________________________________________
Added: svn:executable
+ *
Added: grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_coefficients.py
===================================================================
--- grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_coefficients.py (rev 0)
+++ grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_coefficients.py 2015-08-14 20:40:21 UTC (rev 65935)
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+"""
+ at author: nik | Created on Wed Feb 25 23:20:05 2015
+
+Regression coefficients derived from models for
+Inter-Satellite Calibration of DMSP-OLS Night-Time Light Time Series
+
+Elvidge 2009, 2014: dn_adjusted = C0 + C1 × dn + C2 × dn^2
+Liu 2012: dn_calibrated = a * dn^2 + b * dn + c
+Wu 2013: dn_calibrated + 1 = a * (dn + 1)^b
+"""
+
+CITATIONS = {
+ 'ELVIDGE2009':
+ ('Elvidge, Christopher D., Daniel Ziskin, '
+ 'Kimberly E. Baugh, Benjamin T. Tuttle, Tilottama Ghosh, Dee W. Pack, '
+ 'Edward H. Erwin, and Mikhail Zhizhin. “A Fifteen Year Record of '
+ 'Global Natural Gas Flaring Derived from Satellite Data.” Energies 2, '
+ 'no. 2 (August 7, 2009): 595–622.'),
+ 'ELVIDGE2014':
+ ('Elvidge, Christopher D., Feng-Chi Hsu, '
+ 'Kimberly E. Baugh, and Tilottama Ghosh. “National Trends in '
+ 'Satellite-Observed Lighting.” Global Urban Monitoring and '
+ 'Assessment Through Earth Observation (2014): 97.'),
+ 'LIU2012':
+ ('Liu, Zhifeng, Chunyang He, Qiaofeng Zhang, '
+ 'Qingxu Huang, and Yang Yang. '
+ '"Extracting the Dynamics of Urban Expansion in China Using DMSP-OLS '
+ 'Nighttime Light Data from 1992 to 2008." '
+ 'Landscape and Urban Planning 106, no. 1 (May 2012): 62-72.'),
+ 'WU2013':
+ ('Jiansheng Wu, Shengbin He, Jian Peng, Weifeng Li '
+ '& Xiaohong Zhong (2013). '
+ 'Intercalibration of DMSP-OLS night-time light data by the invariant '
+ 'region method, International Journal of Remote Sensing, 34:20, '
+ '7356-7368. DOI:10.1080/01431161.2013.820365')}
+
+COEFFICIENTS = {
+ 'ELVIDGE2009': {'F12': {'1994': (0.1651, 1.1244, -0.0018, 0.915),
+ '1995': (0.4103, 1.2116, -0.0035, 0.937),
+ '1996': (0.2228, 1.27, -0.004, 0.944),
+ '1997': (-0.0008, 1.1651, -0.0023, 0.945),
+ '1998': (0.1535, 1.0451, -0.0009, 0.956),
+ '1999': (0.0, 1.0, 0.0, 1.0)},
+ 'F14': {'1997': (0.0291, 1.6568, -0.0103, 0.941),
+ '1998': (0.1831, 1.598, -0.0096, 0.972),
+ '1999': (-0.1674, 1.5116, -0.0078, 0.971),
+ '2000': (0.1061, 1.3877, -0.0059, 0.972),
+ '2001': (-0.2595, 1.3467, -0.0053, 0.963),
+ '2002': (0.4486, 1.1983, -0.0035, 0.927),
+ '2003': (-0.2768, 1.2838, -0.0044, 0.938)},
+ 'F15': {'2000': (0.1029, 1.0845, -0.001, 0.97),
+ '2001': (-0.4365, 1.085, -0.0009, -0.959),
+ '2002': (-0.2173, 0.9715, 0.0008, 0.966),
+ '2003': (-0.2244, 1.5238, -0.0079, 0.936),
+ '2004': (-0.3657, 1.3772, -0.0056, 0.948),
+ '2005': (-0.6201, 1.3504, -0.0049, 0.934),
+ '2006': (-0.6005, 1.3551, -0.0049, 0.939),
+ '2007': (-0.1615, 1.396, -0.0054, 0.947),
+ '2008': (0.5031, 0.937, 0.0004, 0.92)},
+ 'F16': {'2004': (-0.4436, 1.2081, -0.003, 0.95),
+ '2005': (-0.2375, 1.4249, -0.0063, 0.937),
+ '2006': (0.0287, 1.1338, -0.0013, 0.938),
+ '2007': (0.321, 0.9216, 0.0013, 0.949),
+ '2008': (-0.1203, 1.0155, -0.0001, 0.946)}},
+ 'ELVIDGE2014': {'F10': {'1992': (-2.057, 1.5903, -0.009, 0.9075),
+ '1993': (-1.0582, 1.5983, -0.0093, 0.936),
+ '1994': (-0.3458, 1.4864, -0.0079, 0.9243)},
+ 'F12': {'1994': (-0.689, 1.177, -0.0025, 0.9071),
+ '1995': (-0.0515, 1.2293, -0.0038, 0.9178),
+ '1996': (-0.0959, 1.2727, -0.004, 0.9319),
+ '1997': (-0.3321, 1.1782, -0.0026, 0.9245),
+ '1998': (-0.0608, 1.0648, -0.0013, 0.9536),
+ '1999': (0.0, 1.0, 0.0, 1.0)},
+ 'F14': {'1997': (-1.1323, 1.7696, -0.0122, 0.9101),
+ '1998': (-0.1917, 1.6321, -0.0101, 0.9723),
+ '1999': (-0.1557, 1.5055, -0.0078, 0.9717),
+ '2000': (1.0988, 1.3155, -0.0053, 0.9278),
+ '2001': (0.1943, 1.3219, -0.0051, 0.9448),
+ '2002': (1.0517, 1.1905, -0.0036, 0.9203),
+ '2003': (0.739, 1.2416, -0.004, 0.9432)},
+ 'F15': {'2000': (0.1254, 1.0452, -0.001, 0.932),
+ '2001': (-0.7024, 1.1081, -0.0012, 0.9593),
+ '2002': (0.0491, 0.9568, 0.001, 0.9658),
+ '2003': (0.2217, 1.5122, -0.008, 0.9314),
+ '2004': (0.5751, 1.3335, -0.0051, 0.9479),
+ '2005': (0.6367, 1.2838, -0.0041, 0.9335),
+ '2006': (0.8261, 1.279, -0.0041, 0.9387),
+ '2007': (1.3606, 1.2974, -0.0045, 0.9013)},
+ 'F16': {'2004': (0.2853, 1.1955, -0.0034, 0.9039),
+ '2005': (-0.0001, 1.4159, -0.0063, 0.939),
+ '2006': (0.1065, 1.1371, -0.0016, 0.9199),
+ '2007': (0.6394, 0.9114, 0.0014, 0.9511),
+ '2008': (0.5564, 0.9931, 0.0, 0.945),
+ '2009': (0.9492, 1.0683, -0.0016, 0.8918),
+ '2010': (2.343, 0.5102, 0.0065, 0.8462),
+ '2011': (1.8956, 0.7345, 0.003, 0.9095),
+ '2012': (1.875, 0.6203, 0.0052, 0.9392)},
+ 'F18': {'2004': (0.2853, 1.1955, -0.0034, 0.9039),
+ '2005': (-0.0001, 1.4159, -0.0063, 0.939),
+ '2006': (0.1065, 1.1371, -0.0016, 0.9199),
+ '2007': (0.6394, 0.9114, 0.0014, 0.9511),
+ '2008': (0.5564, 0.9931, 0.0, 0.945),
+ '2009': (0.9492, 1.0683, -0.0016, 0.8918),
+ '2010': (2.343, 0.5102, 0.0065, 0.8462),
+ '2011': (1.8956, 0.7345, 0.003, 0.9095),
+ '2012': (1.875, 0.6203, 0.0052, 0.9392)}},
+ 'LIU2012': {'F10': {'1992': (0.0029, 0.9699, -0.4454, 0.899),
+ '1993': (0.003, 1.0904, -0.5829, 0.9027),
+ '1994': (0.0056, 0.9038, -0.0699, 0.885)},
+ 'F12': {'1994': (0.0028, 1.0569, -0.4794, 0.8984),
+ '1995': (0.0088, 0.5959, 1.6317, 0.8623),
+ '1996': (0.0097, 0.5674, 1.5939, 0.8319),
+ '1997': (0.0092, 0.4851, 1.9491, 0.8386),
+ '1998': (0.0105, 0.3659, 2.3604, 0.8429),
+ '1999': (0.009, 0.5033, 2.1102, 0.9119)},
+ 'F14': {'1997': (0.0015, 1.0296, 0.7414, 0.8318),
+ '1998': (0.0056, 0.8389, 0.7931, 0.8584),
+ '1999': (0.001, 1.0659, 0.7002, 0.9186),
+ '2000': (0.0057, 0.7197, 1.3015, 0.9325),
+ '2001': (0.0012, 0.9877, 0.2367, 0.9576),
+ '2002': (-0.003, 1.1597, 0.4874, 0.899),
+ '2003': (-0.0083, 1.5049, -0.5827, 0.9629)},
+ 'F15': {'2000': (0.0085, 0.503, 2.1202, 0.8845),
+ '2001': (0.0019, 0.9849, -0.4446, 0.9166),
+ '2002': (0.0009, 0.9596, -0.5467, 0.9632),
+ '2003': (-0.0125, 1.7694, -0.9178, 0.9221),
+ '2004': (-0.0074, 1.4864, 0.1417, 0.9643),
+ '2005': (-0.0041, 1.3075, 0.3526, 0.9212),
+ '2006': (-0.0049, 1.315, 0.8122, 0.9674),
+ '2007': (-0.004, 1.2713, 0.4571, 0.977),
+ '2008': (0.0016, 0.8727, 0.2472, 0.9487)},
+ 'F16': {'2004': (-0.0005, 1.071, 0.2026, 0.9263),
+ '2005': (-0.0032, 1.2913, -0.5429, 0.9649),
+ '2006': (-0.0048, 1.2948, 0.0273, 0.9717),
+ '2007': (0.0, 1.0, 0.0, 1.0),
+ '2008': (0.0014, 0.9151, 0.7329, 0.9864)}},
+ 'WU2013': {'F10': {'1992': (0.8959, 1.031, 0.9492),
+ '1993': (0.6821, 1.1181, 0.8731),
+ '1994': (0.9127, 1.064, 0.9112)},
+ 'F12': {'1994': (0.4225, 1.3025, 0.8559),
+ '1995': (0.3413, 1.3604, 0.9275),
+ '1996': (0.9247, 1.0576, 0.9541),
+ '1997': (0.3912, 1.3182, 0.9042),
+ '1998': (0.9734, 1.0312, 0.9125),
+ '1999': (1.2743, 0.9539, 0.8846)},
+ 'F14': {'1997': (1.3041, 0.9986, 0.8945),
+ '1998': (0.9824, 1.107, 0.9589),
+ '1999': (1.0347, 1.0904, 0.9479),
+ '2000': (0.9885, 1.0702, 0.9047),
+ '2001': (0.9282, 1.0928, 0.9706),
+ '2002': (0.9748, 1.0857, 0.9752),
+ '2003': (0.9144, 1.1062, 0.9156)},
+ 'F15': {'2000': (0.8028, 1.0855, 0.9242),
+ '2001': (0.8678, 1.0646, 0.87),
+ '2002': (0.7706, 1.092, 0.8854),
+ '2003': (0.9852, 1.1141, 0.9544),
+ '2004': (0.864, 1.1671, 0.9352),
+ '2005': (0.5918, 1.2894, 0.9322),
+ '2006': (0.9926, 1.1226, 0.9145),
+ '2007': (1.1823, 1.085, 0.9041)},
+ 'F16': {'2004': (0.7638, 1.1507, 0.9123),
+ '2005': (0.6984, 1.2292, 0.862),
+ '2006': (0.9028, 1.1306, 0.9412),
+ '2007': (0.8864, 1.1112, 0.9576),
+ '2008': (0.9971, 1.0977, 0.9653),
+ '2009': (1.4637, 0.9858, 0.8735),
+ '2010': (0.8114, 1.0849, 0.9542)},
+ 'F18': {'2004': (0.7638, 1.1507, 0.9123),
+ '2005': (0.6984, 1.2292, 0.862),
+ '2006': (0.9028, 1.1306, 0.9412),
+ '2007': (0.8864, 1.1112, 0.9576),
+ '2008': (0.9971, 1.0977, 0.9653),
+ '2009': (1.4637, 0.9858, 0.8735),
+ '2010': (0.8114, 1.0849, 0.9542)}}
+}
+
+# reusable & stand-alone
+if __name__ == "__main__":
+ print ('Citations and coefficients for inter-satellite DMSP-OLS NightTime '
+ 'Lights Time Series calibration models')
+ print CITATIONS
Added: grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_equations.py
===================================================================
--- grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_equations.py (rev 0)
+++ grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_equations.py 2015-08-14 20:40:21 UTC (rev 65935)
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+"""
+Convert (and export -- needs uncommenting!) intercalibration equations
+(strings), sourced in form of csv, to human readable string representations
+(__str__ method of a model's class) and r.mapcalc compatible expressions.
+
+ at author: nik | Created on Wed Mar 11 18:34:03 2015
+"""
+
+import os
+import StringIO
+import csv
+import collections
+
+csvstring = """csvauthor|model|formula
+ELVIDGE2009|DNadj. = ({c0}) + ({c1}) * DN + ({c2}) * DN^2|({c0}) +({c1})*{dummy} + ({c2})*{dummy}^2
+ELVIDGE2014|DNadj. = ({c0}) + ({c1}) * DN + ({c2}) * DN^2|({c0}) +({c1})*{dummy} + ({c2})*{dummy}^2
+LIU2012|DNadj. = {c0} + {c1} * DN + {c2} * DN^2|({c0}) + ({c1})*{dummy} +({c2})*{dummy}^2
+WU2013|DNc + 1 = {a} * (DNm + 1)^{b}|({a}) * ({dummy} + 1)^({b})"""
+
+# fake it...
+csvfile = StringIO.StringIO(csvstring)
+
+
+def csv_to_dictionary(csvfile):
+ """
+ """
+ equations = {} # empty dictionary
+ #csvFile = open(csvfile, 'rb')
+ csvReader = csv.reader(csvfile, delimiter='|')
+
+ rows = []
+ fields = []
+ for row in csvReader:
+ rows.append(row)
+ fields = rows.pop(0)[1:] # header
+
+ def transform(row):
+ """
+ """
+ author = row[0].replace(" ", "_") # key: class name, replace ''w/ _
+
+ # namedtuple
+ strings = collections.namedtuple(author, [fields[0], fields[1]])
+
+ # feed namedtuples
+ strings.model, strings.formula = (str(row[1]), str(row[2]))
+
+ # feed EQUATION
+ equations[author] = equations.get(author, strings)
+
+ # apply helper function to all rows
+ map(transform, rows)
+
+ # return requestred dictionary
+ return equations
+
+
+def export_to_ascii(dictionary, filename, separator):
+ """
+ Exporting ... to an ASCII file
+ """
+
+ # convert dictionary to string
+ dictionary = str(dictionary)
+
+ # define filename
+ filename += '.py'
+
+ # don't overwrite!
+ if not os.path.exists(filename):
+
+ # structure informative message
+ msg = '> Exporting python dictionary as is...'
+ print msg
+
+ # open, write and close file
+ asciif = open(filename, 'w')
+ asciif.write(dictionary)
+ asciif.close()
+
+ else:
+ print '{f} already exists!'.format(f=filename)
+
+
+def main():
+ """
+ Execute main program. Note, filename is hardcoded!
+ """
+ # csvfile = 'equations.csv'
+ dictionary = csv_to_dictionary(csvfile)
+ # print dictionary
+
+ # uncomment to export, hardcoded filename
+ # doesn't make sense with named tuples though!
+ # asciifile = 'intercalibration_equations.ascii'
+ # export_to_ascii(dictionary, asciifile, # separator='|')
+ return dictionary
+
+
+if __name__ == "__main__":
+ main()
Added: grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_models.py
===================================================================
--- grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_models.py (rev 0)
+++ grass-addons/grass7/imagery/i.nightlights.intercalibration/intercalibration_models.py 2015-08-14 20:40:21 UTC (rev 65935)
@@ -0,0 +1,357 @@
+# -*- coding: utf-8 -*-
+"""
+Unified class for DMSP-OLS Inter-Satellite Calibration Model
+ at author: nik | Created on Wed Mar 11 18:07:20 2015
+"""
+
+from intercalibration_coefficients import CITATIONS, COEFFICIENTS
+import intercalibration_equations
+
+# globals
+DUMMY_MAPCALC_STRING = 'Input'
+EQUATIONS = intercalibration_equations.main()
+
+
+class CalibrationModel:
+ """
+ Common attributes for all models:
+
+ # author: Note, Elvidge's two models require a "version"
+ to select which coefficients to use?
+
+ # citation: based on author, hardcoded for each Sub-Class,
+ use a _citation method
+
+ # satellite year coefficients: a tuple (pair or triplet, so far) mapcalc
+ """
+ def __init__(self, author, satellite, year):
+ """
+ Create object for the calibration model
+ """
+ # set key for MODEL, MAPCALC, COEFFICIENTS, CITATIONS
+ self.author = str(author)
+
+ # get/set input
+ self.satellite = satellite
+ self.year = str(year)
+
+ # set citation
+ self.citation = CITATIONS[self.author]
+
+ # check...
+ self.verify_year(author=self.author, satellite=self.satellite,
+ year=self.year)
+
+ # load coefficients and R^2 in tuple, float
+ self.set_coefficients()
+ self.set_r2()
+
+ # build euqations for model (string) and r.mapcalc
+ self.build_model()
+ self._mapcalc()
+
+ def __str__(self):
+ msg = 'Calibration model by ... : '
+ msg += '...mode...\n'
+ return msg + ' ' + self._model + '\n'
+
+ def verify_year(self, author, satellite, year):
+ """
+ Check if coefficients exist for requested year, satellite, author
+ """
+ # retrieve years from COEFFICIENTS dictionary
+ available_years = COEFFICIENTS[author][satellite].keys()
+
+ # does the requested year exist?
+ if year not in available_years:
+ raise ValueError('The selected model does not know about '
+ 'this combination of Satellite + Year!')
+ else:
+ return True
+
+ def set_coefficients(self):
+ """
+ Set the model's coefficients for the requested satellite and year
+ """
+ self.a = COEFFICIENTS[self.author][self.satellite][self.year][0]
+ self.b = COEFFICIENTS[self.author][self.satellite][self.year][1]
+ self.coefficients = (self.a, self.b)
+
+ def get_coefficients(self):
+ """
+ Return the model's coefficients for the requested satellite and year
+ """
+ return (self.a, self.b)
+
+ def set_r2(self):
+ """
+ Set the R^2 statistic for the requested coefficients
+ """
+ self.r2 = COEFFICIENTS[self.author][self.satellite][self.year][2]
+
+ def report_r2(self):
+ """
+ Report the associated R^2 value for the coefficients in question
+ """
+ msg = "Associated R^2: "
+ return msg + str(self.r2)
+
+ def is_dn_valid(self, dn):
+ """
+ Control whether the given DN is valid
+ """
+ if type(dn) != int:
+ raise ValueError('The provided Digital Number value is NOT an '
+ 'integer!')
+
+ if 0 > dn or dn > 63:
+ raise ValueError('The provided Digital Number value is out of the '
+ 'expected range [0,63]')
+ else:
+ return True
+
+ def build_model(self):
+ pass
+
+ # def calibrate(self, dn):
+ # """
+ # Calibrate a clean average visible band Digital Number value
+ # """
+ # model = EQUATIONS[self.author].model # read equations.py
+
+ # def _mapcalc(self):
+ # """
+ # Retrieve the model's formula for r.mapcalc
+ # """
+ # formula = EQUATIONS[self.author].formula # read euqations.py
+
+ def get_mapcalc(self):
+ return self.mapcalc
+
+class Elvidge(CalibrationModel):
+ """
+ Empirical second order, DMSP-OLS inter-satellite, calibration model
+ proposed by Elvidge, 2009 or Elvidge, 2014.
+ DN adj. = C0 + C1×DN + C2×DN^2
+ """
+ def __init__(self, satellite, year, version):
+ """
+ Create object for the polynomial calibration model
+ proposed by Elvidge 2009/2014
+ """
+ # set key for MODEL, MAPCALC, COEFFICIENTS, CITATIONS
+ author = str('ELVIDGE')
+
+ # which version of Elvidge's model?
+ if not version:
+ self.version = '2014' # alternative coefficients: Elvidge 2009
+ else:
+ self.version = version
+
+ # set key for COEFFICIENTS
+ author += str(self.version)
+
+ # initialise object attributes from the Super-Class
+ CalibrationModel.__init__(self, author, satellite, year)
+
+ def _citation(self):
+ if self.version == '2014':
+ self.citation = self._citation_2014
+ elif self.version == '2009':
+ self.citation = self._citation_2009
+
+ def __str__(self):
+ """
+ Return a string representation of the calibration model
+ """
+ msg = 'Calibration model proposed by Elvidge, '
+ msg += str(self.version) + '\n '
+ msg += '[DN adj. = C0 + C1*DN + C2*DN^2]\n'
+ return msg + ' ' + self._model + '\n'
+
+ def set_coefficients(self):
+ """
+ Set coefficients
+ """
+ self.c0 = COEFFICIENTS[self.author][self.satellite][self.year][0]
+ self.c1 = COEFFICIENTS[self.author][self.satellite][self.year][1]
+ self.c2 = COEFFICIENTS[self.author][self.satellite][self.year][2]
+ self.coefficients = (self.c0, self.c1, self.c2)
+
+ def get_coefficients(self):
+ """
+ Triplet tuple
+ """
+ return (self.c0, self.c1, self.c2)
+
+ def set_r2(self):
+ """
+ set R^2
+ """
+ self.r2 = COEFFICIENTS[self.author][self.satellite][self.year][3]
+
+ def build_model(self):
+ """
+ Build model equation, first to serve __str__
+ """
+ # model = 'DNadj. = ({c0}) + ({c1}) * DN + ({c2}) * DN^2'
+ model = EQUATIONS[self.author].model
+ self._model = model.format(c0=self.c0, c1=self.c1, c2=self.c2)
+
+ def calibrate(self, dn):
+ """
+ Calibrate DMSP-OLS NightTime Lights average visible band Digital
+ Number values based on Elvidge's calibration polynomial model and
+ build a calibration equation for the requested satellite and year.
+ """
+ if self.is_dn_valid(dn):
+ cdn = self.c0 + (self.c1 * dn) + (self.c2 * (dn**2))
+ model = EQUATIONS[self.author].model # look in equations.py
+ self._model = model.format(dn=dn, cdn=cdn, c0=self.c0,
+ c1=self.c1, c2=self.c2)
+ return cdn
+
+ def _mapcalc(self):
+ """
+ Return equation for GRASS GIS' mapcalc
+ """
+ # formula = '{c0} + {c1}*{dummy} + {c2}*{dummy}^2'
+ formula = EQUATIONS[self.author].formula # look in equations.py
+ self.mapcalc = formula.format(c0=self.c0, c1=self.c1,
+ dummy=DUMMY_MAPCALC_STRING, c2=self.c2)
+
+
+class Liu2012(CalibrationModel):
+ """
+ Empirical second order calibration model (& optimal threshold method)
+ proposed by Liu, 2012. DNc = a * DN^2 + b * DN + c, where:
+ - DNc:
+ - DN:
+ - a:
+ - b:
+ - c:
+ """
+ def __init__(self, satellite, year):
+ """
+ Create object for the polynomial calibration model
+ proposed by Elvidge 2009/2014
+ """
+ # set key for MODEL, MAPCALC, COEFFICIENTS, CITATIONS
+ author = str('LIU2012')
+
+ # initialise object attributes from the Super-Class
+ CalibrationModel.__init__(self, author, satellite, year)
+
+ def __str__(self):
+ """
+ Return a string representation of the calibration model
+ """
+ msg = 'Calibration model by Liu, 2012: '
+ msg += 'DNc = a * DN^2 + b * DN + c\n'
+ return msg + ' ' + self._model + '\n'
+
+ def set_coefficients(self):
+ """
+ set coefficients
+ """
+ self.c0 = COEFFICIENTS[self.author][self.satellite][self.year][0]
+ self.c1 = COEFFICIENTS[self.author][self.satellite][self.year][1]
+ self.c2 = COEFFICIENTS[self.author][self.satellite][self.year][2]
+ self.coefficients = (self.c0, self.c1, self.c2)
+
+ def get_coefficients(self):
+ """
+ # triplet tuple
+ """
+ return (self.c0, self.c1, self.c2)
+
+ def set_r2(self):
+ """
+ set R^2
+ """
+ self.r2 = COEFFICIENTS[self.author][self.satellite][self.year][3]
+
+ def build_model(self):
+ # model = 'DNadj. = {c0} + {c1} * DN + {c2} * DN^2'
+ model = EQUATIONS[self.author].model
+ self._model = model.format(c0=self.c0, c1=self.c1, c2=self.c2)
+
+ def calibrate(self, dn):
+ """
+ Calibrate DMSP-OLS NightTime Lights average visible band Digital
+ Number values based on Elvidge's calibration polynomial model and
+ build a calibration equation for the requested satellite and year.
+ """
+ if self.is_dn_valid(dn):
+ cdn = self.c0 + (self.c1 * dn) + (self.c2 * (dn**2))
+
+ # Update _model as well!
+ model = '{cdn} = ({c0}) + ({c1}) * {dn} + ({c2}) * {dn}^2'
+ self._model = model.format(dn=dn, cdn=cdn, c0=self.c0,
+ c1=self.c1, c2=self.c2)
+ return cdn
+
+ def _mapcalc(self):
+ """
+ Return equation for GRASS GIS' mapcalc
+ """
+ formula = EQUATIONS[self.author].formula
+ print "FORMULA: ", formula
+ self.mapcalc = formula.format(c0=self.c0, c1=self.c1,
+ dummy=DUMMY_MAPCALC_STRING, c2=self.c2)
+
+
+class Wu2013(CalibrationModel):
+ """
+ Power calibration model proposed by Wu 2013.
+ DNc + 1 = a * (DN + 1)^b
+ Subclass, inheriting from CalibrationModel
+ """
+
+ def __init__(self, satellite, year):
+ """
+ Create object for the power calibration model
+ proposed by Wu, 2013
+ """
+ author = str('WU2013')
+
+ # initialise object attributes from the Super-Class
+ CalibrationModel.__init__(self, author, satellite, year)
+
+ def __str__(self):
+ """
+ """
+ msg = 'Calibration model by Wu, 2013: '
+ msg += 'DNc + 1 = a * (DN + 1)^b\n'
+ return msg + ' ' + self._model + '\n'
+
+ def build_model(self):
+ """
+ """
+ model = EQUATIONS[self.author].model
+ self._model = model.format(a=self.a, b=self.b)
+
+ def calibrate(self, dn):
+ """
+ Calibrate a clean average visible band Digital Number value
+ """
+ cdn = self.a * (dn + 1)**self.b
+
+ # Update _model as well!
+ model = '{cdn} = {a} * ({dn} + 1)^{b})'
+ self._model = model.format(dn=dn, cdn=cdn, a=self.a,
+ b=self.b)
+ return cdn
+
+ def _mapcalc(self):
+ """
+ """
+ formula = EQUATIONS[self.author].formula
+ self.mapcalc = formula.format(a=self.a, dummy=DUMMY_MAPCALC_STRING,
+ b=self.b)
+
+
+# reusable & stand-alone
+if __name__ == "__main__":
+ print ('Calibration models for DMSP-OLS NightTime Lights Time Series'
+ ' (Running as stand-alone tool?)\n')
Added: grass-addons/grass7/imagery/i.nightlights.intercalibration/test_intercalibration_models.py
===================================================================
--- grass-addons/grass7/imagery/i.nightlights.intercalibration/test_intercalibration_models.py (rev 0)
+++ grass-addons/grass7/imagery/i.nightlights.intercalibration/test_intercalibration_models.py 2015-08-14 20:40:21 UTC (rev 65935)
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+"""
+Functions to test Python classes for inter-satellite calibration of nighttime
+lights time series.
+
+ at author = nik
+"""
+
+# required librairies
+import random
+from intercalibration_coefficients import COEFFICIENTS
+from intercalibration_models import Elvidge, Liu2012, Wu2013
+
+# helper functions
+def random_digital_numbers(count=3):
+ """
+ Return a user-requested amount of random Digital Number values for testing
+ purposes
+ """
+ digital_numbers = []
+
+ for dn in range(0, count):
+ digital_numbers.append(random.randint(0, 63))
+
+ return digital_numbers
+
+
+def random_digital_number():
+ """
+ Return one random of Digital Number values for testing purposes
+ """
+ return random.randint(0, 63)
+
+
+def calibrate_digital_number(dn, c0, c1, c2):
+ """
+ Calibrate a "raw" digital number based on Elvidge's calibration
+ polynomial model
+ """
+ if type(dn) != int:
+ raise ValueError('The provided Digital Number value is NOT an '
+ 'integer!')
+
+ if 0 > dn or dn > 63:
+ raise ValueError('The provided Digital Number value is out of the '
+ 'expected range [0, 63]')
+
+ return c0 + (c1 * dn) + (c2 * (dn**2))
+
+
+def test_model(author):
+ """
+ Testing the "?" model
+ """
+ print ">>> Testing -----------------------------------------------------\n"
+
+ # -----------------------------------------------------------------------
+ # set required values
+ print " >> Pre-Setting (randomely) required values for testing purposes:"
+ print " * Assigning author and model version...",
+ version = ''
+ if not author:
+ version = random.choice(['2009', '2014'])
+ author = 'ELVIDGE' + str(version)
+ else:
+ version = author[7:]
+
+ print author
+
+ print " * Assigning a random satellite...",
+ satellite = random.choice(COEFFICIENTS[author].keys())
+ print satellite
+
+ print " * Assiging a random year...",
+ year = random.choice(COEFFICIENTS[author][satellite].keys())
+ print year
+
+ print " * Assiging a random c0 coefficient...",
+ c0 = COEFFICIENTS[author][satellite][year][0]
+ print " Random coefficient c0: ", c0
+
+ print " * Assiging a random c1 coefficient...",
+ c1 = COEFFICIENTS[author][satellite][year][1]
+ print " Random coefficient c1: ", c1
+
+ c2 = float()
+ if 'WU' not in author:
+ print " * Assiging a random c2 coefficient..."
+ c2 = COEFFICIENTS[author][satellite][year][2]
+ print " Random coefficient c2: ", c2
+
+# R2 = coefficients[author][satellite][year][3]
+# print " Associated R^2 value: ", R2
+ print
+
+ # -----------------------------------------------------------------------
+ print " >> Testing ? class:"
+ print
+ print (' [ Usage: ?(satellite, year, model version)\n\n'
+ ' where: DN: input Digital Number value (integer)\n'
+ ' Coefficients: a pair or triplet of floating point '
+
+ 'values (tuple)\n\n'
+ ' eg: ? = Liu2012(F10, 1992, 2009) ]')
+ print
+ if 'ELVIDGE' in author:
+ test_model = Elvidge(satellite, year, version)
+ elif 'LIU' in author:
+ test_model = Liu2012(satellite, year)
+ elif 'WU' in author:
+ test_model = Wu2013(satellite, year)
+
+ print " * Testing 'citation' method:\n\n", test_model.citation
+ print
+ print " * Testing '__str__' of class:\n\n ", test_model
+ print " * Testing 'satellite': ", test_model.satellite
+ print " * Testing 'year': ", test_model.year
+ print " * Testing 'veify_year': ", test_model.verify_year(author,
+ satellite, year)
+ print " * Testing 'coefficients': ", test_model.coefficients
+ print " * Testing 'r2': ", test_model.r2
+ print " * Testing 'report_r2' method: ", test_model.report_r2()
+ dn = random_digital_number()
+ print " > A random digital number: ", dn
+ print " * Testing 'is_dn_valid': ", test_model.is_dn_valid(dn)
+ print " * Testing 'calibrate' method: ", test_model.calibrate(dn)
+ print " * Testing '_model' (hidden): ", test_model._model
+ print " * Testing 'mapcalc': ", test_model.mapcalc
+ print " * Testing 'get_mapcalc': ", test_model.get_mapcalc()
+ print
+
+ # -----------------------------------------------------------------------
+ print " >> Testing helper functions: "
+ dn = random_digital_number()
+ print (" * Testing 'random_digital_number()' method (and type()): ",
+ dn, "|", type(dn))
+ print (" * Testing 'calibrate_digital_number' method: ",
+ calibrate_digital_number(dn, c0, c1, c2))
+ print
+
+ # -----------------------------------------------------------------------
+ print " * Testing three random Digital number values:\n"
+ for dn in random_digital_numbers(3):
+ print " (Random) DN: ", dn
+ print " Coefficients: ", test_model.coefficients
+ print " Model: ", test_model.calibrate(dn), "\n"
+
+
+# reusable & stand-alone
+if __name__ == "__main__":
+ print ('Testing classes for calibration models for DMSP-OLS NightTime '
+ 'Lights Time Series')
+ print
+
+ # uncomment to test
+ test_model('ELVIDGE2009')
+ test_model('ELVIDGE2014')
+ test_model('LIU2012')
+ test_model('WU2013')
+
Modified: grass-addons/grass7/imagery/i.segment.hierarchical/Makefile
===================================================================
--- grass-addons/grass7/imagery/i.segment.hierarchical/Makefile 2015-08-14 16:14:42 UTC (rev 65934)
+++ grass-addons/grass7/imagery/i.segment.hierarchical/Makefile 2015-08-14 20:40:21 UTC (rev 65935)
@@ -2,19 +2,9 @@
PGM = i.segment.hierarchical
+ETCFILES = isegpatch
+
include $(MODULE_TOPDIR)/include/Make/Script.make
include $(MODULE_TOPDIR)/include/Make/Python.make
-MODULES = isegpatch
-
-ETCDIR = $(ETC)/i.segment.hierarchical
-
-PYFILES := $(patsubst %,$(ETCDIR)/%.py,$(MODULES))
-
-default: script $(PYFILES)
-
-$(ETCDIR):
- $(MKDIR) $@
-
-$(ETCDIR)/%: % | $(ETCDIR)
- $(INSTALL_DATA) $< $@
+default: script
More information about the grass-commit
mailing list