Spaces:
Runtime error
Runtime error
update app.py
Browse files
app.py
CHANGED
@@ -1,103 +1,117 @@
|
|
|
|
1 |
import gradio as gr
|
2 |
from ultralytics import YOLO
|
3 |
import cv2
|
4 |
import numpy as np
|
5 |
import torch
|
6 |
-
import wikipedia
|
7 |
from PIL import Image
|
8 |
import pandas as pd
|
9 |
import os
|
10 |
import uuid
|
11 |
from datetime import datetime
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
17 |
midas.to("cpu").eval()
|
18 |
-
midas_transforms = torch.hub.load("intel-isl/MiDaS", "transforms").small_transform
|
19 |
|
20 |
-
#
|
|
|
|
|
21 |
csv_file = "tree_measurements.csv"
|
22 |
if not os.path.exists(csv_file):
|
23 |
-
pd.DataFrame(columns=[
|
24 |
-
"Timestamp", "Latitude", "Longitude", "H3_Index",
|
25 |
-
"Estimated_Height", "Species", "Image_File"
|
26 |
-
]).to_csv(csv_file, index=False)
|
27 |
|
28 |
-
#
|
29 |
-
def
|
30 |
-
return
|
31 |
|
32 |
-
#
|
33 |
-
|
|
|
|
|
34 |
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
35 |
img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
36 |
|
37 |
-
#
|
38 |
-
results =
|
39 |
detections = results[0].boxes.data.cpu().numpy()
|
40 |
-
|
41 |
if len(detections) == 0:
|
42 |
-
return "No tree detected",
|
43 |
|
44 |
-
# Crop
|
45 |
x1, y1, x2, y2, conf, cls = detections[0]
|
46 |
tree_crop = img_cv[int(y1):int(y2), int(x1):int(x2)]
|
47 |
|
48 |
-
#
|
49 |
input_tensor = midas_transforms(Image.fromarray(cv2.cvtColor(tree_crop, cv2.COLOR_BGR2RGB))).unsqueeze(0)
|
50 |
with torch.no_grad():
|
51 |
depth = midas(input_tensor).squeeze().cpu().numpy()
|
52 |
approx_height = round(np.max(depth) - np.min(depth), 2)
|
53 |
|
54 |
-
#
|
55 |
-
|
56 |
|
57 |
-
#
|
58 |
-
|
59 |
-
species_guess = wikipedia.summary("tree", sentences=1)
|
60 |
-
except:
|
61 |
-
species_guess = "Could not retrieve species info"
|
62 |
|
63 |
-
# Save image
|
64 |
image_id = f"tree_{uuid.uuid4().hex[:8]}.png"
|
65 |
image.save(image_id)
|
66 |
|
67 |
-
#
|
68 |
-
|
69 |
"Timestamp": timestamp,
|
70 |
-
"Latitude": latitude,
|
71 |
-
"Longitude": longitude,
|
72 |
-
"H3_Index": h3_index,
|
73 |
"Estimated_Height": approx_height,
|
74 |
-
"Species":
|
|
|
|
|
|
|
75 |
"Image_File": image_id
|
76 |
}])
|
77 |
-
|
78 |
-
|
79 |
-
return (
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
)
|
85 |
|
86 |
-
#
|
87 |
-
|
88 |
-
fn=process_tree_image,
|
89 |
-
inputs=[
|
90 |
-
gr.Image(type="pil", label="πΈ Capture Tree Image"),
|
91 |
-
gr.Number(label="π Latitude"),
|
92 |
-
gr.Number(label="π Longitude")
|
93 |
-
],
|
94 |
-
outputs=[
|
95 |
-
gr.Textbox(label="π Tree Info"),
|
96 |
-
gr.Image(label="πΌοΈ Captured Image")
|
97 |
-
],
|
98 |
-
title="π³ Tree Height & Species Estimator",
|
99 |
-
description="Use your webcam or upload an image of a tree. Enter your GPS location to get height, species info, and H3 geolocation. All data is saved to CSV."
|
100 |
-
)
|
101 |
-
|
102 |
-
interface.launch()
|
103 |
|
|
|
1 |
+
# app.py
|
2 |
import gradio as gr
|
3 |
from ultralytics import YOLO
|
4 |
import cv2
|
5 |
import numpy as np
|
6 |
import torch
|
|
|
7 |
from PIL import Image
|
8 |
import pandas as pd
|
9 |
import os
|
10 |
import uuid
|
11 |
from datetime import datetime
|
12 |
+
import h3
|
13 |
+
import folium
|
14 |
+
|
15 |
+
# ========================
|
16 |
+
# Load Models
|
17 |
+
# ========================
|
18 |
+
yolo_model = YOLO("yolov8n.pt")
|
19 |
+
midas = torch.hub.load("intel-isl/MiDaS", "MiDaS_small", trust_repo=True)
|
20 |
midas.to("cpu").eval()
|
21 |
+
midas_transforms = torch.hub.load("intel-isl/MiDaS", "transforms", trust_repo=True).small_transform
|
22 |
|
23 |
+
# ========================
|
24 |
+
# CSV Initialization
|
25 |
+
# ========================
|
26 |
csv_file = "tree_measurements.csv"
|
27 |
if not os.path.exists(csv_file):
|
28 |
+
pd.DataFrame(columns=["Timestamp", "Estimated_Height", "Species", "Lat", "Lon", "H3_Index", "Image_File"]).to_csv(csv_file, index=False)
|
|
|
|
|
|
|
29 |
|
30 |
+
# Dummy Tree Classifier (replace with a real model or API later)
|
31 |
+
def classify_species(image):
|
32 |
+
return "Unknown Species"
|
33 |
|
34 |
+
# ========================
|
35 |
+
# Tree Processing Function
|
36 |
+
# ========================
|
37 |
+
def process_tree(image, lat, lon):
|
38 |
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
39 |
img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
40 |
|
41 |
+
# Run YOLOv8 detection
|
42 |
+
results = yolo_model(img_cv)
|
43 |
detections = results[0].boxes.data.cpu().numpy()
|
|
|
44 |
if len(detections) == 0:
|
45 |
+
return "No tree detected.", None, None
|
46 |
|
47 |
+
# Crop first detected tree
|
48 |
x1, y1, x2, y2, conf, cls = detections[0]
|
49 |
tree_crop = img_cv[int(y1):int(y2), int(x1):int(x2)]
|
50 |
|
51 |
+
# Estimate height from depth
|
52 |
input_tensor = midas_transforms(Image.fromarray(cv2.cvtColor(tree_crop, cv2.COLOR_BGR2RGB))).unsqueeze(0)
|
53 |
with torch.no_grad():
|
54 |
depth = midas(input_tensor).squeeze().cpu().numpy()
|
55 |
approx_height = round(np.max(depth) - np.min(depth), 2)
|
56 |
|
57 |
+
# Species classification
|
58 |
+
species = classify_species(image)
|
59 |
|
60 |
+
# Location and H3
|
61 |
+
h3_index = h3.geo_to_h3(lat, lon, 9)
|
|
|
|
|
|
|
62 |
|
63 |
+
# Save image
|
64 |
image_id = f"tree_{uuid.uuid4().hex[:8]}.png"
|
65 |
image.save(image_id)
|
66 |
|
67 |
+
# Save to CSV
|
68 |
+
new_entry = pd.DataFrame([{
|
69 |
"Timestamp": timestamp,
|
|
|
|
|
|
|
70 |
"Estimated_Height": approx_height,
|
71 |
+
"Species": species,
|
72 |
+
"Lat": lat,
|
73 |
+
"Lon": lon,
|
74 |
+
"H3_Index": h3_index,
|
75 |
"Image_File": image_id
|
76 |
}])
|
77 |
+
new_entry.to_csv(csv_file, mode='a', header=False, index=False)
|
78 |
+
|
79 |
+
return f"Height: {approx_height} meters\nSpecies: {species}", Image.fromarray(tree_crop), generate_map()
|
80 |
+
|
81 |
+
# ========================
|
82 |
+
# Folium Map from CSV
|
83 |
+
# ========================
|
84 |
+
def generate_map():
|
85 |
+
df = pd.read_csv(csv_file)
|
86 |
+
fmap = folium.Map(location=[20, 78], zoom_start=5)
|
87 |
+
for _, row in df.iterrows():
|
88 |
+
folium.Marker(
|
89 |
+
location=[row["Lat"], row["Lon"]],
|
90 |
+
popup=f"{row['Timestamp']}\n{row['Species']}\n{row['Estimated_Height']} m"
|
91 |
+
).add_to(fmap)
|
92 |
+
fmap.save("map.html")
|
93 |
+
return "map.html"
|
94 |
+
|
95 |
+
# ========================
|
96 |
+
# Gradio UI
|
97 |
+
# ========================
|
98 |
+
with gr.Blocks() as demo:
|
99 |
+
gr.Markdown("## π³ Tree Height & Species Estimator")
|
100 |
+
with gr.Row():
|
101 |
+
image_input = gr.Image(type="pil", label="Capture/Upload Tree Photo")
|
102 |
+
lat_input = gr.Number(label="Latitude")
|
103 |
+
lon_input = gr.Number(label="Longitude")
|
104 |
+
submit_btn = gr.Button("Estimate Height & Species")
|
105 |
+
output_text = gr.Textbox(label="Result")
|
106 |
+
output_image = gr.Image(label="Detected Tree")
|
107 |
+
output_map = gr.HTML(label="Tree Map")
|
108 |
+
|
109 |
+
submit_btn.click(
|
110 |
+
fn=process_tree,
|
111 |
+
inputs=[image_input, lat_input, lon_input],
|
112 |
+
outputs=[output_text, output_image, output_map]
|
113 |
)
|
114 |
|
115 |
+
# ========================
|
116 |
+
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
|