Display an image, log a user response with ipywidgets, then display next image in a folder one at a time

20 Views Asked by At

I have a folder full of files with the extension .tif. They are just geospatial images which I am converting to numpy arrays and then displaying. My goal is to vizualize each image in the folder, register a user response with a button, which is one of three options, yes, no or maybe, then display the new image for the user to register their response again. The response is being appended to a pandas dataframe right now.

I can succesfully do this for one image, but I only want to generate one image at a time, then display the new image after the user responds. As of right now all of my images are displayed in my loop which is not what I am after. I am using an Ipython notebook right now, but am open to new ways too.

Here is my code:

import os
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import rioxarray
import ipywidgets as widgets
from IPython.display import display, clear_output
from IPython.display import Image as IPImage, display as IPdisplay
from mpl_toolkits.axes_grid1 import make_axes_locatable


# Set the path to your image folder
image_folder = 'tif_folder'

# Get a list of image files in the folder
image_files = [f for f in os.listdir(image_folder) if f.endswith(('tif'))]

#display images
def display_image(index):
    image_path = os.path.join(image_folder, image_files[index])
    # image = plt.imread(image_path)
    img = rioxarray.open_rasterio(os.path.join(image_path)).to_numpy()
    
    #dnbr
    dnbr = img[0, :, :]

    #y
    y = img[-1, :, :]

    #plot side by side
    fig, ax = plt.subplots(ncols = 2, nrows = 1, figsize = (12, 4))

    #plot y
    im = ax[0].imshow(y, origin = 'lower', cmap = 'RdYlBu_r', aspect= 'auto', vmin= 0, vmax=1)
    # ax[0,0].title.set_text('Fire')
    ax[0].title.set_text('y')

    divider = make_axes_locatable(ax[0])
    cax = divider.append_axes('right', size='5%', pad=0.05)
    fig.colorbar(im, cax=cax, orientation='vertical')

    #plot2
    # im2 = ax[0,1].imshow(in_mat[:, :, 0]/1000, origin = 'lower', cmap = 'Blues', aspect= 'auto')
    im2 = ax[1].imshow(dnbr, origin = 'lower', cmap = 'RdYlBu_r', aspect= 'auto', vmin=-800, vmax=1000)
    # ax[0,1].title.set_text('B1-Ultra Blue')
    ax[1].title.set_text('dNBR')
    divider = make_axes_locatable(ax[1])
    cax = divider.append_axes('right', size='5%', pad=0.05)
    fig.colorbar(im2, cax=cax, orientation='vertical')

    plt.subplots_adjust(wspace=0.3, hspace=0.4)
    
    # Use IPython.display to show the figure in the notebook
    display(fig)
    plt.close(fig)  # Close the figure to avoid displaying it twice
    # plt.show()
    
    
#on button click register response  
def on_button_clicked(b):
    global current_index, keep_df
    decision = b.description
    keep_df = pd.concat([keep_df, pd.DataFrame({'Image': [image_files[current_index]], 'Keep': [decision]})])
    next_image()

#show next image
def next_image():
    global current_index
    clear_output(wait=True)
    current_index += 1
    if current_index < len(image_files):
        display_image(current_index)
        display_buttons()
    else:
        print("All images reviewed. DataFrame:")
        print(keep_df)

#display buttons
def display_buttons():
    # Create Yes and No buttons
    yes_button = widgets.Button(description="Yes")
    no_button = widgets.Button(description="No")
    maybe_button = widgets.Button(description="Maybe")


    # Connect button callbacks
    yes_button.on_click(on_button_clicked)
    no_button.on_click(on_button_clicked)
    maybe_button.on_click(maybe_button)

    # Display buttons
    buttons = widgets.HBox([yes_button, no_button, maybe_button])
    display(buttons)

    
    
# Initialize variables
current_index = 0
keep_df = pd.DataFrame(columns=['Image', 'Keep'])

all_indexes = np.arange(0, len(image_files) + 1)

for current_index in all_indexes:
    
    # Display the first image and buttons
    display_image(current_index)
    display_buttons()
       
    #here I want it to pause and wait for a user to click yes, maybe or no, log the response then show the next image. but in this format all images are displayed

I don't know how to pause the loop and then use the next_image() function after a response is registered I don't think.

0

There are 0 best solutions below