DEMO 3-3: DEM Visualization and Slope Analysis App

## Version 1 : Button Click
from osgeo import gdal,osr
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt

def Load_image_by_Gdal(file_path):
    img_file = gdal.Open(file_path, gdal.GA_ReadOnly)
    img_bands = img_file.RasterCount
    img_height = img_file.RasterYSize
    img_width = img_file.RasterXSize
    img_arr = img_file.ReadAsArray()
    geomatrix = img_file.GetGeoTransform()
    projection = img_file.GetProjectionRef()
    return img_bands,img_arr, geomatrix, projection

# Define the tiff reading function
def read_tiff(file):
    img_bands,img_arr, geomatrix, projection =Load_image_by_Gdal(file)
    if img_bands >1 :
        img_arr=img_arr.transpose(( 1, 2,0))
    return img_arr, geomatrix, projection

# Function to calculate and visualize slope from a DEM 
def calculate_slope(files,colormap='terrain'):
    print(files.name,colormap)
    file_patchs=files.name
    img_arr,_,_=read_tiff(file_patchs)
    dem_array=img_arr.copy()
    print(dem_array.shape,np.max(dem_array))
    # Calculate gradient in the x and y direction
    x_gradient = np.gradient(dem_array, axis=1)
    y_gradient = np.gradient(dem_array, axis=0)

    # Calculate slope
    slope = np.sqrt(x_gradient**2 + y_gradient**2)
    print(dem_array.shape,np.max(slope),np.min(slope))
    slope = np.clip(slope, 0, 90)/90
    cmap = plt.get_cmap(colormap)
    colormapped_slope = cmap(slope)
    slope_array = colormapped_slope[:, :, :3]  # Extract the RGB bands
    return dem_array/np.max(dem_array),slope_array

def showslope(dem_array,colormap='terrain'):
    x_gradient = np.gradient(dem_array, axis=1)
    y_gradient = np.gradient(dem_array, axis=0)
    slope = np.sqrt(x_gradient**2 + y_gradient**2)
    print(dem_array.shape,np.max(slope),np.min(slope))
    slope = np.clip(slope, 0, 90)/90
    cmap = plt.get_cmap(colormap)
    colormapped_slope = cmap(slope)
    slope_array = colormapped_slope[:, :, :3]  
    return slope_array

# Define the reset function
def reset_state():
    return None,None,None

# Define the visulization function
def show_dem(files):
    # print(files.name)
    file_patchs=files.name
    img_arr, _, _=read_tiff(file_patchs)
    dem_array=img_arr.copy()
    return dem_array/np.max(dem_array),dem_array

with gr.Blocks(theme="Gstaff/Xkcd") as demo: # other theme: ["Default", "Glass", "Monochrome","Gstaff/Xkcd", "NoCrypt/Miku", "gradio/soft"]
    demarray=gr.State(None)  # Define the temporary variable
    # Add an HTML header 
    gr.HTML("""
                <center> 
                <h1> DEM and Slope Visulization  🛰️ </h1>
                <b> jason.yu.mail@qq.com  📧<b>
                </center>
                """) 
    upload_button = gr.UploadButton("Click to Upload a DEM File", file_types=["image"], file_count="single") 
    with gr.Row():
        with gr.Column(scale=50):  
            choice=gr.Radio(choices=["rainbow","plasma","terrain"],label="Colormap") 
        with gr.Column(scale=50):  
            showdem = gr.Button("Showdem",variant="primary") 
            emptyBtn = gr.Button("Restart",variant="secondary")  # different button theme, variant="primary"
    with gr.Row():
        showimg=gr.Image(label="DEM")
        img_output = gr.Image(label="Slope")
    
    # Use temporary variable to recieve the result of the show_dem function
    upload_button.upload(show_dem, upload_button, [showimg,demarray])   
    # Define button click event to show the slope image
    showdem.click(showslope,[demarray,choice],[img_output])

    emptyBtn.click(reset_state,outputs=[upload_button,showimg,img_output],show_progress=True)  
        
demo.launch() 
## Version 2 : Event Listeners

from osgeo import gdal,osr
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt


def Load_image_by_Gdal(file_path):
    img_file = gdal.Open(file_path, gdal.GA_ReadOnly)
    img_bands = img_file.RasterCount
    img_height = img_file.RasterYSize
    img_width = img_file.RasterXSize
    img_arr = img_file.ReadAsArray()
    geomatrix = img_file.GetGeoTransform()
    projection = img_file.GetProjectionRef()
    return img_bands,img_arr, geomatrix, projection

# Define the tiff reading function
def read_tiff(file):
    img_bands,img_arr, geomatrix, projection =Load_image_by_Gdal(file)
    if img_bands >1 :
        img_arr=img_arr.transpose(( 1, 2,0))
    return img_arr, geomatrix, projection

# Function to calculate and visualize slope from a DEM 
def calculate_slope(files,colormap='terrain'):
    print(files.name,colormap)
    file_patchs=files.name
    img_arr,_,_=read_tiff(file_patchs)
    dem_array=img_arr.copy()
    print(dem_array.shape,np.max(dem_array))
    # Calculate gradient in the x and y direction
    x_gradient = np.gradient(dem_array, axis=1)
    y_gradient = np.gradient(dem_array, axis=0)

    # Calculate slope
    slope = np.sqrt(x_gradient**2 + y_gradient**2)
    print(dem_array.shape,np.max(slope),np.min(slope))
    slope = np.clip(slope, 0, 90)/90
    cmap = plt.get_cmap(colormap)
    colormapped_slope = cmap(slope)
    slope_array = colormapped_slope[:, :, :3]  # Extract the RGB bands
    return dem_array/np.max(dem_array),slope_array

# Define the reset function
def reset_state():
    return None,None,None

# Define the visulization function
def show_dem(files):
    # print(files.name)
    file_patchs=files.name
    img_arr, _, _=read_tiff(file_patchs)
    dem_array=img_arr.copy()
    return dem_array/np.max(dem_array),dem_array


with gr.Blocks(theme="Gstaff/Xkcd") as demo: # other theme: ["Default", "Glass", "Monochrome","Gstaff/Xkcd", "NoCrypt/Miku", "gradio/soft"]
    # Add an HTML header 
    gr.HTML("""
                <center> 
                <h1> DEM and Slope Visulization  🛰️ </h1>
                <b> jason.yu.mail@qq.com  📧<b>
                </center>
                """)  
    upload_button = gr.UploadButton("Click to Upload a DEM File", file_types=["image"], file_count="single") 
    with gr.Row():
        with gr.Column(scale=50):  
            choice=gr.Radio(choices=["rainbow","plasma","terrain"],label="Colormap") 
        with gr.Column(scale=50):  
            emptyBtn = gr.Button("Restart",variant="secondary")  # different button theme, variant="primary"
    with gr.Row():
        showimg=gr.Image(label="DEM")
        img_output = gr.Image(label="Slope")
        
    # Use button event listeners to active the show_dem function to process uploaded files
    upload_button.upload(calculate_slope, [upload_button], [showimg,img_output]) 
    choice.change(calculate_slope, [upload_button,choice], [showimg,img_output])

    emptyBtn.click(reset_state,outputs=[upload_button,showimg,img_output],show_progress=True)  
        
demo.launch()