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.