Skip to content

Commit

Permalink
complete split edits (input params, num_pixels, output)
Browse files Browse the repository at this point in the history
  • Loading branch information
vbrunn committed Oct 18, 2024
1 parent 1c9a320 commit d1b1224
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@ <h3>Generation of training data for tree and non-tree classification</h3>
trees_pixel_ndvi=trees_pixel_ndvi \
trees_raw_rast=trees_raw_rast \
group=ml_input \
save_model=ml_trees_randomforest.gz \
save_model=ml_trees_randomforest.gz
</pre></div>

<h2>SEE ALSO</h2>

<em>
<a href="m.analyse.trees.html">m.analyse.trees</a>,
<a href="https://grass.osgeo.org/grass-stable/manuals/r.geomorphon.html">r.geomorphon</a>,
<a href="r.learn.train.html">r.learn.train</a>,
<a href="r.learn.predict.html">r.learn.predict</a>
</em>
Expand Down
144 changes: 78 additions & 66 deletions grass-gis-addons/m.analyse.trees/r.trees.mltrain/r.trees.mltrain.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
# % key: trees_pixel_ndvi
# % label: raster with trees identified by NDVI value
# % answer: trees_pixel_ndvi
# % guisection: Input # ---> ????
# % guisection: Input
# %end

# %option G_OPT_R_INPUT
Expand Down Expand Up @@ -109,6 +109,14 @@
# % guisection: Input
# %end

# %option
# % key: num_samples
# % type: integer
# % required: no
# % label: Number of sample points for each class in training
# % guisection: Optional input
# %end

# %option
# % key: group
# % type: string
Expand All @@ -127,10 +135,6 @@
# % guisection: Output
# %end

# %option G_OPT_MEMORYMB
# % guisection: Parallel processing
# %end

# %option G_OPT_M_NPROCS
# % label: Number of cores for multiprocessing, -2 is the number of available cores - 1
# % answer: -2
Expand All @@ -150,8 +154,6 @@

# initialize global vars
rm_rasters = []
rm_vectors = []
rm_groups = []
tmp_mask_old = None


Expand All @@ -161,24 +163,28 @@ def cleanup():
for rmrast in rm_rasters:
if grass.find_file(name=rmrast, element="cell")["file"]:
grass.run_command("g.remove", type="raster", name=rmrast, **kwargs)
for rmv in rm_vectors:
if grass.find_file(name=rmv, element="vector")["file"]:
grass.run_command("g.remove", type="vector", name=rmv, **kwargs)
for rmgroup in rm_groups:
if grass.find_file(name=rmgroup, element="group")["file"]:
grass.run_command("g.remove", type="group", name=rmgroup, **kwargs)
grass.del_temp_region()

def numsamplecheck(number_samples, rastername):
raster_samples = int(grass.parse_command("r.univar", map=rastername, flags="g")["n"])
if number_samples > raster_samples:
grass.warning(
_(f"The chosen number of pixels {number_samples} is exceeding the total number of ",
f"non-null pixels in the given rastermap {rastername}. ",
f"The number of pixels will be set to the maximal amount of {raster_samples}.")
)
number_samples = raster_samples
return number_samples

def main():
global rm_rasters, tmp_mask_old, rm_vectors, rm_groups
global rm_rasters, tmp_mask_old

path = get_lib_path(modname="m.analyse.trees", libname="analyse_trees_lib")
if path is None:
grass.fatal("Unable to find the analyse trees library directory")
sys.path.append(path)
try:
from analyse_trees_lib import set_nprocs, test_memory
from analyse_trees_lib import set_nprocs
except Exception:
grass.fatal("m.analyse.trees library is not installed")

Expand All @@ -203,28 +209,7 @@ def main():
nprocs = int(options["nprocs"])
trees_pixel_ndvi = options["trees_pixel_ndvi"]

if options["trees_raw_v"]:
trees_raw_v_rast = f"trees_raw_v_rast_{os.getpid()}"
rm_rasters.append(trees_raw_v_rast)

