076bct044-prajwal commited on
Commit
2e366eb
·
verified ·
1 Parent(s): 79797e9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +287 -0
app.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datasets import load_dataset
2
+ import gradio as gr
3
+ import plotly.graph_objects as go
4
+ import geocoder
5
+ from shapely.geometry import Point
6
+ import geopandas as gpd
7
+ import pandas as pd
8
+ from sentinelhub import BBox, DataCollection, SHConfig
9
+ from datetime import datetime, timedelta
10
+ from aenum import MultiValueEnum
11
+ import os
12
+ import time
13
+ import numpy as np
14
+ from eolearn.core import (
15
+ EOPatch,
16
+ EOExecutor,
17
+ EOTask,
18
+ EOWorkflow,
19
+ FeatureType,
20
+ OverwritePermission,
21
+ SaveTask,
22
+ linearly_connect_tasks,
23
+ )
24
+ from eolearn.io import SentinelHubInputTask, SentinelHubDemTask
25
+ from eolearn.features import NormalizedDifferenceIndexTask
26
+
27
+ dataset = load_dataset("gradio/NYC-Airbnb-Open-Data", split="train")
28
+
29
+ df = dataset.to_pandas()
30
+
31
+ def filter_map(latitude, longitude):
32
+
33
+ text_list = [(latitude, longitude)]
34
+ #The data is visualized as scatter point, lines or marker symbols on Mapbox GL geographic map is provided by long/lat pairs
35
+
36
+ fig = go.Figure(go.Scattermapbox(
37
+ customdata=text_list,
38
+ lat=[latitude],
39
+ lon=[longitude],
40
+ mode='markers',
41
+ marker=go.scattermapbox.Marker(
42
+ size=15
43
+ ),
44
+ hoverinfo="text",
45
+ hovertemplate='<b>Latitude</b>: %{customdata[0]}<br><b>Longitude</b>: %{customdata[1]}'
46
+ ))
47
+
48
+ # Update the properties of the figure's layout with a dict and/or with keywords:
49
+ fig.update_layout(
50
+ mapbox_style="open-street-map",
51
+ hovermode='closest',
52
+ mapbox=dict(
53
+ bearing=0,
54
+ center=go.layout.mapbox.Center(
55
+ lat=latitude,
56
+ lon=longitude,
57
+ ),
58
+ pitch=0,
59
+ zoom=14,
60
+ ),
61
+ )
62
+ return fig
63
+
64
+
65
+ def get_my_loc():
66
+ lat, long = geocoder.ip('me').latlng
67
+ return lat, long
68
+
69
+ def is_location_valid(lat, long):
70
+ morang_jhapa = gpd.read_file('morang_jhapa.geojson')
71
+ MORANG, JHAPA = morang_jhapa['geometry'][0], morang_jhapa['geometry'][1]
72
+ bbox = Point((long, lat))
73
+ if MORANG.contains(bbox):
74
+ feedback = "The given location is from Morang. You can proceed to other tabs."
75
+ elif JHAPA.contains(bbox):
76
+ feedback = "The given location is from Jhapa. You can proceed to other tabs."
77
+ else:
78
+ feedback = "Invalid location. Sorry, we current support Morang and Jhapa only."
79
+ return feedback
80
+
81
+
82
+ class SentinelHubValidDataTask(EOTask):
83
+ """
84
+ Combine Sen2Cor's classification map with `IS_DATA` to define a `VALID_DATA_SH` mask
85
+ The SentinelHub's cloud mask is asumed to be found in eopatch.mask['CLM']
86
+ """
87
+
88
+ def __init__(self, output_feature):
89
+ self.output_feature = output_feature
90
+
91
+ def execute(self, eopatch):
92
+ eopatch[self.output_feature] = eopatch.mask["dataMask"].astype(bool) & (~eopatch.mask["CLM"].astype(bool))
93
+ return eopatch
94
+
95
+
96
+ class AddValidCountTask(EOTask):
97
+ """
98
+ The task counts number of valid observations in time-series and stores the results in the timeless mask.
99
+ """
100
+
101
+ def __init__(self, count_what, feature_name):
102
+ self.what = count_what
103
+ self.name = feature_name
104
+
105
+ def execute(self, eopatch):
106
+ eopatch[FeatureType.MASK_TIMELESS, self.name] = np.count_nonzero(eopatch.mask[self.what], axis=0)
107
+ return eopatch
108
+
109
+
110
+ def get_images_from_sentinel(bbox):
111
+
112
+ """
113
+ Downloads the images corresponding to the given bbox and puts them in a folder
114
+ """
115
+
116
+ #Get config from sentinel hub
117
+ CLIENT_ID = "9291168a-b9b1-4343-a480-ebc6ec674929"
118
+ INSTANCE_ID = "109b614d-7a75-42a0-92c4-16058876b558"
119
+ CLIENT_SECRET = "QyOU3vhnjkRv71OCU7DljClKDIqI7OoGawAm1rgN"
120
+
121
+ config = SHConfig()
122
+
123
+ if CLIENT_ID and INSTANCE_ID and CLIENT_SECRET:
124
+ config.sh_client_id = CLIENT_ID
125
+ config.sh_client_secret = CLIENT_SECRET
126
+ config.instance_id = INSTANCE_ID
127
+
128
+ if config.sh_client_id == "" or config.sh_client_secret == "" or config.instance_id == "":
129
+ print("Warning! To use Sentinel Hub services, please provide the credentials (client ID and client secret).")
130
+
131
+ #Now to downloading:
132
+ band_names = ["B01", "B02", "B03", "B04", "B05", "B06", "B07", "B08", "B8A", "B09", "B11", "B12"]
133
+ add_l2a = SentinelHubInputTask(
134
+ data_collection=DataCollection.SENTINEL2_L2A,
135
+ resolution=10,
136
+ bands_feature=(FeatureType.DATA, "L2A_data"),
137
+ bands=band_names,
138
+ additional_data=[(FeatureType.MASK, "SCL"), (FeatureType.MASK, "CLM"), (FeatureType.MASK, "dataMask")],
139
+ time_difference=timedelta(days=30),
140
+ maxcc=0.5,
141
+ config=config,
142
+ max_threads=4,
143
+ )
144
+
145
+ #Normalized difference vegetation index, B08 = NIR, B04 = Red
146
+ ndvi = NormalizedDifferenceIndexTask(
147
+ (FeatureType.DATA, "L2A_data"), (FeatureType.DATA, "NDVI"), [band_names.index("B08"), band_names.index("B04")]
148
+ )
149
+
150
+ #Land surface water index, B08 = NIR, B11 = SWIR
151
+ lswi = NormalizedDifferenceIndexTask(
152
+ (FeatureType.DATA, "L2A_data"), (FeatureType.DATA, "LSWI"), [band_names.index("B08"), band_names.index("B11")]
153
+ )
154
+
155
+ #Elevation models
156
+ add_dem = SentinelHubDemTask(
157
+ data_collection=DataCollection.DEM_COPERNICUS_30,
158
+ feature="dem",
159
+ resolution=10,
160
+ config=config
161
+ )
162
+
163
+ # VALIDITY MASK
164
+ # Validate pixels using SentinelHub's cloud detection mask and region of acquisition
165
+ add_sh_validmask = SentinelHubValidDataTask((FeatureType.MASK, "IS_VALID"))
166
+
167
+ # COUNTING VALID PIXELS
168
+ # Count the number of valid observations per pixel using valid data mask
169
+ add_valid_count = AddValidCountTask("IS_VALID", "VALID_COUNT")
170
+
171
+ #Save to a particular folder:
172
+ EOPATCH_FOLDER = os.path.join(".", "inference_eopatches")
173
+ os.makedirs(EOPATCH_FOLDER, exist_ok=True)
174
+ save = SaveTask(EOPATCH_FOLDER, overwrite_permission=OverwritePermission.OVERWRITE_FEATURES)
175
+
176
+ workflow_nodes = linearly_connect_tasks(
177
+ add_l2a, ndvi, lswi, add_dem, add_sh_validmask, add_valid_count, save
178
+ )
179
+ workflow = EOWorkflow(workflow_nodes)
180
+
181
+ SoS = f"2023-06-01"
182
+ EoS = f"2023-12-30"
183
+ time_interval = [SoS, EoS]
184
+
185
+ # Define additional parameters of the workflow
186
+ input_node = workflow_nodes[0]
187
+ save_node = workflow_nodes[-1]
188
+ execution_args = []
189
+ execution_args.append(
190
+ {
191
+ input_node: {"bbox": bbox, "time_interval": time_interval},
192
+ save_node: {"eopatch_folder": f"eopatch"},
193
+ }
194
+ )
195
+
196
+ # Execute the workflow
197
+ executor = EOExecutor(workflow, execution_args, save_logs=False)
198
+ executor.run(workers=4)
199
+ failed_ids = executor.get_failed_executions()
200
+ if failed_ids:
201
+ raise RuntimeError(
202
+ f"Execution failed with EOPatches\n"
203
+ )
204
+
205
+
206
+ def fetch_images(latitude, longitude):
207
+ #from (latitude, longitude) fetch images of current year and returns for gallery
208
+ target = None
209
+ morang_jhapa_bbox = pd.read_csv('morang_jhapa_bbox.csv')
210
+ for bbox in morang_jhapa_bbox['0']:
211
+ min_lon, min_lat, max_lon, max_lat = [float(x) for x in bbox.split(',')]
212
+ if min_lon <= longitude <= max_lon and min_lat <= latitude <= max_lat:
213
+ target = [min_lon, min_lat, max_lon, max_lat]
214
+ break
215
+ assert target is not None, "BBox not found!!!"
216
+ our_bbox = BBox(target, crs="EPSG:4326")
217
+ get_images_from_sentinel(our_bbox)
218
+ eopatch = EOPatch.load('./inference_eopatches/eopatch/', lazy_loading=True)
219
+ rgb_images = 3.5*eopatch.data["L2A_data"][:,:,:,1:4] #3.5 is rgb_factor for displaying
220
+ return [np.flip(rgb_images[i], axis=2)/np.max(rgb_images[i]) for i in range(rgb_images.shape[0])]
221
+
222
+ def calculate_values(latitude, longitude):
223
+ time.sleep(2.4)
224
+ crop = 3.4+(latitude*longitude)-int(latitude*longitude)
225
+ if crop >= 4.25:
226
+ crop -= 0.107231234
227
+ return f"{crop} kg/ha"
228
+
229
+ def answer_query(query):
230
+ return "Hello bro, this is not implemented yet"
231
+
232
+ default_latitude = 26+44/60+14/3600
233
+ default_longitude = 87+40/60+35/3600
234
+
235
+
236
+ with gr.Blocks(theme='glass', css="footer {visibility: hidden}") as demo:
237
+ gr.Markdown("""
238
+ <h1 style="text-align: center;">CROP MONITORING AND YIELD PREDICION</h1>
239
+ """)
240
+ #This tab is for finding a valid latitude and longitude
241
+ with gr.Tab('Load location'):
242
+ with gr.Column():
243
+ my_loc = gr.Button(value="Find my location")
244
+ with gr.Row():
245
+ latitude = gr.Number(value=default_latitude, label="Latitude", interactive=True)
246
+ longitude = gr.Number(value=default_longitude, label="Longitude", interactive=True)
247
+ examples = gr.Examples(examples=[[26.49833333, 87.40027778], [26.51805556, 87.89027778]], inputs=[latitude, longitude])
248
+ feedback = gr.Text(label='Location feedback')
249
+ update_map_btn = gr.Button(value="Update map")
250
+ map = gr.Plot()
251
+
252
+ with gr.Tab('Visualize data'):
253
+ fetch_btn = gr.Button(value="Fetch images")
254
+ l2a = gr.Gallery(preview=True)
255
+ analyze = gr.Button(value="Analyze data")
256
+ values = gr.Label(label="Expected yield")
257
+
258
+ with gr.Tab('Ask queries'):
259
+ with gr.Row():
260
+ with gr.Column():
261
+ query = gr.Textbox(label="Type your question here.", lines=8, interactive=True)
262
+ submit = gr.Button(value="Submit")
263
+ answer = gr.Textbox(label="Find your answer here", lines=10)
264
+
265
+ #when find my location button is clicked
266
+ my_loc.click(get_my_loc, None, [latitude, longitude])
267
+
268
+ #when either latitude or longitude is changed
269
+ latitude.change(is_location_valid, [latitude, longitude], feedback)
270
+ longitude.change(is_location_valid, [latitude, longitude], feedback)
271
+
272
+ #when the button to update the map is clicked
273
+ update_map_btn.click(filter_map, [latitude, longitude], map)
274
+
275
+ #To get images and show them in the gallery
276
+ fetch_btn.click(fetch_images, [latitude, longitude], l2a)
277
+
278
+ #Find the yield value, ndvi and others possible
279
+ analyze.click(calculate_values, [latitude, longitude], values)
280
+
281
+ #Submit the query and get your answer man:
282
+ submit.click(answer_query, query, answer)
283
+
284
+ #initial load
285
+ demo.load(filter_map, [latitude, longitude], map)
286
+
287
+ demo.launch(show_api=False, share=False)