Skip to content

Commit 6f42291

Browse files
Merge pull request #5 from ProgrammingOperative/visualization
Visualization complete
2 parents 04199ad + 8dc359a commit 6f42291

File tree

8 files changed

+142
-93
lines changed

8 files changed

+142
-93
lines changed

assets/usgs_data_pipeline.json

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"type": "filters.range",
1717
"inputs": [ "crop" ],
1818
"tag": "no_noise",
19-
"limits": "Classification![2:2]"
19+
"limits": "Classification![7:7]"
2020
},
2121
{
2222
"type": "filters.assign",
@@ -25,9 +25,16 @@
2525
"assignment": "Classification[:]=0"
2626
},
2727
{
28-
"type": "filters.smrf",
28+
"type": "filters.reprojection",
2929
"inputs": [ "wipe_classes" ],
30-
"tag": "groundify"
30+
"tag": "reprojection",
31+
"in_srs": "EPSG:3857",
32+
"out_srs": ""
33+
},
34+
{
35+
"inputs": [ "reprojection" ],
36+
"tag": "groundify",
37+
"type": "filters.smrf"
3138
},
3239
{
3340
"type": "filters.range",
@@ -36,11 +43,10 @@
3643
"limits": "Classification[2:2]"
3744
},
3845
{
39-
"type": "filters.reprojection",
46+
"type": "writers.las",
4047
"inputs": [ "classify" ],
41-
"tag": "reprojection",
42-
"in_srs": "EPSG:3857",
43-
"out_srs": ""
48+
"tag": "writers_las",
49+
"filename": ""
4450
},
4551
{
4652
"type": "writers.gdal",

notebooks/extract_and_visualize.ipynb

Whitespace-only changes.

notebooks/lidar1.ipynb

Lines changed: 0 additions & 67 deletions
This file was deleted.

scripts/agritechlidar.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44

55

66

7-
8-
97
class AgriTechLidar:
10-
def __init__(self) -> None:
11-
pass
8+
def __init__(self, epsg = 26915):
9+
self.input_epsg = 3857
10+
self.output_epsg = epsg
11+
self.fetch_data = FetchLidar(self.output_epsg)
12+
1213

13-
def fetch_lidar(self, polygon: Polygon):
14-
return self.fetch_lidar(polygon)
14+
def fetch_lidar(self, polygon: Polygon, regions=[]):
15+
return self.fetch_data.get_lidar_data(polygon, regions)
1516

1617

1718
def render_vis(self, df: gpd.GeoDataFrame) -> Vis:

scripts/fetch_lidar.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
import geopandas as gpd
66
from shapely.geometry import Polygon
77
import json
8+
from gpd_helper import GpdHelper
89
from config import Config
910

1011
class FetchLidar:
11-
def __init__(self) -> None:
12-
pass
12+
def __init__(self, epsg: int = 26915) -> None:
13+
self._input_epsg = 3857
14+
self.output_epsg = epsg
15+
self._gdf_helper = GPDHelper(self._input_epsg, self.output_epsg)
16+
1317

1418

1519

@@ -22,19 +26,26 @@ def make_pipeline(self, bounds: str, polygon_str: str, region: str, filename: st
2226
pipe['pipeline'][0]['filename'] = Config.USGS_3DEP_PUBLIC_DATA_PATH / f"{region}/etp.json"
2327
pipe['pipeline'][0]['bounds'] = bounds
2428
pipe['pipeline'][1]['polygon'] = polygon_str
25-
pipe['pipeline'][6]['out_srs'] = f'EPSG:{self.output_epsg}'
26-
pipe['pipeline'][7]['filename'] = Config.DATA_PATH + f'{filename}.tif'
27-
pipe['pipeline'][8]['filename'] = Config.DATA_PATH + f'{filename}.tif'
29+
pipe['pipeline'][5]['out_srs'] = f'EPSG:{self.output_epsg}'
30+
pipe['pipeline'][8]['filename'] = Config.DATA_PATH + f'{filename}.laz'
31+
pipe['pipeline'][9]['filename'] = Config.DATA_PATH + f'{filename}.tif'
2832
return pdal.Pipeline(json.dumps(pipe))
2933

3034

3135
# def get_dep(self, bounds: Bounds, polygon_str: str, region: list) -> gpd.GeoDataFrame:
3236
# We only need the polygon, not necesarily the boundaries
3337

3438

35-
3639
def fetch_data(self, bounds: Bounds, polygon_str: str, region: list) -> gpd.GeoDataFrame:
37-
""" Executes pdal pipeline and fetches point cloud data from a public repository.
40+
filename = region + "_" + bounds.get_bound_name()
41+
pl = self.make_pipeline(bounds.get_bound_str(),
42+
polygon_str, region, filename)
43+
pl.execute()
44+
gpd_data = self._gdf_helper.create_gdf(pl.arrays)
45+
return gpd_data
46+
47+
48+
""" Executes pdal pipeline and fetches point cloud data from a public repository.
3849
Using GDfHelper class creates Geopandas data frame containing geometry and elevation of the point cloud data.
3950
4051
Args:
@@ -45,12 +56,10 @@ def fetch_data(self, bounds: Bounds, polygon_str: str, region: list) -> gpd.GeoD
4556
Returns:
4657
gpd.GeoDataFrame: Geopandas data frame containing geometry and elevation
4758
"""
48-
filename = region + "_" + bounds.get_bound_name()
49-
pl = self.make_pipeline(bounds.get_bound_str(),
50-
polygon_str, region, filename)
51-
pl.execute()
52-
dep_data = self._gdf_helper.create_gdf(pl.arrays)
53-
return dep_data
59+
60+
def get_lidar_data(self, polygon, regions):
61+
bound, polygon_str = self._gdf_helper.get_bound_from_polygon(polygon)
62+
return self.fetch_data(bound, polygon_str, regions)
5463

5564

5665

scripts/gpd_helper.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ def create_gdf(self, array_data: np.ndarray) -> gpd.GeoDataFrame:
5454

5555

5656

57+

scripts/visualization.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import os
2+
from glob import glob
3+
import matplotlib.pyplot as plt
4+
import rasterio as rio
5+
from rasterio.plot import plotting_extent, show
6+
import geopandas as gpd
7+
import numpy as np
8+
import geopandas as gpd
9+
import matplotlib.image as mpimg
10+
import rasterio
11+
from rasterio.plot import show_hist
12+
13+
14+
15+
class Visualize():
16+
def __init__(self, df: gpd.GeoDataFrame):
17+
self.df = df
18+
19+
20+
def plot_raster(path_to_raster):
21+
"""
22+
displays a raster from a .tif raster file
23+
args:
24+
path_to_raster (str): path to the raster file
25+
returns:
26+
rasterio image
27+
"""
28+
src = rasterio.open(path_to_raster)
29+
fig, (axrgb, axhist) = plt.subplots(1, 2, figsize=(14,7))
30+
show((src), cmap='Greys_r', contour=True, ax=axrgb)
31+
show_hist(src, bins=50, histtype='stepfilled',
32+
lw=0.0, stacked=False, alpha=0.3, ax=axhist)
33+
plt.show()
34+
35+
def get_points(self):
36+
""" Generates a NumPy array from point clouds data.
37+
"""
38+
x = self.df.geometry.x
39+
y = self.df.geometry.y
40+
z = self.df.elevation
41+
return np.vstack((x, y, z)).transpose()
42+
43+
def plot_2d_heatmap(df,column,title):
44+
"""
45+
plot a 2d heat map of the terrain
46+
args:
47+
df (geopndas df): a geopandas dataframe demonstrating the data
48+
column (str): input column to outline in string
49+
title (str): input title of the map in string
50+
return:
51+
2d heat map of terrain
52+
"""
53+
fig, ax = plt.subplots(1, 1, figsize=(12, 10))
54+
fig.patch.set_alpha(0)
55+
plt.grid('on', zorder=0)
56+
df.plot(column=column, ax=ax, legend=True, cmap="terrain")
57+
plt.title(title)
58+
plt.xlabel('long')
59+
plt.ylabel('lat')
60+
plt.show()

tests/test_scripts.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import unittest
2+
import sys, os
3+
sys.path.append(os.path.abspath(os.path.join('..')))
4+
5+
6+
class TestCases(unittest.TestCase):
7+
def test_find_average(self):
8+
"""
9+
Test that it retunrs the average of a given list
10+
"""
11+
data = [1, 2, 3]
12+
result = loader.find_average(data)
13+
self.assertEqual(result, 2.0)
14+
15+
def test_input_value(self):
16+
"""
17+
Provide an assertion level for arg input
18+
"""
19+
20+
self.assertRaises(TypeError, loader.find_average, True)
21+
22+
class TestCountOccurence(unittest.TestCase):
23+
def test_count_occurence(self):
24+
"""
25+
Test that it returns the count of each unique values in the given list
26+
"""
27+
data = [0,0,9,0,8,9,0,7]
28+
result = loader.count_occurence(data)
29+
output = {0: 4, 9: 2, 8: 1, 7: 1}
30+
self.assertAlmostEqual(result, output)
31+
32+
def test_input_value(self):
33+
"""
34+
Provide an assertion level for arg input
35+
"""
36+
self.assertRaises(TypeError, loader.count_occurence, True)
37+
38+
if __name__ == '__main__':
39+
unittest.main()

0 commit comments

Comments
 (0)