[GRASS-SVN] r68479 - grass-addons/grass7/imagery/i.landsat8.qc

svn_grass at osgeo.org svn_grass at osgeo.org
Fri May 20 14:01:30 PDT 2016


Author: sbl
Date: 2016-05-20 14:01:30 -0700 (Fri, 20 May 2016)
New Revision: 68479

Modified:
   grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.html
   grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.py
Log:
i.landsat8.qc: reworked

Modified: grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.html
===================================================================
--- grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.html	2016-05-20 20:42:57 UTC (rev 68478)
+++ grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.html	2016-05-20 21:01:30 UTC (rev 68479)
@@ -1,15 +1,16 @@
 <h2>DESCRIPTION</h2>
 
-<p>Removing unreliable pixels is a fundamental and one of the first steps in 
+Removing unreliable pixels is a fundamental and one of the first steps in 
 remote sensing. Landsat8 provides a Quality Assessment (QA) band which can be 
-used for this purpose.</p>
+used for this purpose.
 
-<p>The <em>i.landsat8.qc</em> module filters (reclasifies) the QA band according 
-to pixel quality characteristics the user defines as unacceptable.</p>
+<p>The <em>i.landsat8.qc</em> module generates reclassification rule files which
+ can be used in <a href="r.reclass.html">r.reclass</a> for filtering the 
+ QA band according to pixel quality characteristics the user defines as 
+ unacceptable.</p>
 
 <p>Values defined as unacceptable for a given condition will be set to NULL
-in the output raster map. All other values will be set to 1. The <em>i</em>-
-flag inverts this behavior.</p>
+in the output raster map. All other values will be set to 1.</p>
 
 <p>The Quality Assessment (QA) band from Landsat8 contains 16bit integer 
 values that represent "bit-packed combinations of surface, atmosphere, and 
@@ -20,7 +21,7 @@
 <p>The following quality relevant conditions are represented as "single bits" 
 in the Landsat8 QA band:</p>
 
-<table border="1" padding="0" spacing="1" style="width:300px;">
+<table border="1" padding="0" spacing="1">
   <tr>
     <td>Condition</td>
     <td>QA Bit Position</td>
@@ -45,7 +46,7 @@
 
 <p>Possible choices for the "single bits" are:</p>
 
-<table border="1" padding="0" spacing="1" style="width:300px;">
+<table border="1" padding="0" spacing="1">
   <tr>
     <td>Value</td>
 	<td>Description</td>
@@ -66,30 +67,30 @@
 <p>The following quality relevant conditions are represented as "double bits" 
 in the Landsat8 QA band:</p>
 
-<table>
+<table border="1" padding="0" spacing="1">
   <tr>
-    <td>QA Bit</td>
-    <td>Description Confidence</td>
+    <td>Condition</td>
+    <td>QA Bit Position</td>
   </tr>
   <tr>
+    <td>Water Confidence</td>
     <td>4-5</td>
-    <td>Water Confidence</td>
   </tr>
   <tr>
+    <td>Reserved (not currently used)</td>
     <td>6-7</td>
-    <td>Reserved (not currently used)</td>
   </tr>
   <tr>
+    <td>Vegetation Confidence</td>
     <td>8-9</td>
-    <td>Vegetation Confidence</td>
   </tr>
   <tr>
+    <td>Snow/Ice Confidence</td>
     <td>10-11</td>
-    <td>Snow/Ice Confidence</td>
   </tr>
   <tr>
+    <td>Cirrus Confidence</td>
     <td>12-13</td>
-    <td>Cirrus Confidence</td>
   </tr>
   <tr>
     <td>14-15</td>
@@ -99,7 +100,7 @@
 
 <p>Possible choices for the "double bits" are:</p>
 
-<table border="1" padding="0" spacing="1" style="width:300px;">
+<table border="1" padding="0" spacing="1">
   <tr>
     <td>Value</td>
 	<td>Description</td>
@@ -132,10 +133,10 @@
 
 <h2>NOTES</h2>
 
