-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from danforthcenter/22-clicks-to-shapefile
Clicked points to shape file
- Loading branch information
Showing
8 changed files
with
141 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
## Output clicked points as a geojson shapefile | ||
|
||
Using a Napari or PlantCV-annotate viewer object with clicked points, output a shapefile. | ||
|
||
**geospatial.points_to_geojson**(*img, viewer, out_path*) | ||
|
||
- **Parameters:** | ||
- img - Spectral image object, likely read in with [`geo.read_geotif`](read_geotif.md) | ||
- viewer - Napari viewer class object, possible created with PlantCV-Annotate. | ||
- out_path - Path to save the geojson shapefile. Must be ".geojson" file type. | ||
|
||
- **Context:** | ||
- Saved points can be used downstream for generating circular ROIs or circles for use with rasterstats. | ||
- **Example use:** | ||
- below to click plant locations | ||
|
||
|
||
```python | ||
import plantcv.geospatial as geo | ||
import plantcv.annotate as an | ||
|
||
# Read geotif in | ||
img = geo.read_geotif("../read_geotif/rgb.tif", bands="R,G,B") | ||
viewer = an.napari_open(img=img.pseudo_rgb) | ||
viewer.add_points() | ||
|
||
# A napari viewer window will pop up, use the points function to add clicks | ||
``` | ||
```python | ||
# In a separate cell, save the output after clicking: | ||
geo.points_to_geojson(img, viewer, out_path="./points_example.geojson") | ||
``` | ||
|
||
![Screenshot](documentation_images/napari_clicks.png) | ||
|
||
**Source Code:** [Here](https://github.com/danforthcenter/plantcv-geospatial/blob/main/plantcv/geospatial/points_to_geojson.py) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Save clicked points from Napari or PlantCV-annotate as a geojson points file. | ||
|
||
import geojson | ||
import rasterio | ||
from plantcv.plantcv import fatal_error | ||
|
||
|
||
def points_to_geojson(img, viewer, out_path): | ||
"""Use clicks from a Napari or plantcv-annotate viewer to output a geojson shapefile. | ||
Parameters | ||
---------- | ||
img : PlantCV spectral_data class object | ||
The image used for clicking on points, should be from read_geotif. | ||
viewer: Napari viewer class object or plantcv-annotate Points class object. | ||
The viewer used to make the clicks. | ||
out_path : str | ||
Path to save to shapefile. Must have "geojson" file extension | ||
""" | ||
# Napari output, points must be reversed | ||
if hasattr(viewer, 'layers'): | ||
points = [(img.metadata["transform"]*reversed(i)) for i in viewer.layers["Points"].data] | ||
# Annotate output | ||
elif hasattr(viewer, 'coords'): | ||
points = [(img.metadata["transform"]*i) for i in viewer.coords['default']] | ||
else: | ||
fatal_error("Viewer class type not recognized. Currently, Napari and PlantCV-annotate viewers supported.") | ||
features = [geojson.Feature(geometry=geojson.Point((lon, lat))) for lon, lat in points] | ||
feature_collection = geojson.FeatureCollection(features) | ||
# Make sure the coordinate system is the same as the original image | ||
feature_collection['crs'] = { | ||
"type": "name", | ||
"properties": { | ||
"name": rasterio.crs.CRS.to_string(img.metadata["crs"]) | ||
} | ||
} | ||
if ".geojson" in out_path: | ||
with open(out_path, 'w') as f: | ||
geojson.dump(feature_collection, f) | ||
else: | ||
fatal_error("File type not supported.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
"""Tests for geospatial.points_to_geojson""" | ||
|
||
import pytest | ||
import os | ||
import napari | ||
from plantcv.geospatial import read_geotif | ||
from plantcv.geospatial import points_to_geojson | ||
|
||
# Set up fake class just for testing the annotate output | ||
# Don't want to have to have annotate as a dependency | ||
|
||
class FakePoints: | ||
def __init__(self): | ||
self.coords = {} | ||
|
||
def test_geospatial_points_to_geojson_napari(test_data, tmpdir): | ||
"""Test for plantcv-geospatial.""" | ||
cache_dir = tmpdir.mkdir("cache") | ||
img = read_geotif(filename=test_data.rgb_tif, bands="R,G,B") | ||
viewer = napari.Viewer(show=False) | ||
viewer.add_image(img.pseudo_rgb) | ||
viewer.add_points() | ||
filename = os.path.join(cache_dir, 'test_out.geojson') | ||
points_to_geojson(img, viewer, out_path=filename) | ||
assert os.path.exists(filename) | ||
|
||
def test_geospatial_points_to_geojson_an(test_data, tmpdir): | ||
"""Test for plantcv-geospatial.""" | ||
cache_dir = tmpdir.mkdir("cache") | ||
img = read_geotif(filename=test_data.rgb_tif, bands="R,G,B") | ||
viewer = FakePoints() | ||
viewer.coords["default"] = [] | ||
filename = os.path.join(cache_dir, 'test_out.geojson') | ||
points_to_geojson(img, viewer, out_path=filename) | ||
assert os.path.exists(filename) | ||
|
||
def test_geospatial_points_to_geojson_badviewer(test_data, tmpdir): | ||
"""Test for plantcv-geospatial.""" | ||
cache_dir = tmpdir.mkdir("cache") | ||
img = read_geotif(filename=test_data.rgb_tif, bands="R,G,B") | ||
viewer = [] | ||
filename = os.path.join(cache_dir, 'test_out.geojson') | ||
with pytest.raises(RuntimeError): | ||
points_to_geojson(img, viewer, out_path=filename) | ||
|
||
def test_geospatial_points_to_geojson_badfilename(test_data, tmpdir): | ||
"""Test for plantcv-geospatial.""" | ||
cache_dir = tmpdir.mkdir("cache") | ||
img = read_geotif(filename=test_data.rgb_tif, bands="R,G,B") | ||
viewer = FakePoints() | ||
viewer.coords["default"] = [] | ||
filename = os.path.join(cache_dir, 'test_out.txt') | ||
with pytest.raises(RuntimeError): | ||
points_to_geojson(img, viewer, out_path=filename) |