N00bML commited on
Commit
e58cb34
·
verified ·
1 Parent(s): ac8c3a0

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -0
app.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joblib
2
+ import rasterio
3
+ import numpy as np
4
+ import gradio as gr
5
+ import matplotlib.pyplot as plt
6
+ import os
7
+
8
+
9
+ model = joblib.load('isolation_forest_ndvi.pkl')
10
+ print("Model loaded successfully!")
11
+
12
+
13
+ TRAINING_FOLDER = 'NDVI_Images'
14
+ training_files = sorted([f for f in os.listdir(TRAINING_FOLDER) if f.endswith('.tif')])
15
+ print(f"Found {len(training_files)} training files")
16
+
17
+
18
+ def predict_anomaly(ndvi_file):
19
+
20
+ print(f"Reading uploaded file: {ndvi_file}")
21
+ with rasterio.open(ndvi_file) as src:
22
+ user_ndvi = src.read(1)
23
+ print(f"User NDVI shape: {user_ndvi.shape}")
24
+
25
+ # Stack
26
+ full_stack = [user_ndvi]
27
+
28
+ # Only take up to 23 more images (or less if we don't have 24 total)
29
+ num_additional = min(23, len(training_files))
30
+ for i in range(num_additional):
31
+ file_path = os.path.join(TRAINING_FOLDER, training_files[i])
32
+ with rasterio.open(file_path) as src:
33
+ full_stack.append(src.read(1))
34
+
35
+ print(f"Total images in stack: {len(full_stack)}")
36
+
37
+ ndvi_stack = np.array(full_stack) # shape: (time, height, width)
38
+ time, height, width = ndvi_stack.shape
39
+ print(f"Stack shape: {ndvi_stack.shape}")
40
+
41
+ # Reshape for model
42
+ X_new = ndvi_stack.reshape(time, height * width).T
43
+ print(f"Reshaped for prediction: {X_new.shape}")
44
+
45
+ # Predict anomalies
46
+ y_pred = model.predict(X_new) # -1 = anomaly, 1 = normal
47
+ print(f"Predictions - Unique values: {np.unique(y_pred, return_counts=True)}")
48
+
49
+ anomaly_map = y_pred.reshape(height, width)
50
+ return anomaly_map, user_ndvi
51
+
52
+
53
+ def show_anomaly(ndvi_file):
54
+ """Generate and display anomaly map"""
55
+ try:
56
+ anomaly_map, original_ndvi = predict_anomaly(ndvi_file)
57
+
58
+ # Create a figure with two subplots
59
+ fig, axes = plt.subplots(1, 2, figsize=(14, 6))
60
+
61
+ im1 = axes[0].imshow(original_ndvi, cmap='RdYlGn', vmin=-1, vmax=1)
62
+ axes[0].set_title('Original NDVI', fontsize=14, fontweight='bold')
63
+ axes[0].axis('off')
64
+ plt.colorbar(im1, ax=axes[0], fraction=0.046, pad=0.04)
65
+
66
+ # Plot anomaly map
67
+ anomaly_visual = (anomaly_map + 1) / 2 # Maps -1→0 (anomaly), 1→1 (normal)
68
+
69
+ im2 = axes[1].imshow(anomaly_visual, cmap='RdYlGn', vmin=0, vmax=1)
70
+ axes[1].set_title('Anomaly Detection\n(Red=Anomaly, Green=Normal)',
71
+ fontsize=14, fontweight='bold')
72
+ axes[1].axis('off')
73
+ plt.colorbar(im2, ax=axes[1], fraction=0.046, pad=0.04,
74
+ label='0=Anomaly, 1=Normal')
75
+
76
+ # Calculate statistics
77
+ num_anomalies = np.sum(anomaly_map == -1)
78
+ total_pixels = anomaly_map.size
79
+ pct_anomaly = (num_anomalies / total_pixels) * 100
80
+
81
+ fig.suptitle(f'Anomaly Detection Results\n{num_anomalies:,} anomalous pixels ({pct_anomaly:.2f}%)',
82
+ fontsize=16, fontweight='bold', y=1.02)
83
+
84
+ plt.tight_layout()
85
+
86
+ # Save the figure
87
+ output_path = 'anomaly_result.png'
88
+ plt.savefig(output_path, dpi=150, bbox_inches='tight')
89
+ plt.close()
90
+
91
+ print(f"Saved result to {output_path}")
92
+ print(f"Anomaly statistics: {num_anomalies}/{total_pixels} pixels ({pct_anomaly:.2f}%)")
93
+
94
+ return output_path
95
+
96
+ except Exception as e:
97
+ print(f"Error in show_anomaly: {str(e)}")
98
+ import traceback
99
+ traceback.print_exc()
100
+
101
+ # Return an error image
102
+ fig, ax = plt.subplots(figsize=(8, 6))
103
+ ax.text(0.5, 0.5, f'Error processing image:\n{str(e)}',
104
+ ha='center', va='center', fontsize=12, color='red')
105
+ ax.axis('off')
106
+ error_path = 'error.png'
107
+ plt.savefig(error_path)
108
+ plt.close()
109
+ return error_path
110
+
111
+
112
+ # Create Gradio interface
113
+ iface = gr.Interface(
114
+ fn=show_anomaly,
115
+ inputs=gr.File(label="Upload NDVI GeoTIFF file (.tif)", file_types=['.tif']),
116
+ outputs=gr.Image(label="Anomaly Detection Result", type="filepath"),
117
+ title="🌿 Vegetation Anomaly Detection",
118
+ description="""
119
+ Upload an NDVI GeoTIFF image to detect vegetation anomalies using Isolation Forest.
120
+
121
+ - **Red areas**: Anomalous vegetation patterns
122
+ - **Green areas**: Normal vegetation patterns
123
+
124
+ The model uses temporal patterns from 24 months of training data to identify unusual changes.
125
+ """,
126
+ examples=None
127
+ )
128
+
129
+ if __name__ == "__main__":
130
+ print("\nStarting Gradio interface...")
131
+ print("Make sure 'isolation_forest_ndvi.pkl' and 'NDVI_Images/' folder are in the same directory")
132
+ iface.launch(share=False)