r-lidar / lidR

Airborne LiDAR data manipulation and visualisation for forestry application
https://CRAN.R-project.org/package=lidR
GNU General Public License v3.0
587 stars 132 forks source link

Normalizing clip_circle output files give square instead of circular plots as output #648

Closed towidoei closed 1 year ago

towidoei commented 1 year ago

I am working on a project in which I need to export plots with a 5m diameter around a coordinate, from a LiDAR pointcloud. This is done 750 times (that's the amount of coordinates I have). This will give me 750 individual circular las files (see picture attached). After doing this these plots need to be normalized, I did this by using the normalize_height function. This all works however the output files from this are square instead of circular (while the input files are circular too).

I am not sure if this is a bug or if I am doing something wrong, it would be great if someone can look at it! As seen in the pictures, the files do get normalized, however they turn into squares.

#save output from AHN4 1000x1000 clip to folder and start all filenames with "plot_"
lidR::opt_output_files(ahn4_tiling_1000) <- paste("~/metrics/clips/plot_{ID}")
#clip AHN4 1000x1000 tiles
export_lidr_1000 <- clip_circle(ahn4_tiling_1000, x, y, r)
x <- dfdata$x #refer to x column excel data
y <- dfdata$y #refer to y column excel data
r <- 5 #radius around coords

#### NORMALIZE LAS ###
#name the seperate las clips into one
las_clip <- lidR::catalog("/metrics/clips/")
#define output map for normalized las clips
lidR::opt_output_files(las_clip) <- paste("~/metrics/norm_clips/{ID}_norm")
#normalize las clips using K-nearest neighbour (knn)
las_norm <- normalize_height(las_clip, knnidw(k=10, p=2))

norm_individual_tile_1_test norm_individual_tile_1_test_square_cirkle plot_1_lidar_a

Jean-Romain commented 1 year ago

Creating a square from a circle means adding points out of nowhere. This is not possible. There is something else that you did not show me. Please produce a minimal reproducible example. The following MRE works as expected.

LASfile <- system.file("extdata", "Topography.laz", package="lidR")

# Load the file and clip the region of interest
las = readLAScatalog(LASfile)
opt_output_files(las) <- paste0(tempfile(), "_{ID}")
subset1 = clip_circle(las, 273500, 5274500, 20)

opt_output_files(subset1) <- paste0(tempdir(), "/{*}_norm")
nlas <- normalize_height(subset1, knnidw(k=10, p=2))

las1 = readLAS(subset1)
las2 = readLAS(nlas)

plot(las1, axis = T)
plot(las2, axis = T)

My guess is that you clipped rectangle files earlier and the files are still in /metrics/clips/. Instead of reading a folder you can simply use your variable export_lidr_1000 that is supposed to be correct.

towidoei commented 1 year ago

Hi Jean, Thanks for trying to help me. I simpled down the script and I think I have found the step where it goes wrong, but I still don't know why. When I load in a single round las cutout and normalize it, the output is what I expect (normalized round cutout).

When I do the same with the readLAScatalog function, it makes squares out of the plots (see picture attached from when I plot all the cutouts into a plot). After that, the output of the normalized las files looks like squares too.

I have added plot_1.las and plot_1_norm.las in a zip so you can run the script with these files too.

###Running this script on a single round las cutout (plot_1.las)
plot_1 <- lidR::readLAS("/Desktop/bruh/clips_5m/plot_1.las")
#works, gives round not-normalized las clip
lidR::plot(plot_1) 
#normalize plot_1
plot_1_normalized <- normalize_height(plot_1,knnidw(k=10,p=2))
#works, gives a normalized round las clip
plot(plot_1_normalized) 

###Running same script on readLAScatalog (combination of the round las cutouts (plot_1.las to plot_750.las))
ctg <- readLAScatalog("/Desktop/bruh/clips_5m/")
#plot looks like the cirles have become squares now (see picture attached)
lidR::plot(ctg) 

#normalize the lascatalog plots
opt_output_files(ctg) <- paste("/Desktop/bruh/clips_5m_norm/plot_{ID}_norm")
ctg_norm <- normalize_height(ctg,knnidw(k=10,p=2))

#outputs normalized square las file 
plot_1_norm <- readLAS("/Desktop/bruh/clips_5m_norm/plot_1_norm.las")
lidR::plot(plot_1_norm) 

37f791deea223ee058ebe9aecc4b89db data_towidoei_las.zip data_towidoei_las_2.zip (added more files to the zip)

towidoei commented 1 year ago

So when I plot the "plot_1_norm.las" and "plot_2_norm.las" etc. and they look square, is that purely a visual thing then? Can I calculate metrics from them and assume that I am calculating metrics form a radius instead of a square?

Jean-Romain commented 1 year ago

Your problem here is that your circular plots are overlapping according to the example you gave me above. Your normalization is incorrect because files are overlapping. A LAScatalog is expected to be a continuous wall-to-wall point cloud. Here you need to specifiy that your files are independents before to normalize. This automatically set the chunk buffer and chunk size to 0. Otherwise you are loading your circular plot + the files that are overlapping this plot.

opt_independent_files(ctg) = TRUE
Jean-Romain commented 1 year ago

That being said your normalization will not be good because you are normalizing without providing an extra buffer to your area of interest. You should first clip e.g. 10 m circle, normalize and them extract your 5m.

towidoei commented 1 year ago

That fixed it! I will also follow your advice and clip 10 and extract 5. Thank you very much for the quick help!! Greetings,