-<p>The Landsat Quality Assessment band is an artificial band which represents 
+The Landsat Quality Assessment band is an artificial band which represents 
 an analysis based on <a href=https://landsat.usgs.gov/documents/LDCM_CVT_ADD.pdf>
 defined algorithms</a>. The USGS provides the users with the following note on 
-how the QA band should be used:</p>
+how the QA band should be used:
 
 <p>"Rigorous science applications seeking to optimize the value of pixels used 
 in a study will find QA bits useful as a first level indicator of certain 
@@ -146,21 +147,27 @@
 
 <div class="code"><pre>
 #Create a cloud mask:
-i.landsat8.qc --overwrite --verbose input=LC81980182015183LGN00_BQA \
-    cloud="Not Determined,Maybe,Yes" output=LC81980182015183LGN00_Cloud_Mask
+i.landsat8.qc --overwrite --verbose cloud="Maybe,Yes" \
+    output=./Cloud_Mask_rules.txt
+r.reclass input=LC81980182015183LGN00_BQA \
+    output=LC81980182015183LGN00_Cloud_Mask rules=./Cloud_Mask_rules.txt
 
 #Create a water mask:
-i.landsat8.qc --overwrite --verbose input=LC81980182015183LGN00_BQA \
-    water="Not Determined,Maybe,Yes" output=LC81980182015183LGN00_Water_Mask
+i.landsat8.qc --overwrite --verbose water="Maybe,Yes" \
+    output=./Water_Mask_rules.txt
+r.reclass input=LC81980182015183LGN00_BQA \
+    output=LC81980182015183LGN00_Water_Mask rules=./Water_Mask_rules.txt
+
 </pre></div>
 
 
 <h2>SEE ALSO</h2>
 
 <em>
-<a href="i.modis.qc.html">i.landsat8.swlst.html</a>,
-<a href="r.bitpattern.html">r.bitpattern.html</a>,
-<a href="i.landsat8.swlst.html">i.landsat8.swlst.html</a>,
+<a href="r.reclass.html">r.reclass</a>,
+<a href="i.modis.qc.html">i.modis.qc</a>,
+<a href="r.bitpattern.html">r.bitpattern</a>,
+<a href="i.landsat8.swlst.html">i.landsat8.swlst</a>
 </em>
 
 <h2>REFERENCES</h2>

Modified: grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.py
===================================================================
--- grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.py	2016-05-20 20:42:57 UTC (rev 68478)
+++ grass-addons/grass7/imagery/i.landsat8.qc/i.landsat8.qc.py	2016-05-20 21:01:30 UTC (rev 68479)
@@ -25,28 +25,15 @@
 #% keywords: landsat8
 #%End
 
-#%flag
-#% key: i
-#% description: Invert filter (default is set unacceptable pixels to NULL)
+#%option G_OPT_F_OUTPUT
+#% description: Output file with reclass rules
+#% required: no
 #%end
 
-#%flag
-#% key: p
-#% guisection: Main
-#% description: Print effect of bitpattern filter in number of pixels filtered and exit
-#%end
-
-#%option G_OPT_R_INPUT
-#% guisection: Main
-#% description: Landsat8 QA band
-#% required : yes
-#%end
-
 #%option
 #% key: designated_fill
 #% multiple: No
 #% description: Unacceptable conditions for Designated Fill (bit 0)
-#% guisection: QA bit filter
 #% options: No, Yes
 #% required : no
 #%end
@@ -55,7 +42,6 @@
 #% key: dropped_frame
 #% multiple: No
 #% description: Unacceptable conditions for Dropped Frame (bit 1)
-#% guisection: QA bit filter
 #% options: No, Yes
 #% required : no
 #%end
@@ -64,7 +50,6 @@
 #% key: terrain_occlusion
 #% multiple: No
 #% description: Unacceptable conditions for Terrain Occlusion (bit 2)
-#% guisection: QA bit filter
 #% options: No, Yes
 #% required : no
 #%end
@@ -73,7 +58,6 @@
 ##% key: reserved
 ##% multiple: No
 ##% description: Unacceptable conditions for Reserved (not currently used) (bit 3)
