Skip to content

Commit

Permalink
Merge pull request #589 from weecology/warn_on_crs_mismatch
Browse files Browse the repository at this point in the history
when the CRS of the shapefile and RGB data don't match, don't proceed…
  • Loading branch information
ethanwhite authored Dec 21, 2023
2 parents 261f084 + 5b82dea commit b87f931
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 12 deletions.
1 change: 0 additions & 1 deletion deepforest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ def __init__(self,

self.create_model()


# Metrics
self.iou_metric = IntersectionOverUnion(
class_metrics=True, iou_threshold=self.config["validation"]["iou_threshold"])
Expand Down
30 changes: 22 additions & 8 deletions deepforest/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,11 @@ def shapefile_to_annotations(shapefile,
left, bottom, right, top = src.bounds
resolution = src.res[0]

# Check matching the crs
if not gdf.crs == src.crs:
raise ValueError("The shapefile crs {} does not match the image crs {}".format(
gdf.crs, src.crs))

# Transform project coordinates to image coordinates
df["tile_xmin"] = (df.minx - left) / resolution
df["tile_xmin"] = df["tile_xmin"].astype(int)
Expand Down Expand Up @@ -389,7 +394,6 @@ def boxes_to_shapefile(df, root_dir, projected=True, flip_y_axis=False):
df: a geospatial dataframe with the boxes optionally transformed to the target crs
"""
# Raise a warning and confirm if a user sets projected to True when flip_y_axis is True.

if flip_y_axis and projected:
warnings.warn(
"flip_y_axis is {}, and projected is {}. In most cases, projected should be False when inverting y axis. Setting projected=False"
Expand Down Expand Up @@ -473,10 +477,11 @@ def annotations_to_shapefile(df, transform, crs):
Returns:
results: a geopandas dataframe where every entry is the bounding box for a detected tree.
"""
warnings.warn("This method is deprecated and will be "
"removed in version DeepForest 2.0.0, "
"please use boxes_to_shapefile which unifies project_boxes and "
"annotations_to_shapefile functionalities")
warnings.warn(
"This method is deprecated and will be "
"removed in version DeepForest 2.0.0, "
"please use boxes_to_shapefile which unifies project_boxes and "
"annotations_to_shapefile functionalities", DeprecationWarning)

# Convert image pixel locations to geographic coordinates
xmin_coords, ymin_coords = rasterio.transform.xy(transform=transform,
Expand All @@ -489,6 +494,13 @@ def annotations_to_shapefile(df, transform, crs):
cols=df.xmax,
offset='center')

# If there is only one tree, the above comes out as a float, not a list
if type(xmin_coords) == float:
xmin_coords = [xmin_coords]
ymin_coords = [ymin_coords]
xmax_coords = [xmax_coords]
ymax_coords = [ymax_coords]

# One box polygon for each tree bounding box
box_coords = zip(xmin_coords, ymin_coords, xmax_coords, ymax_coords)
box_geoms = [
Expand All @@ -511,9 +523,11 @@ def project_boxes(df, root_dir, transform=True):
root_dir: directory of images to lookup image_path column
transform: If true, convert from image to geographic coordinates
"""
warnings.warn("This method is deprecated and will be removed in version "
"DeepForest 2.0.0, please use boxes_to_shapefile which "
"unifies project_boxes and annotations_to_shapefile functionalities")
warnings.warn(
"This method is deprecated and will be removed in version "
"DeepForest 2.0.0, please use boxes_to_shapefile which "
"unifies project_boxes and annotations_to_shapefile functionalities",
DeprecationWarning)
plot_names = df.image_path.unique()
if len(plot_names) > 1:
raise ValueError("This function projects a single plots worth of data. "
Expand Down
6 changes: 3 additions & 3 deletions tests/test_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_shapefile_to_annotations_convert_to_boxes(tmpdir):
sample_geometry = [geometry.Point(404211.9 + 10,3285102 + 20),geometry.Point(404211.9 + 20,3285102 + 20)]
labels = ["Tree","Tree"]
df = pd.DataFrame({"geometry":sample_geometry,"label":labels})
gdf = gpd.GeoDataFrame(df, geometry="geometry")
gdf = gpd.GeoDataFrame(df, geometry="geometry", crs="EPSG:32617")
gdf.to_file("{}/annotations.shp".format(tmpdir))
image_path = get_data("OSBS_029.tif")
shp = utilities.shapefile_to_annotations(shapefile="{}/annotations.shp".format(tmpdir), rgb=image_path, savedir=tmpdir, geometry_type="point")
Expand All @@ -65,7 +65,7 @@ def test_shapefile_to_annotations(tmpdir):
sample_geometry = [geometry.Point(404211.9 + 10,3285102 + 20),geometry.Point(404211.9 + 20,3285102 + 20)]
labels = ["Tree","Tree"]
df = pd.DataFrame({"geometry":sample_geometry,"label":labels})
gdf = gpd.GeoDataFrame(df, geometry="geometry")
gdf = gpd.GeoDataFrame(df, geometry="geometry", crs="EPSG:32617")
gdf["geometry"] = [geometry.box(left, bottom, right, top) for left, bottom, right, top in gdf.geometry.buffer(0.5).bounds.values]

gdf.to_file("{}/annotations.shp".format(tmpdir))
Expand Down Expand Up @@ -118,4 +118,4 @@ def test_boxes_to_shapefile_unprojected(m, flip_y_axis, projected):

# Confirm that each boxes within image bounds
geom = geometry.box(*r.bounds)
assert all(gdf.geometry.apply(lambda x: geom.intersects(geom)).values)
assert all(gdf.geometry.apply(lambda x: geom.intersects(geom)).values)

0 comments on commit b87f931

Please sign in to comment.