Geoeasy commited on
Commit
10d326d
·
verified ·
1 Parent(s): 398be62

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -222
app.py DELETED
@@ -1,222 +0,0 @@
1
- import gradio as gr
2
- import os
3
- import tempfile
4
- import zipfile
5
- import uuid
6
- import rasterio
7
- import numpy as np
8
- from rasterio.mask import mask
9
- import geopandas as gpd
10
- import matplotlib.pyplot as plt
11
- from io import BytesIO
12
- from PIL import Image
13
- import shutil
14
-
15
-
16
- def clip_geotiff(tif_file, shapefile_zip):
17
- """
18
- Clips a GeoTIFF file using a shapefile
19
- """
20
- temp_dir = None
21
- try:
22
- # Check if files were provided
23
- if tif_file is None or shapefile_zip is None:
24
- return None, None
25
-
26
- # Create unique temporary directory
27
- temp_dir = tempfile.mkdtemp(prefix="geotiff_clip_")
28
- img_dir = os.path.join(temp_dir, "image")
29
- shp_dir = os.path.join(temp_dir, "shapefile")
30
- out_dir = os.path.join(temp_dir, "output")
31
-
32
- # Create subdirectories
33
- for directory in [img_dir, shp_dir, out_dir]:
34
- os.makedirs(directory, exist_ok=True)
35
-
36
- # Handle TIFF file - tif_file is now a file path (string)
37
- tif_path = os.path.join(img_dir, f"input_{uuid.uuid4().hex}.tif")
38
- shutil.copy2(tif_file, tif_path)
39
-
40
- # Handle shapefile ZIP - shapefile_zip is now a file path (string)
41
- zip_path = os.path.join(shp_dir, f"shapefile_{uuid.uuid4().hex}.zip")
42
- shutil.copy2(shapefile_zip, zip_path)
43
-
44
- # Extract ZIP
45
- with zipfile.ZipFile(zip_path, 'r') as zip_ref:
46
- zip_ref.extractall(shp_dir)
47
-
48
- # Find .shp file
49
- shp_files = [f for f in os.listdir(shp_dir) if f.endswith(".shp")]
50
- if not shp_files:
51
- raise FileNotFoundError(".shp file not found in the provided ZIP.")
52
-
53
- shp_file = os.path.join(shp_dir, shp_files[0])
54
-
55
- # Read shapefile using geopandas
56
- gdf = gpd.read_file(shp_file)
57
-
58
- # Check if shapefile has valid geometries
59
- if gdf.empty or gdf.geometry.isna().all():
60
- raise ValueError("Shapefile does not contain valid geometries.")
61
-
62
- # Open and process GeoTIFF file
63
- with rasterio.open(tif_path) as src:
64
- # Check for overlap between shapefile and raster
65
- gdf_proj = gdf.to_crs(src.crs)
66
-
67
- # Perform clipping
68
- out_image, out_transform = mask(src, gdf_proj.geometry, crop=True, nodata=src.nodata)
69
-
70
- # Update metadata
71
- out_meta = src.meta.copy()
72
- out_meta.update({
73
- "height": out_image.shape[1],
74
- "width": out_image.shape[2],
75
- "transform": out_transform,
76
- "nodata": src.nodata
77
- })
78
-
79
- # Save clipped GeoTIFF
80
- output_filename = f"clipped_{uuid.uuid4().hex}.tif"
81
- output_tif_path = os.path.join(out_dir, output_filename)
82
-
83
- with rasterio.open(output_tif_path, "w", **out_meta) as dest:
84
- dest.write(out_image)
85
-
86
- # Create PNG visualization in memory
87
- # Prepare data for visualization
88
- if out_image.shape[0] >= 3:
89
- # If has 3 or more bands, use first 3 (RGB)
90
- preview_array = out_image[:3]
91
- else:
92
- # If has less than 3 bands, repeat first band
93
- preview_array = np.repeat(out_image[0:1], 3, axis=0)
94
-
95
- # Rearrange dimensions (bands, height, width) -> (height, width, bands)
96
- preview_array = np.moveaxis(preview_array, 0, -1)
97
-
98
- # Normalize values to 0-255 if necessary
99
- if preview_array.dtype != np.uint8:
100
- # Normalize to 0-255
101
- preview_min = np.nanmin(preview_array)
102
- preview_max = np.nanmax(preview_array)
103
- if preview_max > preview_min:
104
- preview_array = ((preview_array - preview_min) / (preview_max - preview_min) * 255).astype(np.uint8)
105
- else:
106
- preview_array = np.zeros_like(preview_array, dtype=np.uint8)
107
-
108
- # Handle nodata values
109
- if out_meta.get('nodata') is not None:
110
- nodata_mask = np.any(out_image == out_meta['nodata'], axis=0)
111
- preview_array[nodata_mask] = [0, 0, 0] # Black for nodata
112
-
113
- # Create matplotlib figure
114
- plt.style.use('default') # Ensure default style
115
- fig, ax = plt.subplots(figsize=(10, 8), dpi=100)
116
- ax.imshow(preview_array)
117
- ax.set_title(f"Clipped GeoTIFF - {output_filename}", fontsize=12, pad=20)
118
- ax.axis('off')
119
-
120
- # Save to memory buffer
121
- buf = BytesIO()
122
- plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1, dpi=150)
123
- plt.close(fig) # Important: close figure to free memory
124
- buf.seek(0)
125
-
126
- # Convert to PIL image
127
- pil_image = Image.open(buf).convert("RGB")
128
- buf.close()
129
-
130
- return pil_image, output_tif_path
131
-
132
- except Exception as e:
133
- error_msg = f"Error during processing: {str(e)}"
134
- print(f"[ERROR] {error_msg}")
135
-
136
- # Create error image
137
- error_image = Image.new('RGB', (400, 200), color='white')
138
- from PIL import ImageDraw, ImageFont
139
- draw = ImageDraw.Draw(error_image)
140
- try:
141
- font = ImageFont.truetype("arial.ttf", 16)
142
- except:
143
- font = ImageFont.load_default()
144
-
145
- draw.text((10, 10), "Processing Error:", fill='red', font=font)
146
- draw.text((10, 40), str(e)[:50] + "..." if len(str(e)) > 50 else str(e), fill='black', font=font)
147
-
148
- return error_image, None
149
-
150
- finally:
151
- # Clean up temporary directory
152
- if temp_dir and os.path.exists(temp_dir):
153
- try:
154
- shutil.rmtree(temp_dir)
155
- except:
156
- pass # Ignore cleanup errors
157
-
158
-
159
- # Gradio Interface
160
- with gr.Blocks(title="GeoTIFF Clipper", theme=gr.themes.Soft()) as app:
161
- gr.Markdown("""
162
- # 🛰️ GeoTIFF Clipping with Shapefile
163
-
164
- This tool allows you to clip GeoTIFF images using shapefiles as clipping masks.
165
-
166
- **Instructions:**
167
- 1. Upload a GeoTIFF file (.tif)
168
- 2. Upload a ZIP file containing the shapefile (.shp, .dbf, .shx, .prj)
169
- 3. Click "Execute Clipping"
170
- 4. View the result and download the clipped file
171
- """)
172
-
173
- with gr.Row():
174
- with gr.Column():
175
- geotiff_input = gr.File(
176
- label="📁 GeoTIFF File (.tif)",
177
- file_types=[".tif", ".tiff"],
178
- type="filepath" # Changed from "binary" to "filepath"
179
- )
180
- shapefile_input = gr.File(
181
- label="📁 Shapefile ZIP (.zip)",
182
- file_types=[".zip"],
183
- type="filepath" # Changed from "binary" to "filepath"
184
- )
185
- run_button = gr.Button("🚀 Execute Clipping", variant="primary", size="lg")
186
-
187
- with gr.Row():
188
- with gr.Column():
189
- preview_output = gr.Image(
190
- label="🖼️ Result Preview",
191
- type="pil",
192
- height=400
193
- )
194
- with gr.Column():
195
- tif_output = gr.File(
196
- label="💾 Download Clipped GeoTIFF",
197
- type="filepath"
198
- )
199
-
200
- # Connect function to button
201
- run_button.click(
202
- fn=clip_geotiff,
203
- inputs=[geotiff_input, shapefile_input],
204
- outputs=[preview_output, tif_output]
205
- )
206
-
207
- gr.Markdown("""
208
- ---
209
- **Notes:**
210
- - The shapefile ZIP must contain at least .shp, .dbf and .shx files
211
- - Coordinate systems will be automatically adjusted if necessary
212
- - Preview is automatically generated for visualization
213
- """)
214
-
215
- # Configure for Hugging Face Spaces
216
- if __name__ == "__main__":
217
- app.launch(
218
- server_name="0.0.0.0", # Required for Hugging Face Spaces
219
- server_port=7860, # Default Hugging Face Spaces port
220
- share=False # Don't create additional public link
221
- )
222
-