-##% guisection: QA bit filter
 ##% options: No, Yes
 ##% required : no
 ##%end
@@ -82,7 +66,6 @@
 #% key: water
 #% multiple: yes
 #% description: Unacceptable conditions for Water Confidence (bit 4-5)
-#% guisection: QA bit filter
 #% options: Not Determined, No, Maybe, Yes
 #% required : no
 #%end
@@ -91,7 +74,6 @@
 #% key: cloud_shaddow
 #% multiple: yes
 #% description: Unacceptable conditions for Cloud Shaddow Confidence (bit 6-7)
-#% guisection: QA bit filter
 #% options: Not Determined, No, Maybe, Yes
 #% required : no
 #%end
@@ -100,7 +82,6 @@
 #% key: vegetation
 #% multiple: yes
 #% description: Unacceptable conditions for Vegetation Confidence (bit 8-9)
-#% guisection: QA bit filter
 #% options: Not Determined, No, Maybe, Yes
 #% required : no
 #%end
@@ -109,7 +90,6 @@
 #% key: snow_ice
 #% multiple: yes
 #% description: Unacceptable conditions for Snow/Ice Confidence (bit 10-11)
-#% guisection: QA bit filter
 #% options: Not Determined, No, Maybe, Yes
 #% required : no
 #%end
@@ -118,7 +98,6 @@
 #% key: cirrus
 #% multiple: yes
 #% description: Unacceptable conditions for Cirrus Confidence (bit 12-13)
-#% guisection: QA bit filter
 #% options: Not Determined, No, Maybe, Yes
 #% required : no
 #%end
@@ -127,17 +106,10 @@
 #% key: cloud
 #% multiple: yes
 #% description: Unacceptable conditions for Cloud Confidence (bit 14-15)
-#% guisection: QA bit filter
 #% options: Not Determined, No, Maybe, Yes
 #% required : no
 #%end
 
-#%option G_OPT_R_OUTPUT
-#% description: Name for output QA band filter
-#% guisection: Main
-#% required: no
-#%end
-
 #%rules
 #% required: designated_fill,dropped_frame,terrain_occlusion,water,cloud_shaddow,vegetation,snow_ice,cirrus,cloud
 #%end