grass.run_command(
"v.to.rast",
input=options["trees_raw_v"],
output=trees_raw_v_rast,
use="value",
value=2,
)
trees_basemap = trees_raw_v_rast
else:
trees_basemap = options["trees_raw_r"]

nprocs = set_nprocs(nprocs)
memmb = test_memory(options["memory"])
# for some modules like r.neighbors and r.slope_aspect, there is
# no speed gain by using more than 100 MB RAM
memory_max100mb = 100
if memmb < 100:
memory_max100mb = memmb

grass.use_temp_region()

Expand All @@ -240,55 +225,82 @@ def main():
f"{ndgb} = round(127.5 * (1.0 + float({green} - {blue}) / float({green} + {blue})))"
)

# extract training points
# extract 4000 cells
grass.run_command(
"r.random",
input=trees_basemap,
raster="trees_trainpnts",
npoints=4000,
flags="s",
)

rm_rasters.append("trees_trainpnts")
if options["trees_raw_v"]:
trees_raw_v_rast = f"trees_raw_v_rast_{os.getpid()}"
rm_rasters.append(trees_raw_v_rast)

grass.run_command(
"v.to.rast",
input=options["trees_raw_v"],
output=trees_raw_v_rast,
use="value",
value=2,
)
trees_basemap = trees_raw_v_rast
else:
trees_basemap = options["trees_raw_r"]

# non trees

# false trees
# problem areas with high NDVI like shadows on roofs, solar panels
# trees_object_filt_large = NULL and trees_pixel_ndvi != NULL
rm_rasters.append(trees_pixel_ndvi)
grass.mapcalc(
f"false_trees = if(isnull({trees_pixel_ndvi}), null(), if(isnull({trees_basemap}), 1, null()))"
)
grass.run_command(
"r.random",
input="false_trees",
raster="false_trees_trainpnts",
npoints=4000,
flags="s",
)
rm_rasters.append("false_trees")
rm_rasters.append("false_trees_trainpnts")

# other areas clearly not trees
grass.mapcalc(
f"notrees = if(isnull({trees_pixel_ndvi}) && isnull({trees_basemap}), 1, null())"
)
grass.run_command(
"r.random",
input="notrees",
raster="notrees_trainpnts",
npoints=4000,
flags="s",
)
rm_rasters.append("false_trees")
rm_rasters.append("notrees")
rm_rasters.append("notrees_trainpnts")

# extract training points
# extract "num_samples" cells if given
if options["num_samples"]:
num_samples = int(options["num_samples"])

realsamples = numsamplecheck(num_samples, trees_basemap)
grass.run_command(
"r.random",
input=trees_basemap,
raster="trees_trainpnts",
npoints=realsamples,
flags="s",
)

# false trees
realsamples = numsamplecheck(num_samples, "false_trees")
grass.run_command(
"r.random",
input="false_trees",
raster="false_trees_trainpnts",
npoints=realsamples,
flags="s",
)

# other areas clearly not trees
realsamples = numsamplecheck(num_samples, "notrees")
grass.run_command(
"r.random",
input="notrees",
raster="notrees_trainpnts",
npoints=realsamples,
flags="s",
)
rm_rasters.append("trees_trainpnts")
rm_rasters.append("false_trees_trainpnts")
rm_rasters.append("notrees_trainpnts")

patch_list = ["trees_trainpnts", "false_trees_trainpnts", "notrees_trainpnts"]
else:
patch_list = [trees_basemap, "false_trees", "notrees"]

# patch trees, false trees and non-trees
grass.run_command(
"r.patch",
input="trees_trainpnts,false_trees_trainpnts,notrees_trainpnts",
input=patch_list,
output="ml_trainpnts",
)
rm_rasters.append("ml_trainpnts")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ <h3>Generation of training data for tree and non-tree classification</h3>
nir_threshold=130 \
ndsm_threshold=1 \
slopep75_threshold=70 \
area_threshold=5
area_threshold=5 \
trees_pixel_ndvi=trees_pixel_ndvi
</pre></div>

