Comments (11)
I was just about to ask for this kind of thing. In general, it wasn't clear to me whether normalize reclasses the ground, or uses previously classed ground. If you give me a sense of general structure you'd like, I can give it a go. Right now i'm getting some funny results in a handful of cases.
just fyi, green are ground truth trees, blue is predictions. Top is RGB, bottom is a lidar height mask (any points above 2m normalized). Getting alot of artifacts in areas with alot of slope. This was done on a full tile, we are just looking at a portion. My plan is to emulate something from lidR. Ideas appreciated and i'll PR.
from pyfor.
The default Cloud.normalize
is a wrapper for Zhang2003
, the same algorithm JR uses:
https://github.com/brycefrank/pyfor/blob/master/pyfor/ground_filter.py
the normalization does the following (lines 137-148):
- Computes a bare earth model
- For each point, finds the underlying elevation of the bare earth model
- Subtracts this elevation from each point
Another method in cloud, Cloud.subtract
can use already computed bare earth models (as .tif
) to normalize heights. It is untested.
from pyfor.
Okay, let me have a fork and poke around. Can we agree on some goals?
- Read in ground model from either disk or
- Computes a new raster from current ground classification - emulating
dtm <- lidR::grid_terrain(las,res=1, algorithm = lidR::knnidw(k = 10 , p = 2))
from liDR.
- Utilities the same routine as the ground_filter class to compute steps 2 and 3 above.
from pyfor.
Here is what I am seeing,
Cloud.subtract
already accomplishes (1), but if I recall it reads a tif from file, rather than using a Raster
object.
(2) is straightforward, just subset the points dataframe to classification==2 (that is las spec standard for sorted ground points), proceed with Grid.interpolate
. Where to put the wrapper is the question.
What's missing I think is a standard way to use already existing rasters. The Raster
object is really only created as a derivative of a Cloud
(or Grid
). We could add functionality to create a Raster
from file, but this conflicts with the goal of converting Raster
to in-memory rasterio objects.
It is not so much the challenge of writing any new functions, but how to organize it in a consistent way, I think.
from pyfor.
As for the original normalization weirdness. Have you inspected the point cloud? There seems to be a cliff or some other oddity around that location.
from pyfor.
I will definitely followup on the current results, just haven't had a time to sit and look. Its pretty common, and I haven't noticed this in the liDR normalization - but i've been using the already classed grounds there.
I'm resubmitting a paper this week, but I have a feeling that normalization is definitely a problem, so i'll commit some time to a PR and we can discuss.
from pyfor.
here is an example from a standalone small file (the other was from a full tile - done all at once). I have not investigated this yet, but this is where i'll start.
just for completeness, that .laz and .tif are here (054): https://github.com/weecology/NeonTreeEvaluation/blob/master/SJER/plots/SJER_054.laz
and the code to generate the binary height mask is here:
from pyfor.
Here is my normalization attempt:
import pyfor
from time import sleep
pc = pyfor.cloud.Cloud('SJER_054.laz')
pc.normalize(0.33)
pc_2m = pc
pc_2m.data.points = pc.data.points[pc.data.points['z']>2]
pc_2m.write('test.las')
And the output (no mask, just displaying points > 2 m)
Perhaps adjusting the parameters are what you need, here I just adjusted the normalization cell size. Other parameters can be adjusted. See Zhang2003
docstrings and the sample in the pyfor samples repositories.
from pyfor.
from pyfor.
I am sure it is robust. It is not too hard to write ground points to a raster file to reconstruct the bare earth model.. You could try to use it with Cloud.subtract
but that function is untested
pc = pyfor.cloud.Cloud('your_cloud.laz')
pc_ground = pc
pc_ground.data.points = pc.data.points[pc.data.points['classification'] == 2]
pc_ground.grid(0.5).interpolate("min", "z").write('your_bem.tif')
pc.subtract('your_bem.tif')
That is a free-hand attempt, but I ran something similar for the last post.
Of course, coordinate references and such should be added to pc.crs
for best results.
The Zhang filter basically operates on neighboring "steepness" of a rasterized point cloud, if a point/cell is too steep compared to a reference point, it is removed from consideration as ground. This process iterates a few times to provide the BEM. Larger cell sizes wash out this "steepness", and leave artifacts like those you observed, usually in flatter landscapes.
from pyfor.
Added in 7ae2458
from pyfor.
Related Issues (20)
- Cryptic error when clipping a particular polygon and point set HOT 2
- Travis fails on write .laz
- Subversive pyproj error for Windows conda environment HOT 4
- Unclear argument parameter name in `retile_raster`
- Point cloud colors HOT 2
- `KrausPfeifer1998` classify fails HOT 1
- Add heightbreak for all metrics
- Eliminate `ResourceWarning`s from testing suite HOT 1
- `create_index` should be multithreaded by default
- Scanning files for a collection should be generalized to `.las/z` files
- Point gridding can be simplified
- Migrate to `conda-forge` testing
- Warning for `force_extent` bbox
- Docstring for `array_to_raster` is out of date HOT 1
- Make minimal area-based approach example
- Add ability to pass additional arguments through par_apply HOT 2
- Area-Based Metrics dodument is missing
- missing else branch for tolerance parameter in KrausPfeifer1998 HOT 2
- Conda forge gdal issue HOT 7
- Failed rasterization HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pyfor.