Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transform points #10

Merged
merged 22 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ All notable changes to this project will be documented below.
#### geospatial.read_geotif

* v0.1dev: spectral = **geospatial.read_geotif**(*filename, bands="B,G,R"*)

#### geospatial.transform_points

* v0.1dev: coord = **geospatial.transform_points**(*img, geojson*)
29 changes: 29 additions & 0 deletions docs/transform_points.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Transform Points

Transform the points from a georeferenced shapefile/GeoJSON based on an image size.

**plantcv.geospatial.transform_points**(*img, geojson*)

**returns** list of transformed coordinates

- **Parameters:**
- img - Spectral image object, likely read in with [`geo.read_geotif`](read_geotif.md)
- geojson - Path to the shapefile/GeoJSON containing the points. Can be Point or MultiPoint geometry.

- **Context:**
- Transformed points can be used downstream for Python analysis, such as defining ROIs.
- **Example use:**
- below to define plot boundaries


```python
import plantcv.geospatial as geo

# Read geotif in
spectral = geo.read_geotif(filename="./data/example_img.tif", bands="b,g,r,RE,NIR")
coords = geo.transform_points(img=spectral, geojson="./experimental_bounds_2024.shp")
roi_objects = pcv.roi.custom(img=spectral.pseudo_rgb, vertices=coords)

```

**Source Code:** [Here](https://github.com/danforthcenter/plantcv-geospatial/blob/main/plantcv/geospatial/transform_points.py)
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ nav:
- 'PlantCV Namespace':
- 'Geopspatial Tools':
- Read Geo-tif Data: read_geotif.md
- Transform coordinate points: transform_points.md
markdown_extensions:
- toc:
permalink: True
Expand Down
4 changes: 3 additions & 1 deletion plantcv/geospatial/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from importlib.metadata import version
from plantcv.geospatial.read_geotif import read_geotif
from plantcv.geospatial.transform_points import transform_points

# Auto versioning
__version__ = version("plantcv-geospatial")

__all__ = [
"read_geotif"
"read_geotif",
"transform_points"
]
30 changes: 30 additions & 0 deletions plantcv/geospatial/transform_points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Transform georeferenced GeoJSON/shapefile points into python coordinates
import fiona


def transform_points(img, geojson):
"""Takes a points-type shapefile/GeoJSON and transforms to numpy coordinates
Inputs:
img: A spectral object from read_geotif.
geojson: Path to the shape file containing the points.

Returns:
coord: Transformed points as a list of numpy coordinates

:param img: [spectral object]
:param geojson: str
:return coord: list
"""
geo_transform = img.geo_transform

coord = []
with fiona.open(geojson, 'r') as shapefile:
for i, _ in enumerate(shapefile):
if type((shapefile[i].geometry["coordinates"])) is list:
pixel_point = ~(geo_transform) * (shapefile[i].geometry["coordinates"][0])
if type((shapefile[i].geometry["coordinates"])) is tuple:
pixel_point = ~(geo_transform) * (shapefile[i].geometry["coordinates"])
rounded = (int(pixel_point[0]), int(pixel_point[1]))
coord.append(rounded)

return coord
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dependencies = [
"rasterio",
"fiona",
"shapely",

]
requires-python = ">=3.6"
authors = [
Expand Down
4 changes: 4 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def __init__(self):
self.empty_tif = os.path.join(self.datadir, "cropped_empty.tif")
# rgb image
self.rgb_tif = os.path.join(self.datadir, "rgb.tif")
# multiPoints shapefilex
self.pts_geojson = os.path.join(self.datadir, "test_pts.geojson")
# points shapefilex
self.single_pts_geojson = os.path.join(self.datadir, "single_test_pts.geojson")
# polygon shapefile
self.square_crop = os.path.join(self.datadir, "square_crop.geojson")
# points shapefile
Expand Down
19 changes: 19 additions & 0 deletions tests/test_geospatial_transform_points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Tests for geospatial.readd_geotif."""

from plantcv.geospatial import read_geotif, transform_points


def test_geospatial_transform_points(test_data):
"""Test for plantcv-geospatial."""
# read in small 5-band tif image
img = read_geotif(filename=test_data.rgb_tif, bands="B,G,R")
coords = transform_points(img=img, geojson=test_data.pts_geojson)
assert len(coords) == 4


def test_geospatial_transform_single_points(test_data):
"""Test for plantcv-geospatial."""
# read in small 5-band tif image
img = read_geotif(filename=test_data.rgb_tif, bands="B,G,R")
coords = transform_points(img=img, geojson=test_data.single_pts_geojson)
assert len(coords) == 8
15 changes: 15 additions & 0 deletions tests/testdata/single_test_pts.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"type": "FeatureCollection",
"name": "single_test_pts",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::32615" } },
"features": [
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720201.455548222991638, 4302929.009466916322708 ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720200.939437506720424, 4302928.515762113966048 ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720200.359096014057286, 4302927.93337285425514 ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720199.889628155739047, 4302927.349608448334038 ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720199.406284277676605, 4302926.797856044024229 ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720198.922733629238792, 4302926.185171222314239 ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720198.442067798110656, 4302925.539512793533504 ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "Point", "coordinates": [ 720197.996919097611681, 4302925.057554029859602 ] } }
]
}
11 changes: 11 additions & 0 deletions tests/testdata/test_pts.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"type": "FeatureCollection",
"name": "test_pts",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::32615" } },
"features": [
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "MultiPoint", "coordinates": [ [ 720198.48000389453955, 4302927.004775654524565 ] ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "MultiPoint", "coordinates": [ [ 720199.890186188276857, 4302928.102779876440763 ] ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "MultiPoint", "coordinates": [ [ 720200.501309029874392, 4302929.21947811357677 ] ] } },
{ "type": "Feature", "properties": { "id": null }, "geometry": { "type": "MultiPoint", "coordinates": [ [ 720197.757872894289903, 4302926.144173440523446 ] ] } }
]
}