brycefrank / pyfor

Tools for analyzing aerial point clouds of forest data.
MIT License
93 stars 19 forks source link

Clip multiple features from single Cloud #11

Closed ccimarp closed 6 years ago

ccimarp commented 6 years ago

Hi Bryce,

I would like to clip my point cloud with a shapefile with several polygons. It is possible to do with polyclip? How can I save this point cloud clipped?

Thanks! Carmen

brycefrank commented 6 years ago

Hello Carmen,

As of right now there is not a straightforward way to do this with pyfor functions, since the Cloud.clip() only works with a single geometry. I am a little swamped right now with other work, but sometime this week I should be able to work up a small example.

If this provides any insight, I expect it should be easy, if all of your polygons are within the extent of the point cloud, to loop through polygon objects and clip from the same cloud object. This is probably your best bet.

This is something I have been meaning to incorporate within the package itself, so thank you for the motivation :) I will also make sure to add anything I come up with to the clipping sample.

Bryce

brycefrank commented 6 years ago

Carmen, Here is a quick example I was able to make work. This uses geopandas which should already be installed in your pyfor environment.

import geopandas as gpd

# Load your object cloud
cloud = pyfor.cloud.Cloud("/home/bryce/Programming/PyFor/pyfortest/data/test.las")

# Load your shapefile with 2 features as a GeoDataFrame
two_features = gpd.read_file("/home/bryce/Desktop/pyfor_test_data/two_features.shp")

# Construct container list
new_clouds = []

# Clip the cloud and append
for polygon in two_features['geometry']:
    new_clouds.append(cloud.clip(polygon))

We can do this a bit more concisely with a list comprehension if you prefer:

new_clouds = [cloud.clip(polygon) for polygon in two_features['geometry']]

cloud.clip() is pretty flexible, as long as you are feeding it objects that are shapely polygons and properly georeferenced with the original point cloud you should be good to go.

As for clipping to polygons that cover multiple LiDAR tiles, this is still something I am working on, and should be implemented later this summer.

Here are a few useful references for you if you want to extend further: The Shapely User Manual GeoPandas Documentation

ccimarp commented 6 years ago

Thanks so much! It's worked. Now, how can I save these clipped clouds in my own folder? I tried to save my clouds but I have this error:

AttributeError: 'Cloud' object has no attribute 'write'

brycefrank commented 6 years ago

This should do it:

your_cloud.las.write("your/path/your_cloud.las")

I have debated adding a wrapper function to Cloud for write for a while. I will play this idea and implement in 0.2.2. It does seem like a natural extension.

ccimarp commented 6 years ago

I put my script like this and it works:

poly_frame = gpd.read_file("../10190_b26_copia.shp")
poly_frame
Multi = MultiPolygon([shape(pol['geometry']) for pol in fiona.open('../10190_b26_copia.shp')])
Polygons = list(Multi)

new_clouds1 = []

for polygon in Polygons:
    new_clouds1.append(cloud.clip(polygon))

for i in range(0,len(new_clouds1)):
    try:
        new_clouds1[i].las.write("../" + poly_frame['id_new'][i] + ".las")
    except ValueError:
        pass

Thank you so much for your help and patience. Carmen

brycefrank commented 6 years ago

No problem!

These questions also help me iron out weirdnesses in the package.