@@ -156,41 +128,26 @@
     Main program
     """
 
-    # flags
-    invert = flags['i']
-    print_effect = flags['p']
-
     # Parse options
-    input = options['input']
     output = options['output']
 
-    # Define bitpattern filter (bf)
-    bf = {'designated_fill': options['designated_fill'],
-          'dropped_frame': options['dropped_frame'],
-          'terrain_occlusion': options['terrain_occlusion'],
-          # 'reserved': options[''],
-          'water': options['water'],
-          'cloud_shaddow': options['cloud_shaddow'],
-          'vegetation': options['vegetation'],
-          'snow_ice': options['snow_ice'],
-          'cirrus': options['cirrus'],
-          'cloud': options['cloud']}
+    # Extract bitpattern filter from user input
+    bit_filter = []
+    for f in options.keys():
+        if options[f] and f != 'output':
+            bit_filter.append(f)
 
     # Check if propper input is provided:
-    if print_effect and output:
-        grass.fatal("output option and p-flag are mutually exclusive")
+    for o in bit_filter:
+        if len(options[o].split(',')) >= 4:
+            grass.fatal("""All conditions for {} specified as
+            unacceptable, this will result in an empty map.""".format(o))
 
-    if print_effect and invert:
-        grass.fatal("i-flag and p-flag are mutually exclusive")
+    # Define length of Landsat8 QA bitpattern
+    number_of_bits = 16
 
-    for o in ['water', 'cloud_shaddow', 'vegetation',
-              'snow_ice', 'cirrus', 'cloud']:
-        if len(bf[o].split(',')) >= 4 and not invert:
-            grass.fatal("""All conditions for {} specified as 
-            unacceptable, this will result in an empty map.""".format(o))
-        if not bf[o] and invert:
-            grass.fatal("""No conditions for {} selected for an
-            invers filter, this will result in an empty map.""".format(o))
+    # Get maximum integer representation
+    max_int = int(''.join([str(1)] * number_of_bits), 2)
 
     # Define bitpattern characteristics according to
     # http://landsat.usgs.gov/qualityband.php
@@ -263,63 +220,47 @@
                    'Maybe': '10',
                    'Yes': '11'}
 
-    # Get categories and number of pixels from QA band raster
-    qa_cats = grass.parse_command('r.stats', flags='cn', input=input).keys()
+    # List for categories representing pixels of unacceptable quality
+    rc = []
 
-    # Initialise string for reclass rules
-    rc = ''
+    # Loop over all possible integer representations of a 16-bit bitpattern
+    # given as category values in the QA band
+    for cat in range(max_int + 1):
+        # Get the binary equivalent of the integer value
+        bin_cat = '{0:016b}'.format(cat)
 
-    # Initialise dictionary for printing the effect of the different bitpattern
-    if print_effect:
-        pe = {}
+        # Loop over user-defined the bitpattern filter (bit_filter) elements
+        for k in bit_filter:
+            # Calculate bit positions end (bpe)
+            bpe = bps[k] + bl[k]
 
-    # Loop over category values present in the QA band (qa_cats)
-    for line in qa_cats:
-        cat, pixels = line.split(' ')
-        # Convert integer categories into bitpattern
-        bin_cat = '{0:016b}'.format(int(cat))
+            # Extract unnacceptable bitpatterns (bp) form bitpattern filter
+            for bp in options[k].split(','):
 
-        # Loop over the bitpattern filter (bf) elements defined by the user
-        for k in bf.keys():
-            # Only work on bits included in the user`s bitpattern filter (bf)
-            if bf[k]:
-                # Calculate bit positions end (bpe)
-                bpe = bps[k] + bl[k]
-                # Extract unnacceptable bitpatterns (bp) form bitpattern filter
-                for bp in bf[k].split(','):
-                    if bl[k] == 1:
-                        bits = single_bits[bp]
-                    else:
-                        bits = double_bits[bp]
-                    # Check if bitpattern of the category should be filtered
-                    if bits == bin_cat[len(bin_cat) -
-                                       bpe:len(bin_cat) - bps[k]]:
-                        # Add category to recassification rule
-                        rc = rc + ' {}'.format(cat)
-                        # Calculate nuber of pixels which are filtered using
-                        # the current bitpattern
-                        if print_effect:
-                            pe_key = '{} = {}'.format(k, bp)
-                            if pe_key not in pe.keys():
-                                pe[pe_key] = int(pixels)
-                            else:
-                                pe[pe_key] = pe[pe_key] + int(pixels)
+                if bl[k] == 1:
+                    bits = single_bits[bp]
+                else:
+                    bits = double_bits[bp]
 
+                # Check if bitpattern of the category should be filtered
+                if bits == bin_cat[len(bin_cat) - bpe:len(bin_cat) - bps[k]]:
+                    # Add category to recassification rule
+                    rc.append(str(cat) + ' = NULL')
+                    break
+            # Avoid duplicates in reclass rules when several filter are applied
+            if bits == bin_cat[len(bin_cat) - bpe:len(bin_cat) - bps[k]]:
+                break
+
     # Construct rules for reclassification
-    if invert:
-        rc = rc + ' = 1\n * = NULL'
-    else:
-        rc = rc + ' = NULL\n * = 1'
+    rules = '\n'.join(rc) + '\n* = 1\n'
 
-    # Print filterstistics if requested, else reclassify
-    if print_effect:
-        for k in pe.keys():
-            sys.stdout.write('{} {}\n'.format(k, pe[k]))
+    # Print to stdout if no output file is specified
+    if not options['output']:
+            sys.stdout.write(rules)
     else:
-        grass.write_command('r.reclass', flags='', input=input, output=output,
-                            rules='-', stdin=rc)
+        with open(output, 'w') as o:
+            o.write(rules)
 
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())
-



More information about the grass-commit mailing list