from detectree2model.predictions.predict import run_detectree2
from polygons_processing.postpprocess_detectree2 import postprocess
from generate_tree_images.generate_tree_images import generate_tree_images
from classification.classification_predict import classify
import os
import json
import gradio as gr
import rasterio
import geopandas as gpd
import plotly.graph_objects as go
import numpy as np
import ast
def row_to_feature(row):
if (row['geometry'].geom_type == 'Polygon'):
coordinates = row['geometry'].exterior.coords.xy
coordinate_list = [[x, y] for x, y in zip(coordinates[0], coordinates[1])]
feature = {
"id": row["id"],
"type": "Feature",
"properties": {"Confidence_score": row["Confidence_score"], "species": row['species']},
"geometry": {"type": "Polygon", "coordinates": [coordinate_list]},
}
return feature
def export_geojson(df, filename):
features = [row_to_feature(row) for idx, row in df.iterrows()]
feature_collection = {
"type": "FeatureCollection",
"crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::32720"}},
"features": features,
}
output_geojson = json.dumps(feature_collection)
with open(f"{filename}.geojson", "w") as f:
f.write(output_geojson)
print(f"GeoJSON data exported to '{filename}.geojson' file.")
def delete_files_in_directory(directory_path: str) -> None:
"""
Delete all files in the given directory.
:param directory_path: Path to the directory
"""
if not os.path.exists(directory_path):
return
if not os.path.isdir(directory_path):
raise ValueError(f"The provided path '{directory_path}' is not a valid directory.")
for filename in os.listdir(directory_path):
file_path = os.path.join(directory_path, filename)
if os.path.isfile(file_path):
os.remove(file_path)
print(f"Deleted file: {file_path}")
else:
print(f"Skipped non-file: {file_path}")
def process_image(image_path: str, progress: gr.Progress):
current_directory = os.getcwd()
output_directory = os.path.join(current_directory, "outputs")
if not os.path.exists(output_directory):
os.makedirs(output_directory)
progress(0, desc="Deleting files")
delete_files_in_directory("tiles")
delete_files_in_directory("tiles/predictions")
delete_files_in_directory("tiles/predictions_geo")
delete_files_in_directory("tree_images")
delete_files_in_directory("detected_trees")
progress(0.01, desc="Running detectree2")
run_detectree2(image_path, store_path=output_directory)
progress(0.2, desc="Ran detectree2")
processed_output_df = postprocess(output_directory + '/detectree2_delin.geojson', output_directory + '/processed_delin.geojson')
progress(0.4, desc="Post processed")
processed_geojson = output_directory + '/processed_delin.geojson'
progress(0.6, desc="Generating tree images")
generate_tree_images(processed_geojson, image_path)
progress(0.7, desc="Generated tree images")
output_folder = './tree_images'
processed_output_df = gpd.read_file(processed_geojson)
all_top_3_list = [] # Initialize an empty list to accumulate all top_3 lists
for file_name in os.listdir(output_folder):
file_path = os.path.join(output_folder, file_name)
probs = classify(file_path)
top_3 = probs.head(3)
top_3_list = [[cls, prob] for cls, prob in top_3.items()]
# Accumulate the top_3_list for each file
all_top_3_list.append(top_3_list)
# Assign the accumulated top_3_list to the 'species' column of the dataframe
processed_output_df['species'] = all_top_3_list
print(processed_output_df.head())
print(processed_output_df.columns)
final_output_path = 'result'
progress(0.8, desc="Exporting geojson")
export_geojson(processed_output_df, final_output_path)
progress(0.9, desc="Exported geojson")
return final_output_path, image_path
def plot_results(geojson_path, image_path):
with rasterio.open(image_path) as src:
tif_image = src.read([1, 2, 3]) # Read the first three bands (RGB)
tif_transform = src.transform
height, width = tif_image.shape[1], tif_image.shape[2]
# Read the GeoJSON file
geojson_data = gpd.read_file(geojson_path + '.geojson')
# Create Plotly figure
fig = go.Figure()
# Add image to the figure
fig.add_trace(go.Image(z=tif_image.transpose((1, 2, 0)), hoverinfo = 'none'))
# Add polygons to the plot
for idx, row in geojson_data.iterrows():
coordinates = row['geometry'].exterior.coords.xy
x, y = list(coordinates[0]), list(coordinates[1]) # Convert to list
# Transform coordinates to match image pixel space
x_transformed = [(xi - tif_transform.c) / tif_transform.a for xi in x]
y_transformed = [(yi - tif_transform.f) / tif_transform.e for yi in y]
species_info_str = row['species']
species_info = ast.literal_eval(species_info_str)
first_array = species_info[0]
second_array = species_info[1]
third_array = species_info[2]
confidence_score = row['Confidence_score']
hovertemplate = f"Polygon:
{idx}
Species and Probability:
{first_array}
{second_array}
{third_array}
Confidence:
{confidence_score}"
fig.add_trace(go.Scatter(
x=x_transformed,
y=y_transformed,
mode='lines',
name = '',
line=dict(color='red'),
hovertemplate=hovertemplate,
hoverinfo='text'
))
fig.update_layout(
title='TIF Image with Tree Crowns Overlay',
xaxis_title='X',
yaxis_title='Y',
showlegend=False, # Hide the legend
)
return fig
def greet(image_path: str, progress=gr.Progress()):
geojson_path, image_path = process_image(image_path, progress)
progress(0.0, desc="Plotting results")
fig = plot_results (geojson_path, image_path)
progress(1, desc="Plotted results")
return fig
#tif_file_name = "TreeCrownVectorDataset_761588_9673769_20_20_32720.tif"
#tif_input = "/Users/jonathanseele/ETH/Hackathons/EcoHackathon/WeCanopy/test/" + tif_file_name
# File paths
#tif_file_path = '/Users/taekim/ecohackathon/WeCanopy/test/TreeCrownVectorDataset_761588_9673769_20_20_32720.tif'
#geojson_file_path = '/Users/taekim/ecohackathon/WeCanopy/test/result.geojson'
# Read the TIF file
def main():
demo = gr.Interface(
fn=greet,
inputs=gr.File(type='filepath'),
outputs=gr.Plot(label="Tree Crowns"),
)
demo.queue()
demo.launch(server_name='0.0.0.0', debug=True, show_error=True)
if __name__ == "__main__":
main()