File size: 4,048 Bytes
8ae2ea0
 
522e6eb
8ae2ea0
 
 
7f0ac64
 
 
 
c16916d
522e6eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7f0ac64
 
522e6eb
8ae2ea0
522e6eb
 
 
 
8ae2ea0
522e6eb
 
7f0ac64
522e6eb
 
8ae2ea0
522e6eb
7f0ac64
522e6eb
7f0ac64
522e6eb
7f0ac64
522e6eb
7f0ac64
522e6eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7f0ac64
c16916d
7f0ac64
522e6eb
7f0ac64
522e6eb
 
7f0ac64
522e6eb
 
c16916d
522e6eb
 
7f0ac64
522e6eb
c16916d
522e6eb
c16916d
522e6eb
c16916d
522e6eb
 
 
c16916d
522e6eb
 
 
 
 
c16916d
 
522e6eb
 
c16916d
 
522e6eb
 
c16916d
 
 
522e6eb
 
c16916d
522e6eb
 
 
8ae2ea0
522e6eb
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import gradio as gr
from ultralytics import YOLO
import torch
import cv2
import numpy as np
from PIL import Image
import pandas as pd
import os
import uuid
from datetime import datetime
import folium
from h3 import h3
import base64

# Load YOLO model for tree detection
model = YOLO("yolov8n.pt")

# Try loading MiDaS depth model
try:
    midas = torch.hub.load("intel-isl/MiDaS", "MiDaS_small", trust_repo=True)
    midas.to("cpu").eval()
    midas_transforms = torch.hub.load("intel-isl/MiDaS", "transforms", trust_repo=True).small_transform
    use_depth = True
except Exception as e:
    print(f"Depth model load failed: {e}")
    use_depth = False

# CSV file setup
csv_file = "tree_measurements.csv"
if not os.path.exists(csv_file):
    pd.DataFrame(columns=["Timestamp", "Latitude", "Longitude", "H3_Index", "Height", "Species", "Image_File"]).to_csv(csv_file, index=False)

# Dummy classifier
def classify_tree_species(image):
    # Placeholder - returns fixed label
    return "Generic Tree"

# Process function
def analyze_tree(image, latitude, longitude):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    image_np = np.array(image)
    img_cv = cv2.cvtColor(image_np, cv2.COLOR_RGB2BGR)

    results = model(img_cv)
    detections = results[0].boxes.data.cpu().numpy()

    if len(detections) == 0:
        return "No tree detected", image, "N/A", generate_map()

    # First detected tree
    x1, y1, x2, y2, conf, cls = detections[0]
    crop = img_cv[int(y1):int(y2), int(x1):int(x2)]
    tree_crop = Image.fromarray(cv2.cvtColor(crop, cv2.COLOR_BGR2RGB))

    # Depth estimation
    if use_depth:
        try:
            input_tensor = midas_transforms(tree_crop).unsqueeze(0)
            with torch.no_grad():
                depth = midas(input_tensor).squeeze().cpu().numpy()
            approx_height = round(np.max(depth) - np.min(depth), 2)
        except Exception:
            approx_height = "Unavailable"
    else:
        approx_height = "Unavailable"

    # Geolocation + H3 index
    h3_index = h3.geo_to_h3(float(latitude), float(longitude), 9)

    # Species
    species = classify_tree_species(tree_crop)

    # Save image
    image_id = f"tree_{uuid.uuid4().hex[:8]}.png"
    tree_crop.save(image_id)

    # Append to CSV
    pd.DataFrame([{
        "Timestamp": timestamp,
        "Latitude": latitude,
        "Longitude": longitude,
        "H3_Index": h3_index,
        "Height": approx_height,
        "Species": species,
        "Image_File": image_id
    }]).to_csv(csv_file, mode='a', header=False, index=False)

    return f"Height: {approx_height} units\nSpecies: {species}", tree_crop, species, generate_map()

# Render map
def generate_map():
    if not os.path.exists(csv_file):
        return "No map yet."

    df = pd.read_csv(csv_file)
    if df.empty:
        return "No map data."

    lat, lon = df.iloc[-1][["Latitude", "Longitude"]]
    fmap = folium.Map(location=[lat, lon], zoom_start=14)
    for _, row in df.iterrows():
        folium.Marker(
            location=[row["Latitude"], row["Longitude"]],
            popup=f"{row['Species']} ({row['Height']} units)"
        ).add_to(fmap)
    fmap.save("map.html")
    with open("map.html", "r", encoding="utf-8") as f:
        return f.read()

# Gradio UI
with gr.Blocks() as demo:
    gr.Markdown("## 🌳 Tree Height & Species Estimator with Map & Logger")

    with gr.Row():
        image_input = gr.Image(type="pil", label="πŸ“Έ Tree Image")
        lat_input = gr.Textbox(label="🌍 Latitude", placeholder="e.g., 12.9716")
        lon_input = gr.Textbox(label="🌍 Longitude", placeholder="e.g., 77.5946")

    btn = gr.Button("Analyze Tree")

    output_text = gr.Textbox(label="πŸ“ Results")
    output_crop = gr.Image(label="🌲 Detected Tree")
    output_species = gr.Textbox(label="🌳 Species")
    map_html = gr.HTML(label="πŸ—ΊοΈ Tree Map")

    btn.click(analyze_tree, inputs=[image_input, lat_input, lon_input],
              outputs=[output_text, output_crop, output_species, map_html])

demo.launch()