Update app.py
Browse files
app.py
CHANGED
@@ -158,31 +158,19 @@ 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 |
-
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
|
177 |
results = (
|
178 |
-
{'properties': {'class':
|
179 |
-
for
|
180 |
-
if
|
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 |
|
@@ -191,21 +179,23 @@ def mask_to_polygons(mask, transform, target_class_id):
|
|
191 |
return gdf
|
192 |
|
193 |
|
194 |
-
|
195 |
-
|
|
|
196 |
mining_gdf = mining_gdf.to_crs(wiup_gdf.crs)
|
197 |
|
198 |
-
#
|
199 |
-
|
200 |
|
201 |
# Convert to metric CRS (e.g., UTM) to calculate area in m²
|
202 |
-
metric_crs = 'EPSG:4326' # UTM zone for SE Asia (adjust based on location)
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
|
|
207 |
|
208 |
-
return
|
209 |
|
210 |
# Streamlit App Title
|
211 |
st.title("Satellite Mining Segmentation: SAR + Optic Image Inference")
|
@@ -365,28 +355,19 @@ if st.button("Run Inference"):
|
|
365 |
transform, crs = get_transform_from_tif(optic_path)
|
366 |
|
367 |
# Convert mask to mining polygons
|
368 |
-
|
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 |
-
|
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 |
-
|
382 |
-
mining_area, mining_area_gdf = calculate_area(mining_gdf, wiup_gdf)
|
383 |
-
beach_area, beach_area_gdf = calculate_area(beach_gdf, wiup_gdf)
|
384 |
|
385 |
# Display in Streamlit
|
386 |
-
st.success(f"
|
387 |
-
st.success(f" Mining Area : {mining_area/1e6:.2f} sq. km")
|
388 |
-
st.success(f" Beach Area : {beach_area/1e6:.2f} sq. km")
|
389 |
-
|
390 |
|
391 |
else:
|
392 |
st.warning("Please upload all three .tiff files to proceed.")
|
|
|
158 |
crs = src.crs
|
159 |
return transform, crs
|
160 |
|
161 |
+
def mask_to_polygons(mask, transform, mining_class_id=1):
|
162 |
+
# Create a binary mask for mining areas
|
163 |
+
mining_mask = (mask == mining_class_id).astype(np.uint8)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
|
165 |
+
# Extract shapes (polygons) from the mask
|
166 |
results = (
|
167 |
+
{'properties': {'class': 'mining_land'}, 'geometry': s}
|
168 |
+
for s, v in shapes(mining_mask, mask=None, transform=transform)
|
169 |
+
if v == 1 # Only keep areas marked as mining
|
170 |
)
|
171 |
|
172 |
+
# Create a GeoDataFrame from the polygon results
|
173 |
geoms = list(results)
|
|
|
|
|
174 |
if not geoms:
|
175 |
return gpd.GeoDataFrame(columns=['geometry'], geometry='geometry', crs='EPSG:4326')
|
176 |
|
|
|
179 |
return gdf
|
180 |
|
181 |
|
182 |
+
# Function to calculate illegal mining area (mining outside WIUP)
|
183 |
+
def calculate_illegal_area(mining_gdf, wiup_gdf):
|
184 |
+
# Ensure both are in the same CRS
|
185 |
mining_gdf = mining_gdf.to_crs(wiup_gdf.crs)
|
186 |
|
187 |
+
# Perform overlay operation: difference (mining area outside WIUP)
|
188 |
+
illegal_area_gdf = gpd.overlay(mining_gdf, wiup_gdf, how='difference')
|
189 |
|
190 |
# Convert to metric CRS (e.g., UTM) to calculate area in m²
|
191 |
+
metric_crs = ' EPSG:4326' # UTM zone for SE Asia (adjust based on location)
|
192 |
+
illegal_area_gdf = illegal_area_gdf.to_crs(metric_crs)
|
193 |
+
|
194 |
+
# Calculate the area in square meters
|
195 |
+
illegal_area_gdf['area_m2'] = illegal_area_gdf.geometry.area
|
196 |
+
total_illegal_area = illegal_area_gdf['area_m2'].sum()
|
197 |
|
198 |
+
return total_illegal_area, illegal_area_gdf
|
199 |
|
200 |
# Streamlit App Title
|
201 |
st.title("Satellite Mining Segmentation: SAR + Optic Image Inference")
|
|
|
355 |
transform, crs = get_transform_from_tif(optic_path)
|
356 |
|
357 |
# Convert mask to mining polygons
|
358 |
+
mining_gdf = mask_to_polygons(pred_label_mask, transform, mining_class_id=1)
|
|
|
|
|
|
|
|
|
359 |
st.success(f"Mining polygons: {len(mining_gdf)}")
|
360 |
+
|
361 |
|
362 |
# Make sure WIUP and prediction are in same CRS
|
363 |
wiup_gdf = wiup_gdf.to_crs(mining_gdf.crs)
|
364 |
st.success(f"WIUP CRS: {wiup_gdf.crs}")
|
365 |
|
366 |
# Find area
|
367 |
+
mining_area, mining_area_gdf = calculate_illegal_area(mining_gdf, wiup_gdf)
|
|
|
|
|
368 |
|
369 |
# Display in Streamlit
|
370 |
+
st.success(f" Illegal Mining Area : {mining_area/1e6:.2f} sq. km")
|
|
|
|
|
|
|
371 |
|
372 |
else:
|
373 |
st.warning("Please upload all three .tiff files to proceed.")
|