[GRASS-SVN] r73551 - grass-addons/grass7/imagery/i.cutlines

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Oct 15 04:21:59 PDT 2018


Author: mlennert
Date: 2018-10-15 04:21:59 -0700 (Mon, 15 Oct 2018)
New Revision: 73551

Modified:
   grass-addons/grass7/imagery/i.cutlines/i.cutlines.html
   grass-addons/grass7/imagery/i.cutlines/i.cutlines.py
Log:
i.cutlines: added option to use existing cutlines; reduced output options to vector polygons; clearer parameters names

Modified: grass-addons/grass7/imagery/i.cutlines/i.cutlines.html
===================================================================
--- grass-addons/grass7/imagery/i.cutlines/i.cutlines.html	2018-10-15 09:27:46 UTC (rev 73550)
+++ grass-addons/grass7/imagery/i.cutlines/i.cutlines.html	2018-10-15 11:21:59 UTC (rev 73551)
@@ -14,19 +14,28 @@
 
 <p>
 The user can determine the number of lines desired (<b>number_lines</b>) in each
-direction and the relative weight given to edges compared to other pixels 
-(<b>edge_weight</b>), weight of other pixels being 1. In order to avoid that all
-lines gather into one single lowest cost path, the module defines a lane for 
-each desired line. The parameter <b>lane_border_resistance</b> defines the cost 
-to cross that line, i.e. the lower the value, the more likely cutlines will join
-each other. Output can be in the form of raster or vector lines 
-(<b>raster_lines</b> and <b>vector_lines</b> parameters) or in the form of 
-vector polygon tiles (<b>vector_tiles</b>). For the latter, the user can decide
-a minimum size defined in map units (<b>min_tile_size</b>). Tiles smaller than
-that size will be merged with the neighboring tile they share the longest 
-border with.
+direction and the friction associated with pixels which are not on an edge
+detected in the image (<b>no_edge_friction</b>). The higher this value, the
+more the module will follow the detected edges.
 
 <p>
+In order to avoid that all lines gather into one single lowest cost path, the
+module defines a lane for each desired line. The parameter
+<b>lane_border_multiplier</b> defines the a multiplier of the
+<b>no_edge_friction</b> value, in order to define the cost to 
+cross that line, i.e. the lower the value, the more likely cutlines will join 
+each other across lanes. Output is in the form of vector polygon tiles. The user
+can decide a minimum size defined in map units (<b>min_tile_size</b>). Tiles 
+smaller than that size will be merged with the neighboring tile they share the 
+longest border with.
+
+<p>
+The user can provide a series of auxiliary vector maps which contain existing
+cutlines (roads, boundaries, etc) that the module should take into account
+(<b>existing_cutlines</b>). These can be either lines or polygons. The module
+will transform all to potential cutlines.
+
+<p>
 For edge detection the user can chose between the <a href="i.zc.html">i.zc</a> 
 module or the <a href="i.edge.html">i.edge</a> addon. For the former, the user
 can determine the <b>zc_threshold</b> and the <b>zc_width</b> parameters. For

Modified: grass-addons/grass7/imagery/i.cutlines/i.cutlines.py
===================================================================
--- grass-addons/grass7/imagery/i.cutlines/i.cutlines.py	2018-10-15 09:27:46 UTC (rev 73550)
+++ grass-addons/grass7/imagery/i.cutlines/i.cutlines.py	2018-10-15 11:21:59 UTC (rev 73551)
@@ -25,6 +25,10 @@
 #% required: yes
 #%end
 #
+#%option G_OPT_V_OUTPUT
+#% description: Name of output vector map with cutline polygons
+#%end
+#
 #%option
 #% key: number_lines
 #% type: integer
@@ -41,20 +45,26 @@
 #% required: yes
 #%end
 #
+#%option G_OPT_V_INPUTS
+#% key: existing_cutlines
+#% label: Input vector maps with existing cutlines
+#% required: no
+#%end
+#
 #%option
-#% key: edge_weight
+#% key: no_edge_friction
 #% type: integer
-#% description: Priority to give to edge pixels over other pixels
+#% description: Additional friction for non-edge pixels
 #% required: yes
 #% answer: 5
 #%end
 #
 #%option
-#% key: lane_border_resistance
+#% key: lane_border_multiplier
 #% type: integer
-#% description: Friction of borders of lanes
+#% description: Multiplier for borders of lanes compared to non-edge pixels
 #% required: yes
-#% answer: 10000
+#% answer: 10
 #%end
 #
 #%option
@@ -64,27 +74,6 @@
 #% required: no
 #%end
 #