<h2>SEE ALSO</h2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,23 @@
# % key: traindata_r
# % label: primary tree map as raster
# % description: Primary tree map in raster format to pass to mltrain
# % answer: traindata_r
# % required: no
# % guisection: Output
# %end

# %option G_OPT_V_OUTPUT
# % key: traindata_v
# % label: primary tree map as vector
# % description: Primary tree map in vector format to export and edit
# % answer: traindata_v
# % required: no
# % guisection: Output
# %end

# %option G_OPT_R_OUTPUT
# % key: trees_pixel_ndvi
# % label: Name of raster with nearest peak IDs filtered by NDVI
# % description: necessary intermediate result for mltrain
# % required: no
# % guisection: Output
# %end

Expand All @@ -168,7 +176,6 @@
# %end

# %rules
# % exclusive: traindata_r,traindata_v
# % required: traindata_r,traindata_v
# %end

Expand All @@ -181,7 +188,6 @@
# initialize global vars
rm_rasters = []
rm_vectors = []
rm_groups = []
tmp_mask_old = None


Expand All @@ -194,14 +200,11 @@ def cleanup():
for rmv in rm_vectors:
if grass.find_file(name=rmv, element="vector")["file"]:
grass.run_command("g.remove", type="vector", name=rmv, **kwargs)
for rmgroup in rm_groups:
if grass.find_file(name=rmgroup, element="group")["file"]:
grass.run_command("g.remove", type="group", name=rmgroup, **kwargs)
grass.del_temp_region()


def main():
global rm_rasters, tmp_mask_old, rm_vectors, rm_groups
global rm_rasters, tmp_mask_old, rm_vectors

path = get_lib_path(modname="m.analyse.trees", libname="analyse_trees_lib")
if path is None:
Expand Down Expand Up @@ -311,16 +314,22 @@ def main():
rm_rasters.append(f"{ndvi_split}_max1")
rm_rasters.append(f"{ndvi_split}_max2")

if options["trees_pixel_ndvi"]:
trees_pixel_ndvi = options["trees_pixel_ndvi"]
else:
trees_pixel_ndvi = "trees_pixel_ndvi"
rm_rasters.append(trees_pixel_ndvi)

grass.mapcalc(
f"trees_pixel_ndvi = if({ndvi_split}_max2 < {ndvi_threshold}, null(), {nearest})"
f"{trees_pixel_ndvi} = if({ndvi_split}_max2 < {ndvi_threshold}, null(), {nearest})"
)
# rm_rasters.append("trees_pixel_ndvi") --> keep raster for mltrain


# cut to nir: all pixels below 100 are not vegetation
# removes shadows with high ndvi e.g. on roofs
# needed
grass.mapcalc(
f"trees_pixel_nir = if({nir} < {nir_threshold}, null(), trees_pixel_ndvi)"
f"trees_pixel_nir = if({nir} < {nir_threshold}, null(), {trees_pixel_ndvi})"
)
rm_rasters.append("trees_pixel_nir")

Expand Down Expand Up @@ -491,10 +500,11 @@ def main():

# trees: trees_object_filt_large
if options["traindata_r"]:
grass.mapcalc(f"{options["traindata_r"]} = if(isnull(trees_object_filt_large), null(), 2)")
rm_vectors.append("trees_object_filt_large")
grass.mapcalc(f"{options['traindata_r']} = if(isnull(trees_object_filt_large), null(), 2)")
if not options["traindata_v"]:
rm_vectors.append("trees_object_filt_large")

elif options["traindata_v"]:
if options["traindata_v"]:
grass.run_command(
"g.rename",
vector=f"trees_object_filt_large,{options['traindata_v']}"
Expand Down

0 comments on commit d1b1224

Please sign in to comment.