Update app.py
Browse files
app.py
CHANGED
|
@@ -158,25 +158,39 @@ def get_transform_from_tif(tif_path):
|
|
| 158 |
crs = src.crs
|
| 159 |
return transform, crs
|
| 160 |
|
| 161 |
-
def mask_to_polygons(mask, transform,
|
| 162 |
-
|
| 163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
|
| 165 |
-
# Extract
|
| 166 |
results = (
|
| 167 |
-
{'properties': {'class': '
|
| 168 |
-
for
|
| 169 |
-
if
|
| 170 |
)
|
| 171 |
|
| 172 |
geoms = list(results)
|
|
|
|
|
|
|
| 173 |
if not geoms:
|
| 174 |
return gpd.GeoDataFrame(columns=['geometry'], geometry='geometry', crs='EPSG:4326')
|
| 175 |
-
|
| 176 |
gdf = gpd.GeoDataFrame.from_features(geoms)
|
| 177 |
gdf.set_crs(epsg=4326, inplace=True)
|
| 178 |
return gdf
|
| 179 |
|
|
|
|
| 180 |
def calculate_illegal_area(mining_gdf, wiup_gdf):
|
| 181 |
# Ensure both are in same CRS
|
| 182 |
mining_gdf = mining_gdf.to_crs(wiup_gdf.crs)
|
|
@@ -351,12 +365,17 @@ if st.button("Run Inference"):
|
|
| 351 |
transform, crs = get_transform_from_tif(optic_path)
|
| 352 |
|
| 353 |
# Convert mask to mining polygons
|
| 354 |
-
non_mining_gdf = mask_to_polygons(pred_label_mask, transform,
|
| 355 |
-
mining_gdf = mask_to_polygons(pred_label_mask, transform,
|
| 356 |
-
beach_gdf = mask_to_polygons(pred_label_mask, transform,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 357 |
|
| 358 |
# Make sure WIUP and prediction are in same CRS
|
| 359 |
wiup_gdf = wiup_gdf.to_crs(mining_gdf.crs)
|
|
|
|
| 360 |
|
| 361 |
# Find area
|
| 362 |
non_mining_area, non_mining_area_gdf = calculate_illegal_area(non_mining_gdf, wiup_gdf)
|
|
|
|
| 158 |
crs = src.crs
|
| 159 |
return transform, crs
|
| 160 |
|
| 161 |
+
def mask_to_polygons(mask, transform, target_class_id):
|
| 162 |
+
"""
|
| 163 |
+
Convert a single-class mask to polygons with proper geospatial reference.
|
| 164 |
+
|
| 165 |
+
Args:
|
| 166 |
+
mask (np.ndarray): Predicted mask (H, W) with class indices.
|
| 167 |
+
transform (Affine): Georeferencing transform from the input TIF.
|
| 168 |
+
target_class_id (int): The class ID to convert into polygons.
|
| 169 |
+
|
| 170 |
+
Returns:
|
| 171 |
+
gpd.GeoDataFrame: Geodataframe containing polygons for the target class.
|
| 172 |
+
"""
|
| 173 |
+
# Binary mask for the target class
|
| 174 |
+
binary_mask = (mask == target_class_id).astype(np.uint8)
|
| 175 |
|
| 176 |
+
# Extract polygon shapes
|
| 177 |
results = (
|
| 178 |
+
{'properties': {'class': f'class_{target_class_id}'}, 'geometry': geom}
|
| 179 |
+
for geom, value in shapes(binary_mask, mask=None, transform=transform)
|
| 180 |
+
if value == 1
|
| 181 |
)
|
| 182 |
|
| 183 |
geoms = list(results)
|
| 184 |
+
|
| 185 |
+
# Return empty GeoDataFrame if no shapes found
|
| 186 |
if not geoms:
|
| 187 |
return gpd.GeoDataFrame(columns=['geometry'], geometry='geometry', crs='EPSG:4326')
|
| 188 |
+
|
| 189 |
gdf = gpd.GeoDataFrame.from_features(geoms)
|
| 190 |
gdf.set_crs(epsg=4326, inplace=True)
|
| 191 |
return gdf
|
| 192 |
|
| 193 |
+
|
| 194 |
def calculate_illegal_area(mining_gdf, wiup_gdf):
|
| 195 |
# Ensure both are in same CRS
|
| 196 |
mining_gdf = mining_gdf.to_crs(wiup_gdf.crs)
|
|
|
|
| 365 |
transform, crs = get_transform_from_tif(optic_path)
|
| 366 |
|
| 367 |
# Convert mask to mining polygons
|
| 368 |
+
non_mining_gdf = mask_to_polygons(pred_label_mask, transform, target_class_id=0)
|
| 369 |
+
mining_gdf = mask_to_polygons(pred_label_mask, transform, target_class_id=1)
|
| 370 |
+
beach_gdf = mask_to_polygons(pred_label_mask, transform, target_class_id=2)
|
| 371 |
+
|
| 372 |
+
st.success(f"Non-mining polygons: {len(non_mining_gdf)}")
|
| 373 |
+
st.success(f"Mining polygons: {len(mining_gdf)}")
|
| 374 |
+
st.success(f"Beach polygons: {len(beach_gdf)}")
|
| 375 |
|
| 376 |
# Make sure WIUP and prediction are in same CRS
|
| 377 |
wiup_gdf = wiup_gdf.to_crs(mining_gdf.crs)
|
| 378 |
+
st.success(f"WIUP CRS: {wiup_gdf.crs}")
|
| 379 |
|
| 380 |
# Find area
|
| 381 |
non_mining_area, non_mining_area_gdf = calculate_illegal_area(non_mining_gdf, wiup_gdf)
|