-#%option G_OPT_V_OUTPUT
-#% key: vector_tiles
-#% label: Name for output vector map with tiles as polygons
-#% required: no
-#% guisection: Output
-#%end
-#
-#%option G_OPT_V_OUTPUT
-#% key: vector_lines
-#% label: Name for output vector map with tiles as lines
-#% required: no
-#% guisection: Output
-#%end
-#
-#%option G_OPT_R_OUTPUT
-#% key: raster_lines
-#% label: Name for output raster map with tiles as lines
-#% required: no
-#% guisection: Output
-#%end
-#
 #%option
 #% key: zc_threshold
 #% type: double
@@ -170,12 +159,10 @@
 #% description: RAM memory available (in MB)
 #% answer: 300
 #% required: yes
-#% guisection: Options
 #%end
 #
 #%rules
 #% collective: tile_width, tile_height, overlap
-#% required: vector_tiles, vector_lines, raster_lines
 #%end
 
 import os
@@ -197,20 +184,15 @@
     inputraster = options['input']
     number_lines = int(options['number_lines'])
     edge_detection_algorithm = options['edge_detection']
-    edge_weight = int(options['edge_weight'])
-    lane_border_resistance = int(options['lane_border_resistance'])
+    no_edge_friction = int(options['no_edge_friction'])
+    lane_border_multiplier = int(options['lane_border_multiplier'])
     min_tile_size = None
     if options['min_tile_size']:
         min_tile_size = float(options['min_tile_size'])
-    tiles = None
-    if options['vector_tiles']:
-        tiles = options['vector_tiles'] 
-    vector_lines = None
-    if options['vector_lines']:
-        vector_lines = options['vector_lines']
-    raster_lines = None
-    if options['raster_lines']:
-        raster_lines = options['raster_lines']
+    existing_cutlines = None
+    if options['existing_cutlines']:
+        existing_cutlines = options['existing_cutlines'].split(',') 
+    tiles = options['output'] 
     memory = int(options['memory'])
     tiled = False
 
@@ -228,6 +210,26 @@
     r = 'raster'
     v = 'vector'
 
+    if existing_cutlines:
+        existingcutlinesmap = 'temp_icutlines_existingcutlinesmap_%i' % os.getpid()
+        if len(existing_cutlines) > 1:
+            gscript.run_command('v.patch',
+                                input_=existing_cutlines,
+                                output=existingcutlinesmap,
+                                quiet=True,
+                                overwrite=True)
+            existing_cutlines=existingcutlinesmap
+
+        gscript.run_command('v.to.rast',
+                            input_=existing_cutlines,
+                            output=existingcutlinesmap,
+                            use='val',
+                            type_='line,boundary',
+                            overwrite=True,
+                            quiet=True)
+
+        temp_maps.append([existingcutlinesmap, r])
+
     temp_edge_map = "temp_icutlines_edgemap_%d" % os.getpid()
     temp_maps.append([temp_edge_map, r])
 
@@ -240,13 +242,6 @@
                   'quiet' : True}
 
         if tiled:
-            if gscript.version()['version'] < '7.5':
-                message = "Currently there is a parameter name conflict between\n"
-                message += "i.zc and GridModule used for tiling.\n"
-                message += "This is solved in GRASS trunk.\n"
-                message += "Please use i.edge for edge detection or GRASS trunk\n"
-                message += "if you want to tile this part."
-                gscript.fatal(message)
             grd = GridModule('i.zc',
                              width=width,
                              height=height,
@@ -293,16 +288,24 @@
     region = gscript.region()
     gscript.message(_("Finding cutlines in both directions"))
 
+    nsrange = float(region.n - region.s - region.nsres)
+    ewrange = float(region.e - region.w - region.ewres)
+
+    if nsrange > ewrange:
+        hnumber_lines = number_lines
+        vnumber_lines = int(number_lines * (ewrange / nsrange))
+    else:
+        vnumber_lines = number_lines
+        hnumber_lines = int(number_lines * (nsrange / ewrange))
+
     # Create the lines in horizonal direction
-    nsstep = float(region.n - region.s - region.nsres) / number_lines
-    hpointsy = [((region.n - i * nsstep) - region.nsres / 2.0) for i in range(0, number_lines+1)]
+    nsstep = float(region.n - region.s - region.nsres) / hnumber_lines
+    hpointsy = [((region.n - i * nsstep) - region.nsres / 2.0) for i in range(0, hnumber_lines+1)]
     hlanepointsy = [y - nsstep / 2.0 for y in hpointsy]
     hstartpoints = zip([region.w + 0.2 * region.ewres] * len(hpointsy), hpointsy)
     hstoppoints = zip([region.e - 0.2 * region.ewres] * len(hpointsy), hpointsy)
-    hlanestartpoints = zip([region.w + 0.2 * region.ewres] * len(hlanepointsy),
-            hlanepointsy)
-    hlanestoppoints = zip([region.e - 0.2 * region.ewres] * len(hlanepointsy),
-            hlanepointsy)
+    hlanestartpoints = zip([region.w + 0.2 * region.ewres] * len(hlanepointsy), hlanepointsy)
+    hlanestoppoints = zip([region.e - 0.2 * region.ewres] * len(hlanepointsy), hlanepointsy)
 
     hlanemap = 'temp_icutlines_hlanemap_%i' % os.getpid()
     temp_maps.append([hlanemap, v])
@@ -326,11 +329,28 @@
 
     hbasemap = 'temp_icutlines_hbasemap_%i' % os.getpid()
     temp_maps.append([hbasemap, r])
+
+    # Building the cost maps using the following logic
+    # - Any pixel not on an edge, nor on an existing cutline gets a
+    # no_edge_friction cost, or no_edge_friction_cost x 10  if there are
+    # existing cutlines
+    # - Any pixel on an edge gets a cost of 1 if there are no existing cutlines,
+    # and a cost of no_edge_friction if there are
+    # - A lane line gets a very high cost (lane_border_multiplier x cost of no
+    # edge pixel - the latter depending on the existence of cutlines).
+
     mapcalc_expression = "%s = " % hbasemap
     mapcalc_expression += "if(isnull(%s), " % hlanemap
-    mapcalc_expression += "if(%s == 0, " % temp_edge_map 
-    mapcalc_expression += "%i, 1), " % edge_weight 
-    mapcalc_expression += "%i)" % lane_border_resistance
+    if existing_cutlines:
+        mapcalc_expression += "if(%s == 0 && isnull(%s), " % (temp_edge_map, existingcutlinesmap)
+        mapcalc_expression += "%i, " % (no_edge_friction * 10)
+        mapcalc_expression += "if(isnull(%s), %s, 1))," % (existingcutlinesmap, no_edge_friction)
+        mapcalc_expression += "%i)" % (lane_border_multiplier * no_edge_friction * 10)
+    else:
+        mapcalc_expression += "if(%s == 0, " % temp_edge_map
+        mapcalc_expression += "%i, " % no_edge_friction
+        mapcalc_expression += "1), "
+        mapcalc_expression += "%i)" % (lane_border_multiplier * no_edge_friction)
     gscript.run_command('r.mapcalc',
                         expression=mapcalc_expression,
                         quiet=True,
@@ -343,14 +363,12 @@
 
 
     # Create the lines in vertical direction
-    ewstep = float(region.e - region.w - region.ewres) / number_lines
-    vpointsx = [((region.e - i * ewstep) - region.ewres / 2.0) for i in range(0, number_lines+1)]
+    ewstep = float(region.e - region.w - region.ewres) / vnumber_lines
+    vpointsx = [((region.e - i * ewstep) - region.ewres / 2.0) for i in range(0, vnumber_lines+1)]
     vlanepointsx = [x + ewstep / 2.0 for x in vpointsx]
     vstartpoints = zip(vpointsx, [region.n - 0.2 * region.nsres] * len(vpointsx))
     vstoppoints = zip(vpointsx, [region.s + 0.2 * region.nsres] * len(vpointsx))
-    vlanestartpoints = zip(vlanepointsx, [region.n - 0.2 * region.nsres] *
-            len(vlanepointsx))
-            
+    vlanestartpoints = zip(vlanepointsx, [region.n - 0.2 * region.nsres] * len(vlanepointsx))
     vlanestoppoints = zip(vlanepointsx, [region.s + 0.2 * region.nsres] * len(vlanepointsx))
             
 
@@ -378,9 +396,16 @@
     temp_maps.append([vbasemap, r])
     mapcalc_expression = "%s = " % vbasemap
     mapcalc_expression += "if(isnull(%s), " % vlanemap
-    mapcalc_expression += "if(%s == 0, " % temp_edge_map 
-    mapcalc_expression += "%i, 1), " % edge_weight 
-    mapcalc_expression += "%i)" % lane_border_resistance
+    if existing_cutlines:
+        mapcalc_expression += "if(%s == 0 && isnull(%s), " % (temp_edge_map, existingcutlinesmap)
+        mapcalc_expression += "%i, " % (no_edge_friction  * 10)
+        mapcalc_expression += "if(isnull(%s), %s, 1))," % (existingcutlinesmap, no_edge_friction)
+        mapcalc_expression += "%i)" % (lane_border_multiplier * no_edge_friction * 10)
+    else:
+        mapcalc_expression += "if(%s == 0, " % temp_edge_map
+        mapcalc_expression += "%i, " % no_edge_friction
+        mapcalc_expression += "1), "
+        mapcalc_expression += "%i)" % (lane_border_multiplier * no_edge_friction)
     gscript.run_command('r.mapcalc',
                         expression=mapcalc_expression,
                         quiet=True,
@@ -493,135 +518,114 @@
                         quiet=True,
                         overwrite=True)
 
-    if raster_lines:
-        gscript.run_command('g.copy',
-                            raster=[temp_raster_tile_borders,raster_lines],
-                            quiet=True,
-                            overwrite=True)
+    gscript.message(_("Creating vector polygons"))
+                        
+    # Create vector polygons
 
-    if vector_lines:
-        temp_vector_tile_borders = 'temp_icutlines_vector_tile_borders_%i' % os.getpid()
-        temp_maps.append([temp_vector_tile_borders, v])
-        gscript.run_command('r.to.vect',
-                            input_=temp_raster_tile_borders,
-                            output=temp_vector_tile_borders,
-                            type_='line',
-                            flags='t',
-                            quiet=True,
-                            overwrite=True)
-        gscript.run_command('g.copy',
-                            vector=[temp_vector_tile_borders,vector_lines],
-                            quiet=True,
-                            overwrite=True)
+    # First we need to shrink the region a bit to make sure that all vector
+    # points / lines fall within the raster
+    gscript.use_temp_region()
+    gscript.run_command('g.region',
+                        s=region.s+region.nsres,
+                        e=region.e-region.ewres,
+                        quiet=True)
 
-    if tiles:
-        gscript.message(_("Creating vector polygons"))
-                            
-        # Create vector polygons
+    region_map = 'temp_icutlines_region_map_%i' % os.getpid()
+    temp_maps.append([region_map, v])
+    temp_maps.append([region_map, r])
+    gscript.run_command('v.in.region',
+                        output=region_map,
+                        type_='line',
+                        quiet=True,
+                        overwrite=True)
 
-        # First we need to shrink the region a bit to make sure that all vector
-        # points / lines fall within the raster
-        gscript.use_temp_region()
-        gscript.run_command('g.region',
-                            s=region.s+region.nsres,
-                            e=region.e-region.ewres,
-                            quiet=True)
+    gscript.del_temp_region()
+    
+    gscript.run_command('v.to.rast',
+                        input_=region_map,
+                        output=region_map,
+                        use='val',
+                        type_='line',
+                        quiet=True,
+                        overwrite=True)
 
-        region_map = 'temp_icutlines_region_map_%i' % os.getpid()
-        temp_maps.append([region_map, v])
-        temp_maps.append([region_map, r])
-        gscript.run_command('v.in.region',
-                            output=region_map,
-                            type_='line',
-                            quiet=True,
-                            overwrite=True)
+    temp_raster_polygons = 'temp_icutlines_raster_polygons_%i' % os.getpid()
+    temp_maps.append([temp_raster_polygons, r])
+    gscript.run_command('r.patch',
+                        input_=[temp_raster_tile_borders,region_map],
+                        output=temp_raster_polygons,
+                        quiet=True,
+                        overwrite=True)
 
-        gscript.del_temp_region()
-        
-        gscript.run_command('v.to.rast',
-                            input_=region_map,
-                            output=region_map,
-                            use='val',
-                            type_='line',
-                            quiet=True,
-                            overwrite=True)
+    temp_raster_polygons_thin = 'temp_icutlines_raster_polygons_thin_%i' % os.getpid()
+    temp_maps.append([temp_raster_polygons_thin, r])
+    gscript.run_command('r.thin',
+                        input_=temp_raster_polygons,
+                        output=temp_raster_polygons_thin,
+                        quiet=True,
+                        overwrite=True)
 
-        temp_raster_polygons = 'temp_icutlines_raster_polygons_%i' % os.getpid()
-        temp_maps.append([temp_raster_polygons, r])
-        gscript.run_command('r.patch',
-                            input_=[temp_raster_tile_borders,region_map],
-                            output=temp_raster_polygons,
-                            quiet=True,
-                            overwrite=True)
+    # Create a series of temporary map names as we have to go 
+    # through several steps until we reach the final map.
+    temp_vector_polygons1 = 'temp_icutlines_vector_polygons1_%i' % os.getpid()
+    temp_maps.append([temp_vector_polygons1, v])
+    temp_vector_polygons2 = 'temp_icutlines_vector_polygons2_%i' % os.getpid()
+    temp_maps.append([temp_vector_polygons2, v])
+    temp_vector_polygons3 = 'temp_icutlines_vector_polygons3_%i' % os.getpid()
+    temp_maps.append([temp_vector_polygons3, v])
+    temp_vector_polygons4 = 'temp_icutlines_vector_polygons4_%i' % os.getpid()
+    temp_maps.append([temp_vector_polygons4, v])
 
-        temp_raster_polygons_thin = 'temp_icutlines_raster_polygons_thin_%i' % os.getpid()
-        temp_maps.append([temp_raster_polygons_thin, r])
-        gscript.run_command('r.thin',
-                            input_=temp_raster_polygons,
-                            output=temp_raster_polygons_thin,
-                            quiet=True,
-                            overwrite=True)
+    gscript.run_command('r.to.vect',
+                        input_=temp_raster_polygons_thin,
+                        output=temp_vector_polygons1,
+                        type_='line',
+                        flags='t',
+                        quiet=True,
+                        overwrite=True)
 
-        # Create a series of temporary map names as we have to go 
-        # through several steps until we reach the final map.
-        temp_vector_polygons1 = 'temp_icutlines_vector_polygons1_%i' % os.getpid()
-        temp_maps.append([temp_vector_polygons1, v])
-        temp_vector_polygons2 = 'temp_icutlines_vector_polygons2_%i' % os.getpid()
-        temp_maps.append([temp_vector_polygons2, v])
-        temp_vector_polygons3 = 'temp_icutlines_vector_polygons3_%i' % os.getpid()
-        temp_maps.append([temp_vector_polygons3, v])
-        temp_vector_polygons4 = 'temp_icutlines_vector_polygons4_%i' % os.getpid()
-        temp_maps.append([temp_vector_polygons4, v])
+    # Erase all category values from the lines
+    gscript.run_command('v.category',
+                        input_=temp_vector_polygons1,
+                        op='del',
+                        cat='-1',
+                        output=temp_vector_polygons2,
+                        quiet=True,
+                        overwrite=True)
 
-        gscript.run_command('r.to.vect',
-                            input_=temp_raster_polygons_thin,
-                            output=temp_vector_polygons1,
-                            type_='line',
-                            flags='t',
-                            quiet=True,
-                            overwrite=True)
+    # Transform lines to boundaries
+    gscript.run_command('v.type',
+                        input_=temp_vector_polygons2,
+                        from_type='line',
+                        to_type='boundary',
+                        output=temp_vector_polygons3,
+                        quiet=True,
+                        overwrite=True)
 
-        # Erase all category values from the lines
-        gscript.run_command('v.category',
-                            input_=temp_vector_polygons1,
-                            op='del',
-                            cat='-1',
-                            output=temp_vector_polygons2,
-                            quiet=True,
-                            overwrite=True)
+    # Add centroids
+    gscript.run_command('v.centroids',
+                        input_=temp_vector_polygons3,
+                        output=temp_vector_polygons4,
+                        quiet=True,
+                        overwrite=True)
 
-        # Transform lines to boundaries
-        gscript.run_command('v.type',
-                            input_=temp_vector_polygons2,
-                            from_type='line',
-                            to_type='boundary',
-                            output=temp_vector_polygons3,
+    # If a threshold is given erase polygons that are too small
+    if min_tile_size:
+        gscript.run_command('v.clean',
+                            input_=temp_vector_polygons4,
+                            tool='rmarea',
+                            threshold=min_tile_size,
+                            output=tiles,
                             quiet=True,
                             overwrite=True)
-
-        # Add centroids
-        gscript.run_command('v.centroids',
-                            input_=temp_vector_polygons3,
-                            output=temp_vector_polygons4,
+    else:
+        gscript.run_command('g.copy',
+                            vect=[temp_vector_polygons4,tiles],
                             quiet=True,
                             overwrite=True)
 
-        # If a threshold is given erase polygons that are too small
-        if min_tile_size:
-            gscript.run_command('v.clean',
-                                input_=temp_vector_polygons4,
-                                tool='rmarea',
-                                threshold=min_tile_size,
-                                output=tiles,
-                                quiet=True,
-                                overwrite=True)
-        else:
-            gscript.run_command('g.copy',
-                                vect=[temp_vector_polygons4,tiles],
-                                quiet=True,
-                                overwrite=True)
+    gscript.vector_history(tiles)
 
-
 if __name__ == "__main__":
     options, flags = gscript.parser()
     atexit.register(cleanup)



More information about the grass-commit mailing list