BERATools 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- beratools/__init__.py +1 -7
- beratools/core/algo_centerline.py +491 -351
- beratools/core/algo_common.py +497 -0
- beratools/core/algo_cost.py +192 -0
- beratools/core/{dijkstra_algorithm.py → algo_dijkstra.py} +503 -460
- beratools/core/algo_footprint_rel.py +577 -0
- beratools/core/algo_line_grouping.py +944 -0
- beratools/core/algo_merge_lines.py +214 -0
- beratools/core/algo_split_with_lines.py +304 -0
- beratools/core/algo_tiler.py +428 -0
- beratools/core/algo_vertex_optimization.py +469 -0
- beratools/core/constants.py +52 -86
- beratools/core/logger.py +76 -85
- beratools/core/tool_base.py +196 -133
- beratools/gui/__init__.py +11 -15
- beratools/gui/{beratools.json → assets/beratools.json} +2185 -2300
- beratools/gui/batch_processing_dlg.py +513 -463
- beratools/gui/bt_data.py +481 -487
- beratools/gui/bt_gui_main.py +710 -691
- beratools/gui/main.py +26 -0
- beratools/gui/map_window.py +162 -146
- beratools/gui/tool_widgets.py +725 -493
- beratools/tools/Beratools_r_script.r +1120 -1120
- beratools/tools/Ht_metrics.py +116 -116
- beratools/tools/__init__.py +7 -7
- beratools/tools/batch_processing.py +136 -132
- beratools/tools/canopy_threshold_relative.py +672 -670
- beratools/tools/canopycostraster.py +222 -222
- beratools/tools/centerline.py +136 -176
- beratools/tools/common.py +857 -885
- beratools/tools/fl_regen_csf.py +428 -428
- beratools/tools/forest_line_attributes.py +408 -408
- beratools/tools/line_footprint_absolute.py +213 -363
- beratools/tools/line_footprint_fixed.py +436 -282
- beratools/tools/line_footprint_functions.py +733 -720
- beratools/tools/line_footprint_relative.py +73 -64
- beratools/tools/line_grouping.py +45 -0
- beratools/tools/ln_relative_metrics.py +615 -615
- beratools/tools/r_cal_lpi_elai.r +24 -24
- beratools/tools/r_generate_pd_focalraster.r +100 -100
- beratools/tools/r_interface.py +79 -79
- beratools/tools/r_point_density.r +8 -8
- beratools/tools/rpy_chm2trees.py +86 -86
- beratools/tools/rpy_dsm_chm_by.py +81 -81
- beratools/tools/rpy_dtm_by.py +63 -63
- beratools/tools/rpy_find_cellsize.py +43 -43
- beratools/tools/rpy_gnd_csf.py +74 -74
- beratools/tools/rpy_hummock_hollow.py +85 -85
- beratools/tools/rpy_hummock_hollow_raster.py +71 -71
- beratools/tools/rpy_las_info.py +51 -51
- beratools/tools/rpy_laz2las.py +40 -40
- beratools/tools/rpy_lpi_elai_lascat.py +466 -466
- beratools/tools/rpy_normalized_lidar_by.py +56 -56
- beratools/tools/rpy_percent_above_dbh.py +80 -80
- beratools/tools/rpy_points2trees.py +88 -88
- beratools/tools/rpy_vegcoverage.py +94 -94
- beratools/tools/tiler.py +48 -206
- beratools/tools/tool_template.py +69 -54
- beratools/tools/vertex_optimization.py +61 -620
- beratools/tools/zonal_threshold.py +144 -144
- beratools-0.2.2.dist-info/METADATA +108 -0
- beratools-0.2.2.dist-info/RECORD +74 -0
- {beratools-0.2.0.dist-info → beratools-0.2.2.dist-info}/WHEEL +1 -1
- {beratools-0.2.0.dist-info → beratools-0.2.2.dist-info}/licenses/LICENSE +22 -22
- beratools/gui/cli.py +0 -18
- beratools/gui/gui.json +0 -8
- beratools/gui_tk/ASCII Banners.txt +0 -248
- beratools/gui_tk/__init__.py +0 -20
- beratools/gui_tk/beratools_main.py +0 -515
- beratools/gui_tk/bt_widgets.py +0 -442
- beratools/gui_tk/cli.py +0 -18
- beratools/gui_tk/img/BERALogo.png +0 -0
- beratools/gui_tk/img/closed.gif +0 -0
- beratools/gui_tk/img/closed.png +0 -0
- beratools/gui_tk/img/open.gif +0 -0
- beratools/gui_tk/img/open.png +0 -0
- beratools/gui_tk/img/tool.gif +0 -0
- beratools/gui_tk/img/tool.png +0 -0
- beratools/gui_tk/main.py +0 -14
- beratools/gui_tk/map_window.py +0 -144
- beratools/gui_tk/runner.py +0 -1481
- beratools/gui_tk/tooltip.py +0 -55
- beratools/third_party/pyqtlet2/__init__.py +0 -9
- beratools/third_party/pyqtlet2/leaflet/__init__.py +0 -26
- beratools/third_party/pyqtlet2/leaflet/control/__init__.py +0 -6
- beratools/third_party/pyqtlet2/leaflet/control/control.py +0 -59
- beratools/third_party/pyqtlet2/leaflet/control/draw.py +0 -52
- beratools/third_party/pyqtlet2/leaflet/control/layers.py +0 -20
- beratools/third_party/pyqtlet2/leaflet/core/Parser.py +0 -24
- beratools/third_party/pyqtlet2/leaflet/core/__init__.py +0 -2
- beratools/third_party/pyqtlet2/leaflet/core/evented.py +0 -180
- beratools/third_party/pyqtlet2/leaflet/layer/__init__.py +0 -5
- beratools/third_party/pyqtlet2/leaflet/layer/featuregroup.py +0 -34
- beratools/third_party/pyqtlet2/leaflet/layer/icon/__init__.py +0 -1
- beratools/third_party/pyqtlet2/leaflet/layer/icon/icon.py +0 -30
- beratools/third_party/pyqtlet2/leaflet/layer/imageoverlay.py +0 -18
- beratools/third_party/pyqtlet2/leaflet/layer/layer.py +0 -105
- beratools/third_party/pyqtlet2/leaflet/layer/layergroup.py +0 -45
- beratools/third_party/pyqtlet2/leaflet/layer/marker/__init__.py +0 -1
- beratools/third_party/pyqtlet2/leaflet/layer/marker/marker.py +0 -91
- beratools/third_party/pyqtlet2/leaflet/layer/tile/__init__.py +0 -2
- beratools/third_party/pyqtlet2/leaflet/layer/tile/gridlayer.py +0 -4
- beratools/third_party/pyqtlet2/leaflet/layer/tile/tilelayer.py +0 -16
- beratools/third_party/pyqtlet2/leaflet/layer/vector/__init__.py +0 -5
- beratools/third_party/pyqtlet2/leaflet/layer/vector/circle.py +0 -15
- beratools/third_party/pyqtlet2/leaflet/layer/vector/circlemarker.py +0 -18
- beratools/third_party/pyqtlet2/leaflet/layer/vector/path.py +0 -5
- beratools/third_party/pyqtlet2/leaflet/layer/vector/polygon.py +0 -14
- beratools/third_party/pyqtlet2/leaflet/layer/vector/polyline.py +0 -18
- beratools/third_party/pyqtlet2/leaflet/layer/vector/rectangle.py +0 -14
- beratools/third_party/pyqtlet2/leaflet/map/__init__.py +0 -1
- beratools/third_party/pyqtlet2/leaflet/map/map.py +0 -220
- beratools/third_party/pyqtlet2/mapwidget.py +0 -45
- beratools/third_party/pyqtlet2/web/custom.js +0 -43
- beratools/third_party/pyqtlet2/web/map.html +0 -23
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-shadow.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.css +0 -656
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.js +0 -6
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.codeclimate.yml +0 -14
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.editorconfig +0 -4
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.gitattributes +0 -22
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.travis.yml +0 -43
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/LICENSE +0 -20
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-shadow.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.svg +0 -156
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.css +0 -10
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.js +0 -10
- beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/LICENSE +0 -22
- beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/leaflet.rotatedMarker.js +0 -57
- beratools/tools/forest_line_ecosite.py +0 -216
- beratools/tools/lapis_all.py +0 -103
- beratools/tools/least_cost_path_from_chm.py +0 -152
- beratools-0.2.0.dist-info/METADATA +0 -63
- beratools-0.2.0.dist-info/RECORD +0 -142
- /beratools/gui/{img → assets}/BERALogo.png +0 -0
- /beratools/gui/{img → assets}/closed.gif +0 -0
- /beratools/gui/{img → assets}/closed.png +0 -0
- /beratools/{gui_tk → gui/assets}/gui.json +0 -0
- /beratools/gui/{img → assets}/open.gif +0 -0
- /beratools/gui/{img → assets}/open.png +0 -0
- /beratools/gui/{img → assets}/tool.gif +0 -0
- /beratools/gui/{img → assets}/tool.png +0 -0
- {beratools-0.2.0.dist-info → beratools-0.2.2.dist-info}/entry_points.txt +0 -0
beratools/tools/r_cal_lpi_elai.r
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
#create a 'rlpi_elai' function
|
|
2
|
-
library(terra)
|
|
3
|
-
|
|
4
|
-
rlpi_elai <- function(pdTotal, pdGround, radius, scan_angle, out_lpi, out_elai) {
|
|
5
|
-
|
|
6
|
-
total_focal <- rast(pdTotal)
|
|
7
|
-
ground_focal <- rast(pdGround)
|
|
8
|
-
|
|
9
|
-
# pdTotal_SpatRaster <- rast(pdTotal)Aug 24
|
|
10
|
-
# pdGround_SpatRaster <- rast(pdGround)
|
|
11
|
-
ground_focal <- extend(ground_focal, ext(total_focal))
|
|
12
|
-
|
|
13
|
-
# lpi
|
|
14
|
-
lpi = ground_focal / total_focal
|
|
15
|
-
#lpi
|
|
16
|
-
lpi[is.infinite(lpi)] = NA
|
|
17
|
-
|
|
18
|
-
elai = -cos(((scan_angle / 2.0) / 180) * pi) / 0.5 * log(lpi)
|
|
19
|
-
elai[is.infinite(elai)] = NA
|
|
20
|
-
elai[elai == 0 | elai == -0] = 0
|
|
21
|
-
|
|
22
|
-
writeRaster(lpi, out_lpi, overwrite = TRUE)
|
|
23
|
-
writeRaster(elai, out_elai, overwrite = TRUE)
|
|
24
|
-
|
|
1
|
+
#create a 'rlpi_elai' function
|
|
2
|
+
library(terra)
|
|
3
|
+
|
|
4
|
+
rlpi_elai <- function(pdTotal, pdGround, radius, scan_angle, out_lpi, out_elai) {
|
|
5
|
+
|
|
6
|
+
total_focal <- rast(pdTotal)
|
|
7
|
+
ground_focal <- rast(pdGround)
|
|
8
|
+
|
|
9
|
+
# pdTotal_SpatRaster <- rast(pdTotal)Aug 24
|
|
10
|
+
# pdGround_SpatRaster <- rast(pdGround)
|
|
11
|
+
ground_focal <- extend(ground_focal, ext(total_focal))
|
|
12
|
+
|
|
13
|
+
# lpi
|
|
14
|
+
lpi = ground_focal / total_focal
|
|
15
|
+
#lpi
|
|
16
|
+
lpi[is.infinite(lpi)] = NA
|
|
17
|
+
|
|
18
|
+
elai = -cos(((scan_angle / 2.0) / 180) * pi) / 0.5 * log(lpi)
|
|
19
|
+
elai[is.infinite(elai)] = NA
|
|
20
|
+
elai[elai == 0 | elai == -0] = 0
|
|
21
|
+
|
|
22
|
+
writeRaster(lpi, out_lpi, overwrite = TRUE)
|
|
23
|
+
writeRaster(elai, out_elai, overwrite = TRUE)
|
|
24
|
+
|
|
25
25
|
}
|
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
#create a 'generate_pd' function
|
|
2
|
-
generate_pd <- function(ctg, radius_fr_CHM, focal_radius, cell_size, cache_folder,
|
|
3
|
-
cut_ht, PD_Ground_folder, PD_Total_folder, rprocesses) {
|
|
4
|
-
library(terra)
|
|
5
|
-
library(lidR)
|
|
6
|
-
|
|
7
|
-
plan(multisession, workers = rprocesses)
|
|
8
|
-
set_lidr_threads(rprocesses)
|
|
9
|
-
|
|
10
|
-
opts <- paste0("-drop_class 7")
|
|
11
|
-
|
|
12
|
-
print("Processing using R packages.")
|
|
13
|
-
|
|
14
|
-
folder <- paste0(cache_folder, "/nlidar/n_{*}")
|
|
15
|
-
opt_output_files(ctg) <- opt_output_files(ctg) <- folder
|
|
16
|
-
opt_laz_compression(ctg) <- FALSE
|
|
17
|
-
opt_filter(ctg) <- "-drop_class 7"
|
|
18
|
-
opt_chunk_alignment(ctg) <- c(0, 0)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
#normalized LAS with pulse info
|
|
22
|
-
print("Indexing LAS Tiles ...")
|
|
23
|
-
lidR:::catalog_laxindex(ctg)
|
|
24
|
-
print("Normalize point cloud using K-nearest neighbour IDW ...")
|
|
25
|
-
normalize_height(ctg, algorithm = knnidw())
|
|
26
|
-
|
|
27
|
-
print("Generating point density (total focal sum) raster ...")
|
|
28
|
-
|
|
29
|
-
pd_total <- function(chunk, radius, cell_size)
|
|
30
|
-
{
|
|
31
|
-
las <- readLAS(chunk)
|
|
32
|
-
if (is.empty(las)) return(NULL)
|
|
33
|
-
|
|
34
|
-
las_1 <- filter_poi(readLAS(chunk), buffer == 0)
|
|
35
|
-
hull <- st_convex_hull(las_1)
|
|
36
|
-
# bbox <- ext(las_1)
|
|
37
|
-
|
|
38
|
-
# convert to SpatialPolygons
|
|
39
|
-
bbox <- vect(hull)
|
|
40
|
-
|
|
41
|
-
las <- filter_poi(las, Classification != 7L)
|
|
42
|
-
#las <- retrieve_pulses(las)
|
|
43
|
-
density_raster_total <- rasterize_density(las, res = cell_size, pkg = "terra")[[1]]
|
|
44
|
-
|
|
45
|
-
tfw <- focalMat(density_raster_total, radius, "circle")
|
|
46
|
-
|
|
47
|
-
tfw[tfw > 0] = 1
|
|
48
|
-
tfw[tfw == 0] = NA
|
|
49
|
-
|
|
50
|
-
Total_focal <- focal(density_raster_total, w = tfw, fun = "sum", na.rm = TRUE, na.policy = "omit", fillvalue = NA, expand = FALSE)
|
|
51
|
-
Total_focal <- crop(Total_focal, bbox)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
opt <- list(need_output_file =TRUE, autocrop = TRUE)
|
|
55
|
-
opt_chunk_alignment(ctg) <- c(0,0)
|
|
56
|
-
ctg@output_options$drivers$SpatRaster$param$overwrite <- TRUE
|
|
57
|
-
opt_output_files(ctg) <- paste0(PD_Total_folder,"/{*}_PD_Tfocalsum")
|
|
58
|
-
opt_stop_early(ctg) <- FALSE
|
|
59
|
-
catalog_apply(ctg, pd_total, radius = focal_radius, cell_size = cell_size, .options = opt)
|
|
60
|
-
|
|
61
|
-
#load normalized LAS for ground point density
|
|
62
|
-
ht <- paste0("-drop_class 7 -drop_z_above ", cut_ht)
|
|
63
|
-
ctg2 <- readLAScatalog(paste0(cache_folder, "/nlidar"), filter = ht)
|
|
64
|
-
lidR:::catalog_laxindex(ctg2)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
print("Generating point density (ground focal sum) raster ...")
|
|
68
|
-
|
|
69
|
-
pd_ground <- function(chunk, radius, cell_size, cut_ht)
|
|
70
|
-
{
|
|
71
|
-
las <- readLAS(chunk)
|
|
72
|
-
if (is.empty(las)) return(NULL)
|
|
73
|
-
|
|
74
|
-
las_1 <- filter_poi(readLAS(chunk), buffer == 0)
|
|
75
|
-
hull <- st_convex_hull(las_1)
|
|
76
|
-
|
|
77
|
-
# convert to SpatialPolygons
|
|
78
|
-
bbox <- vect(hull)
|
|
79
|
-
# bbox <- ext(las_1)
|
|
80
|
-
|
|
81
|
-
#las <- retrieve_pulses(las)
|
|
82
|
-
density_raster_ground <- rasterize_density(las, res = cell_size, pkg = "terra")[[1]]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
gfw <- focalMat(density_raster_ground, radius, "circle")
|
|
86
|
-
gfw[gfw > 0] = 1
|
|
87
|
-
gfw[gfw == 0] = NA
|
|
88
|
-
|
|
89
|
-
Ground_focal <- focal(density_raster_ground, w = gfw, fun = "sum", na.policy = "omit", na.rm = TRUE, fillvalue = NA, expand = FALSE)
|
|
90
|
-
ground_focal <- crop(Ground_focal, bbox)
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
opt <- list(need_output_file =TRUE, autocrop = TRUE)
|
|
94
|
-
opt_chunk_alignment(ctg2) <- c(0,0)
|
|
95
|
-
ctg2@output_options$drivers$SpatRaster$param$overwrite <- TRUE
|
|
96
|
-
opt_output_files(ctg2) <- paste0(PD_Ground_folder,"/{*}_PD_Gfocalsum")
|
|
97
|
-
opt_stop_early(ctg2) <- FALSE
|
|
98
|
-
catalog_apply(ctg2, pd_ground,radius=focal_radius,cell_size=cell_size,cut_ht=cut_ht,.options=opt)
|
|
99
|
-
# reset R mutilsession back to default
|
|
100
|
-
plan("default")
|
|
1
|
+
#create a 'generate_pd' function
|
|
2
|
+
generate_pd <- function(ctg, radius_fr_CHM, focal_radius, cell_size, cache_folder,
|
|
3
|
+
cut_ht, PD_Ground_folder, PD_Total_folder, rprocesses) {
|
|
4
|
+
library(terra)
|
|
5
|
+
library(lidR)
|
|
6
|
+
|
|
7
|
+
plan(multisession, workers = rprocesses)
|
|
8
|
+
set_lidr_threads(rprocesses)
|
|
9
|
+
|
|
10
|
+
opts <- paste0("-drop_class 7")
|
|
11
|
+
|
|
12
|
+
print("Processing using R packages.")
|
|
13
|
+
|
|
14
|
+
folder <- paste0(cache_folder, "/nlidar/n_{*}")
|
|
15
|
+
opt_output_files(ctg) <- opt_output_files(ctg) <- folder
|
|
16
|
+
opt_laz_compression(ctg) <- FALSE
|
|
17
|
+
opt_filter(ctg) <- "-drop_class 7"
|
|
18
|
+
opt_chunk_alignment(ctg) <- c(0, 0)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
#normalized LAS with pulse info
|
|
22
|
+
print("Indexing LAS Tiles ...")
|
|
23
|
+
lidR:::catalog_laxindex(ctg)
|
|
24
|
+
print("Normalize point cloud using K-nearest neighbour IDW ...")
|
|
25
|
+
normalize_height(ctg, algorithm = knnidw())
|
|
26
|
+
|
|
27
|
+
print("Generating point density (total focal sum) raster ...")
|
|
28
|
+
|
|
29
|
+
pd_total <- function(chunk, radius, cell_size)
|
|
30
|
+
{
|
|
31
|
+
las <- readLAS(chunk)
|
|
32
|
+
if (is.empty(las)) return(NULL)
|
|
33
|
+
|
|
34
|
+
las_1 <- filter_poi(readLAS(chunk), buffer == 0)
|
|
35
|
+
hull <- st_convex_hull(las_1)
|
|
36
|
+
# bbox <- ext(las_1)
|
|
37
|
+
|
|
38
|
+
# convert to SpatialPolygons
|
|
39
|
+
bbox <- vect(hull)
|
|
40
|
+
|
|
41
|
+
las <- filter_poi(las, Classification != 7L)
|
|
42
|
+
#las <- retrieve_pulses(las)
|
|
43
|
+
density_raster_total <- rasterize_density(las, res = cell_size, pkg = "terra")[[1]]
|
|
44
|
+
|
|
45
|
+
tfw <- focalMat(density_raster_total, radius, "circle")
|
|
46
|
+
|
|
47
|
+
tfw[tfw > 0] = 1
|
|
48
|
+
tfw[tfw == 0] = NA
|
|
49
|
+
|
|
50
|
+
Total_focal <- focal(density_raster_total, w = tfw, fun = "sum", na.rm = TRUE, na.policy = "omit", fillvalue = NA, expand = FALSE)
|
|
51
|
+
Total_focal <- crop(Total_focal, bbox)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
opt <- list(need_output_file =TRUE, autocrop = TRUE)
|
|
55
|
+
opt_chunk_alignment(ctg) <- c(0,0)
|
|
56
|
+
ctg@output_options$drivers$SpatRaster$param$overwrite <- TRUE
|
|
57
|
+
opt_output_files(ctg) <- paste0(PD_Total_folder,"/{*}_PD_Tfocalsum")
|
|
58
|
+
opt_stop_early(ctg) <- FALSE
|
|
59
|
+
catalog_apply(ctg, pd_total, radius = focal_radius, cell_size = cell_size, .options = opt)
|
|
60
|
+
|
|
61
|
+
#load normalized LAS for ground point density
|
|
62
|
+
ht <- paste0("-drop_class 7 -drop_z_above ", cut_ht)
|
|
63
|
+
ctg2 <- readLAScatalog(paste0(cache_folder, "/nlidar"), filter = ht)
|
|
64
|
+
lidR:::catalog_laxindex(ctg2)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
print("Generating point density (ground focal sum) raster ...")
|
|
68
|
+
|
|
69
|
+
pd_ground <- function(chunk, radius, cell_size, cut_ht)
|
|
70
|
+
{
|
|
71
|
+
las <- readLAS(chunk)
|
|
72
|
+
if (is.empty(las)) return(NULL)
|
|
73
|
+
|
|
74
|
+
las_1 <- filter_poi(readLAS(chunk), buffer == 0)
|
|
75
|
+
hull <- st_convex_hull(las_1)
|
|
76
|
+
|
|
77
|
+
# convert to SpatialPolygons
|
|
78
|
+
bbox <- vect(hull)
|
|
79
|
+
# bbox <- ext(las_1)
|
|
80
|
+
|
|
81
|
+
#las <- retrieve_pulses(las)
|
|
82
|
+
density_raster_ground <- rasterize_density(las, res = cell_size, pkg = "terra")[[1]]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
gfw <- focalMat(density_raster_ground, radius, "circle")
|
|
86
|
+
gfw[gfw > 0] = 1
|
|
87
|
+
gfw[gfw == 0] = NA
|
|
88
|
+
|
|
89
|
+
Ground_focal <- focal(density_raster_ground, w = gfw, fun = "sum", na.policy = "omit", na.rm = TRUE, fillvalue = NA, expand = FALSE)
|
|
90
|
+
ground_focal <- crop(Ground_focal, bbox)
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
opt <- list(need_output_file =TRUE, autocrop = TRUE)
|
|
94
|
+
opt_chunk_alignment(ctg2) <- c(0,0)
|
|
95
|
+
ctg2@output_options$drivers$SpatRaster$param$overwrite <- TRUE
|
|
96
|
+
opt_output_files(ctg2) <- paste0(PD_Ground_folder,"/{*}_PD_Gfocalsum")
|
|
97
|
+
opt_stop_early(ctg2) <- FALSE
|
|
98
|
+
catalog_apply(ctg2, pd_ground,radius=focal_radius,cell_size=cell_size,cut_ht=cut_ht,.options=opt)
|
|
99
|
+
# reset R mutilsession back to default
|
|
100
|
+
plan("default")
|
|
101
101
|
}
|
beratools/tools/r_interface.py
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import psutil
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# def check_r_env():
|
|
6
|
-
try: # integrated R env
|
|
7
|
-
# check R language within env
|
|
8
|
-
current_env_path = os.environ['CONDA_PREFIX']
|
|
9
|
-
# if os.path.isdir(current_env_path):
|
|
10
|
-
os.environ['R_HOME'] = os.path.join(current_env_path, r"Lib\R")
|
|
11
|
-
os.environ['R_USER'] = os.path.expanduser('~')
|
|
12
|
-
os.environ['R_LIBS_USER'] = os.path.join(current_env_path, r"Lib\R\library")
|
|
13
|
-
|
|
14
|
-
except FileNotFoundError:
|
|
15
|
-
print("Warning: Please install R for this process!!")
|
|
16
|
-
exit()
|
|
17
|
-
|
|
18
|
-
import rpy2.robjects as robjects
|
|
19
|
-
from rpy2.robjects.packages import importr, data
|
|
20
|
-
from rpy2.robjects.vectors import StrVector
|
|
21
|
-
|
|
22
|
-
r = robjects.r
|
|
23
|
-
|
|
24
|
-
def r_processes(processes):
|
|
25
|
-
stats = psutil.virtual_memory() # returns a named tuple
|
|
26
|
-
available = getattr(stats, 'available') / 1024000000
|
|
27
|
-
rprocesses = processes
|
|
28
|
-
|
|
29
|
-
if 2 < processes <= 8:
|
|
30
|
-
if available <= 50:
|
|
31
|
-
rprocesses = 2
|
|
32
|
-
elif 50 < available <= 150:
|
|
33
|
-
rprocesses = 4
|
|
34
|
-
elif 150 < available <= 250:
|
|
35
|
-
rprocesses = 8
|
|
36
|
-
else:
|
|
37
|
-
rprocesses = 8
|
|
38
|
-
|
|
39
|
-
return rprocesses
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def check_las_files_existence(folder):
|
|
43
|
-
if not os.path.exists(folder):
|
|
44
|
-
print("Error! Cannot locate Las folder, please check.")
|
|
45
|
-
exit()
|
|
46
|
-
else:
|
|
47
|
-
found = False
|
|
48
|
-
for files in os.listdir(folder):
|
|
49
|
-
if files.endswith(".las") or files.endswith(".laz"):
|
|
50
|
-
found = True
|
|
51
|
-
break
|
|
52
|
-
if not found:
|
|
53
|
-
print("Error! Cannot locate input LAS file(s), please check!")
|
|
54
|
-
exit()
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def check_r_packages_installation(packages):
|
|
58
|
-
utils = importr('utils')
|
|
59
|
-
base = importr('base')
|
|
60
|
-
utils.chooseCRANmirror(ind=12) # select the 12th mirror in the list: Canada
|
|
61
|
-
print("Checking R packages....")
|
|
62
|
-
|
|
63
|
-
cran_names_to_install = [x for x in packages if not robjects.packages.isinstalled(x)]
|
|
64
|
-
need_fasterRaster = False
|
|
65
|
-
if len(cran_names_to_install) > 0:
|
|
66
|
-
if not 'fasterRaster' in cran_names_to_install:
|
|
67
|
-
utils.install_packages(StrVector(cran_names_to_install))
|
|
68
|
-
else:
|
|
69
|
-
cran_names_to_install.remove('fasterRaster')
|
|
70
|
-
need_fasterRaster = True
|
|
71
|
-
utils.install_packages(StrVector(cran_names_to_install))
|
|
72
|
-
packages_found = True
|
|
73
|
-
else:
|
|
74
|
-
packages_found = True
|
|
75
|
-
|
|
76
|
-
if need_fasterRaster:
|
|
77
|
-
devtools=importr('devtools')
|
|
78
|
-
devtools.install_github("adamlilith/fasterRaster", dependencies=True)
|
|
79
|
-
|
|
1
|
+
import os
|
|
2
|
+
import psutil
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# def check_r_env():
|
|
6
|
+
try: # integrated R env
|
|
7
|
+
# check R language within env
|
|
8
|
+
current_env_path = os.environ['CONDA_PREFIX']
|
|
9
|
+
# if os.path.isdir(current_env_path):
|
|
10
|
+
os.environ['R_HOME'] = os.path.join(current_env_path, r"Lib\R")
|
|
11
|
+
os.environ['R_USER'] = os.path.expanduser('~')
|
|
12
|
+
os.environ['R_LIBS_USER'] = os.path.join(current_env_path, r"Lib\R\library")
|
|
13
|
+
|
|
14
|
+
except FileNotFoundError:
|
|
15
|
+
print("Warning: Please install R for this process!!")
|
|
16
|
+
exit()
|
|
17
|
+
|
|
18
|
+
import rpy2.robjects as robjects
|
|
19
|
+
from rpy2.robjects.packages import importr, data
|
|
20
|
+
from rpy2.robjects.vectors import StrVector
|
|
21
|
+
|
|
22
|
+
r = robjects.r
|
|
23
|
+
|
|
24
|
+
def r_processes(processes):
|
|
25
|
+
stats = psutil.virtual_memory() # returns a named tuple
|
|
26
|
+
available = getattr(stats, 'available') / 1024000000
|
|
27
|
+
rprocesses = processes
|
|
28
|
+
|
|
29
|
+
if 2 < processes <= 8:
|
|
30
|
+
if available <= 50:
|
|
31
|
+
rprocesses = 2
|
|
32
|
+
elif 50 < available <= 150:
|
|
33
|
+
rprocesses = 4
|
|
34
|
+
elif 150 < available <= 250:
|
|
35
|
+
rprocesses = 8
|
|
36
|
+
else:
|
|
37
|
+
rprocesses = 8
|
|
38
|
+
|
|
39
|
+
return rprocesses
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def check_las_files_existence(folder):
|
|
43
|
+
if not os.path.exists(folder):
|
|
44
|
+
print("Error! Cannot locate Las folder, please check.")
|
|
45
|
+
exit()
|
|
46
|
+
else:
|
|
47
|
+
found = False
|
|
48
|
+
for files in os.listdir(folder):
|
|
49
|
+
if files.endswith(".las") or files.endswith(".laz"):
|
|
50
|
+
found = True
|
|
51
|
+
break
|
|
52
|
+
if not found:
|
|
53
|
+
print("Error! Cannot locate input LAS file(s), please check!")
|
|
54
|
+
exit()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def check_r_packages_installation(packages):
|
|
58
|
+
utils = importr('utils')
|
|
59
|
+
base = importr('base')
|
|
60
|
+
utils.chooseCRANmirror(ind=12) # select the 12th mirror in the list: Canada
|
|
61
|
+
print("Checking R packages....")
|
|
62
|
+
|
|
63
|
+
cran_names_to_install = [x for x in packages if not robjects.packages.isinstalled(x)]
|
|
64
|
+
need_fasterRaster = False
|
|
65
|
+
if len(cran_names_to_install) > 0:
|
|
66
|
+
if not 'fasterRaster' in cran_names_to_install:
|
|
67
|
+
utils.install_packages(StrVector(cran_names_to_install))
|
|
68
|
+
else:
|
|
69
|
+
cran_names_to_install.remove('fasterRaster')
|
|
70
|
+
need_fasterRaster = True
|
|
71
|
+
utils.install_packages(StrVector(cran_names_to_install))
|
|
72
|
+
packages_found = True
|
|
73
|
+
else:
|
|
74
|
+
packages_found = True
|
|
75
|
+
|
|
76
|
+
if need_fasterRaster:
|
|
77
|
+
devtools=importr('devtools')
|
|
78
|
+
devtools.install_github("adamlilith/fasterRaster", dependencies=True)
|
|
79
|
+
|
|
80
80
|
print("Checking R packages....Done")
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
pd_routine <- function(chunk) {
|
|
2
|
-
las <- readLAS(chunk)
|
|
3
|
-
|
|
4
|
-
if (is.empty(las)) return(NULL)
|
|
5
|
-
las <- retrieve_pulses(las)
|
|
6
|
-
output <- density(las)[1]
|
|
7
|
-
# output is a list
|
|
8
|
-
return(list(output))
|
|
1
|
+
pd_routine <- function(chunk) {
|
|
2
|
+
las <- readLAS(chunk)
|
|
3
|
+
|
|
4
|
+
if (is.empty(las)) return(NULL)
|
|
5
|
+
las <- retrieve_pulses(las)
|
|
6
|
+
output <- density(las)[1]
|
|
7
|
+
# output is a list
|
|
8
|
+
return(list(output))
|
|
9
9
|
}
|
beratools/tools/rpy_chm2trees.py
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import time
|
|
3
|
-
from multiprocessing.pool import Pool
|
|
4
|
-
|
|
5
|
-
from beratools.tools.common import *
|
|
6
|
-
from beratools.tools.r_interface import *
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def chm2trees(callback, in_chm_folder, Min_ws, hmin, out_folder, processes, verbose):
|
|
10
|
-
rprocesses = r_processes(processes)
|
|
11
|
-
|
|
12
|
-
# assign R script file to local variable
|
|
13
|
-
Beratools_R_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Beratools_r_script.r')
|
|
14
|
-
# Defining the R script and loading the instance in Python
|
|
15
|
-
r['source'](Beratools_R_script)
|
|
16
|
-
# Loading the function defined in R script.
|
|
17
|
-
r_chm2trees = robjects.globalenv['chm2trees']
|
|
18
|
-
|
|
19
|
-
args_list = []
|
|
20
|
-
for root, dirs, files in sorted(os.walk(in_chm_folder)):
|
|
21
|
-
for file in files:
|
|
22
|
-
if file.endswith(".tif"):
|
|
23
|
-
result = []
|
|
24
|
-
chm_file = os.path.join(root, file)
|
|
25
|
-
chm_file = chm_file.replace("\\", "/")
|
|
26
|
-
result.append(chm_file)
|
|
27
|
-
result.append(Min_ws)
|
|
28
|
-
result.append(hmin)
|
|
29
|
-
result.append(out_folder)
|
|
30
|
-
result.append(rprocesses)
|
|
31
|
-
args_list.append(result)
|
|
32
|
-
# Invoking the R function
|
|
33
|
-
r_chm2trees(chm_file, Min_ws, hmin, out_folder, rprocesses)
|
|
34
|
-
|
|
35
|
-
del root, dirs, files
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if __name__ == '__main__':
|
|
39
|
-
start_time = time.time()
|
|
40
|
-
print('Starting tree detection from CHM processing\n @ {}'
|
|
41
|
-
.format(time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())))
|
|
42
|
-
|
|
43
|
-
packages = ['lidR', 'rgrass', 'rlas', 'future', 'terra']
|
|
44
|
-
check_r_packages_installation(packages)
|
|
45
|
-
|
|
46
|
-
print("Checking input parameters....")
|
|
47
|
-
in_args, in_verbose = check_arguments()
|
|
48
|
-
in_chm_folder = in_args.input["in_chm_folder"]
|
|
49
|
-
try:
|
|
50
|
-
ws = float(in_args.input["Min_ws"])
|
|
51
|
-
in_args.input["Min_ws"] = ws
|
|
52
|
-
except ValueError:
|
|
53
|
-
print("Invalid input of circular diameter, default is used")
|
|
54
|
-
in_args.input["Min_ws"] = 2.5
|
|
55
|
-
try:
|
|
56
|
-
hmin = float(in_args.input["hmin"])
|
|
57
|
-
in_args.input["hmin"] = hmin
|
|
58
|
-
except ValueError:
|
|
59
|
-
print("Invalid input of minimum height of a tree, default is used")
|
|
60
|
-
in_args.input["hmin"] = 3.0
|
|
61
|
-
|
|
62
|
-
out_folder = in_args.input["out_folder"]
|
|
63
|
-
|
|
64
|
-
if not os.path.exists(in_chm_folder):
|
|
65
|
-
print("Error! Cannot locate CHM raster folder, please check.")
|
|
66
|
-
exit()
|
|
67
|
-
else:
|
|
68
|
-
found = False
|
|
69
|
-
for files in os.listdir(in_chm_folder):
|
|
70
|
-
if files.endswith(".tif"):
|
|
71
|
-
found = True
|
|
72
|
-
break
|
|
73
|
-
if not found:
|
|
74
|
-
print("Error! Cannot locate input CHM raster file(s), please check!")
|
|
75
|
-
exit()
|
|
76
|
-
|
|
77
|
-
if not os.path.exists(out_folder):
|
|
78
|
-
print("Warning! Cannot locate output folder, It will be created.")
|
|
79
|
-
os.makedirs(out_folder)
|
|
80
|
-
|
|
81
|
-
print("Checking input parameters....Done")
|
|
82
|
-
|
|
83
|
-
chm2trees(print, **in_args.input, processes=int(in_args.processes), verbose=in_verbose)
|
|
84
|
-
|
|
85
|
-
print('Tree detection from CHM raster data processing is done in {} seconds)'
|
|
86
|
-
.format(round(time.time() - start_time, 5)))
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
from multiprocessing.pool import Pool
|
|
4
|
+
|
|
5
|
+
from beratools.tools.common import *
|
|
6
|
+
from beratools.tools.r_interface import *
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def chm2trees(callback, in_chm_folder, Min_ws, hmin, out_folder, processes, verbose):
|
|
10
|
+
rprocesses = r_processes(processes)
|
|
11
|
+
|
|
12
|
+
# assign R script file to local variable
|
|
13
|
+
Beratools_R_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Beratools_r_script.r')
|
|
14
|
+
# Defining the R script and loading the instance in Python
|
|
15
|
+
r['source'](Beratools_R_script)
|
|
16
|
+
# Loading the function defined in R script.
|
|
17
|
+
r_chm2trees = robjects.globalenv['chm2trees']
|
|
18
|
+
|
|
19
|
+
args_list = []
|
|
20
|
+
for root, dirs, files in sorted(os.walk(in_chm_folder)):
|
|
21
|
+
for file in files:
|
|
22
|
+
if file.endswith(".tif"):
|
|
23
|
+
result = []
|
|
24
|
+
chm_file = os.path.join(root, file)
|
|
25
|
+
chm_file = chm_file.replace("\\", "/")
|
|
26
|
+
result.append(chm_file)
|
|
27
|
+
result.append(Min_ws)
|
|
28
|
+
result.append(hmin)
|
|
29
|
+
result.append(out_folder)
|
|
30
|
+
result.append(rprocesses)
|
|
31
|
+
args_list.append(result)
|
|
32
|
+
# Invoking the R function
|
|
33
|
+
r_chm2trees(chm_file, Min_ws, hmin, out_folder, rprocesses)
|
|
34
|
+
|
|
35
|
+
del root, dirs, files
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == '__main__':
|
|
39
|
+
start_time = time.time()
|
|
40
|
+
print('Starting tree detection from CHM processing\n @ {}'
|
|
41
|
+
.format(time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())))
|
|
42
|
+
|
|
43
|
+
packages = ['lidR', 'rgrass', 'rlas', 'future', 'terra']
|
|
44
|
+
check_r_packages_installation(packages)
|
|
45
|
+
|
|
46
|
+
print("Checking input parameters....")
|
|
47
|
+
in_args, in_verbose = check_arguments()
|
|
48
|
+
in_chm_folder = in_args.input["in_chm_folder"]
|
|
49
|
+
try:
|
|
50
|
+
ws = float(in_args.input["Min_ws"])
|
|
51
|
+
in_args.input["Min_ws"] = ws
|
|
52
|
+
except ValueError:
|
|
53
|
+
print("Invalid input of circular diameter, default is used")
|
|
54
|
+
in_args.input["Min_ws"] = 2.5
|
|
55
|
+
try:
|
|
56
|
+
hmin = float(in_args.input["hmin"])
|
|
57
|
+
in_args.input["hmin"] = hmin
|
|
58
|
+
except ValueError:
|
|
59
|
+
print("Invalid input of minimum height of a tree, default is used")
|
|
60
|
+
in_args.input["hmin"] = 3.0
|
|
61
|
+
|
|
62
|
+
out_folder = in_args.input["out_folder"]
|
|
63
|
+
|
|
64
|
+
if not os.path.exists(in_chm_folder):
|
|
65
|
+
print("Error! Cannot locate CHM raster folder, please check.")
|
|
66
|
+
exit()
|
|
67
|
+
else:
|
|
68
|
+
found = False
|
|
69
|
+
for files in os.listdir(in_chm_folder):
|
|
70
|
+
if files.endswith(".tif"):
|
|
71
|
+
found = True
|
|
72
|
+
break
|
|
73
|
+
if not found:
|
|
74
|
+
print("Error! Cannot locate input CHM raster file(s), please check!")
|
|
75
|
+
exit()
|
|
76
|
+
|
|
77
|
+
if not os.path.exists(out_folder):
|
|
78
|
+
print("Warning! Cannot locate output folder, It will be created.")
|
|
79
|
+
os.makedirs(out_folder)
|
|
80
|
+
|
|
81
|
+
print("Checking input parameters....Done")
|
|
82
|
+
|
|
83
|
+
chm2trees(print, **in_args.input, processes=int(in_args.processes), verbose=in_verbose)
|
|
84
|
+
|
|
85
|
+
print('Tree detection from CHM raster data processing is done in {} seconds)'
|
|
86
|
+
.format(round(time.time() - start_time, 5)))
|