Spaces:
Build error
Build error
File size: 9,832 Bytes
942a4e7 468ff63 942a4e7 468ff63 942a4e7 cef0cfd 9b964a4 468ff63 87cd5c2 c07e3a4 46b356d 9b964a4 ddcf446 efe8624 9a07d15 1bca2f2 cef0cfd ddcf446 cef0cfd ddcf446 efe8624 cef0cfd 7898f2e 9b964a4 17093b6 c07e3a4 46b356d c07e3a4 ddcf446 cef0cfd 17093b6 cef0cfd 17093b6 efe8624 a5dd34c 23ea141 468ff63 ddcf446 cef0cfd 04a844f ddcf446 cef0cfd ddcf446 efe8624 aefdf62 2cd8efe ddcf446 cef0cfd 1d9c61d 17093b6 efe8624 17093b6 efe8624 17093b6 cef0cfd 468ff63 ddcf446 cef0cfd 04a844f 468ff63 cef0cfd 46b356d 45a7dbe 46b356d 468ff63 6d3398e 1c05fc1 83b5039 438fcf3 0c94757 83b5039 438fcf3 e9dc4d9 0c94757 438fcf3 e9dc4d9 ce97f8d 774a4c9 a5dd34c 83b5039 774a4c9 e49d1f1 87cd5c2 1c05fc1 87cd5c2 1c05fc1 49883ce 2ea33c1 49883ce 1c05fc1 49883ce 87cd5c2 23ea141 87cd5c2 0c94757 a7969be 1b0235e a5dd34c 1b0235e b479b28 45a7dbe 17093b6 cef0cfd 17093b6 04a844f 17093b6 04a844f 17093b6 194da3d 17093b6 46b356d 26dea75 46b356d cef0cfd ddcf446 46b356d 194da3d 46b356d 468ff63 9af6198 f999af8 cef0cfd ce97f8d 468ff63 17093b6 468ff63 ddcf446 468ff63 ce97f8d 468ff63 46b356d 468ff63 a7969be a5dd34c a7969be a5dd34c a7969be a5dd34c a7969be |
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 7 13:43:34 2025
@author: camaac
"""
import streamlit as st
import os
import random
import pandas as pd
from PIL import Image, ImageEnhance
import numpy as np
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from skimage.exposure import match_histograms
import time
from streamlit_autorefresh import st_autorefresh
# -------------------------
# Global parameters
# -------------------------
IMAGE_DIR = "images" # Folder containing images
NUM_PAIRS = 25 # Total number of pairs to be assessed
RESULTS_FILE = "results.csv" # CSV file for saving responses
# -------------------------
# Helper functions
# -------------------------
def load_image_pair(index):
"""
For a given index (integer), returns the path of the ground truth and the path of AI generated image.
Files are named with a 5-digit index.
"""
idx_str = str(index).zfill(5)
gt_path = os.path.join(IMAGE_DIR, f"{idx_str}.png")
pred_path = os.path.join(IMAGE_DIR, f"{idx_str}_gen0.png")
return gt_path, pred_path
def match_brightness(source_img, target_img):
source_brightness = np.mean(np.array(source_img))
target_brightness = np.mean(np.array(target_img))
if target_brightness == 0:
factor = 1 # avoid division by zero
else:
factor = source_brightness / target_brightness
enhancer = ImageEnhance.Brightness(target_img)
adjusted = enhancer.enhance(factor)
return adjusted
def match_histograms_pil(img_reference, img_to_adjust):
"""
Layer the histogram of `img_reference` on `img_to_adjust`
(both images are PIL.Image objects).
Returns a PIL image with adjusted histogram.
"""
# Convertir les deux images en tableaux numpy
ref_array = np.array(img_reference)
adj_array = np.array(img_to_adjust)
# Ajuster l'histogramme
matched = match_histograms(adj_array, ref_array, channel_axis=-1)
# Reconvertir en image PIL
matched_img = Image.fromarray(np.uint8(matched))
return matched_img
# -------------------------
# Navigation via st.session_state
# -------------------------
if "page" not in st.session_state:
st.session_state.page = "intro"
if "user_name" not in st.session_state:
st.session_state.user_name = ""
if "current_index" not in st.session_state:
st.session_state.current_index = 0
if "results" not in st.session_state:
st.session_state.results = []
if "list_pair" not in st.session_state:
st.session_state.list_pair = []
if "list_pair_ID" not in st.session_state:
st.session_state.list_pair_ID = []
if "results_tot" not in st.session_state:
st.session_state.results_tot = 0
if "submitted" not in st.session_state:
st.session_state.submitted = False
# -------------------------
# Intro page
# -------------------------
if st.session_state.page == "intro":
st.title("AI Wood Generation Evaluation Study")
st.markdown(
"""
**Welcome!**
In this study, you will be shown pairs of wood surface images.
One image is a real photograph and the other is generated by AI.
Your task is to select the image you believe is **real**.
⌛ *Each image pair will be visible for 10 seconds only, be quick!* ⌛
Please enter your name below and click **Start Evaluation** to begin.
"""
)
name = st.text_input("Enter your name:")
if st.button("Start Evaluation") and name:
st.session_state.user_name = name
st.session_state.page = "evaluation"
st.rerun()
st.session_state.list_pair_ID = random.sample(range(1, 51), NUM_PAIRS)
for i, index in enumerate(st.session_state.list_pair_ID):
gt_path, pred_path = load_image_pair(index)
pair = [("GT", gt_path), ("Pred", pred_path)]
random.shuffle(pair)
st.session_state.list_pair.append(pair)
st.stop()
# -------------------------
# Evaluation page
# -------------------------
if st.session_state.page == "evaluation":
st.title("AI Wood Generation Evaluation")
# st.write(f"User: **{st.session_state.user_name}**")
if "start_time" not in st.session_state or st.session_state.page_changed:
st.session_state.start_time = time.time()
st.session_state.page_changed = False
# If all pairs have been evaluated, display a message and save the results
if st.session_state.current_index+1 > NUM_PAIRS:
st.markdown("<h4>How confident were you in your answers?</h4>", unsafe_allow_html=True)
confidence = st.radio( #st.select_slider
" ",
[
"Not confident at all",
"Slightly confident",
"Moderately confident",
"Very confident",
"Extremely confident"
],
index=2, #value="Moderately confident"
horizontal=True
)
if st.button("Submit"):
#Calculating result
correct_guess = np.array(st.session_state.results)
nb_correct = np.sum(correct_guess)
st.session_state.results_tot = nb_correct
st.success(f"Number of correct answers: {nb_correct}/{NUM_PAIRS}")
st.success("Thank you for completing the evaluation!", icon=":material/park:")
#Save result
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('glass-flux-456209-d4-6fc4b7d9d274.json', scope)
client = gspread.authorize(creds)
sh = client.open('Results_woodAI').worksheet('test')
row = [
st.session_state.user_name,
confidence,
str(nb_correct),
",".join(map(str, st.session_state.list_pair_ID)),
",".join(map(str, correct_guess)),
]
sh.append_row(row)
st.session_state.submitted = True
# if st.button("See detailed results"):
# st.session_state.page = "detailed_results"
# st.rerun()
if st.session_state.submitted == True:
if st.button("See detailed results"):
st.session_state.page = "detailed_results"
st.rerun()
# st.stop()
st.stop()
st_autorefresh(interval=1000, key=f"timer_{st.session_state.current_index}")
st.write(f"Image Pair {st.session_state.current_index+1} of {NUM_PAIRS}")
# Charger et mélanger la paire pour l'index courant
pair = st.session_state.list_pair[st.session_state.current_index]
img1 = Image.open(pair[0][1])
img1 = img1.convert("L")
img2 = Image.open(pair[1][1])
img2 = img2.convert("L")
# if pair[0][0] == "GT":
# img2 = match_brightness(img1, img2)
# else:
# img1 = match_brightness(img2, img1)
elapsed = time.time() - st.session_state.start_time
remaining = max(0, 10 - int(elapsed))
st.markdown(f"**Time remaining:** {remaining} seconds")
percent = int((remaining / 10) * 100)
st.progress(percent)
placeholder = Image.new("L", img1.size, 128)
col1, col2 = st.columns(2)
with col1:
if elapsed < 10:
st.image(img1, caption="Image 1", use_container_width=True)
else:
st.image(placeholder, caption="Time’s up!", use_container_width=True)
with col2:
if elapsed < 10:
st.image(img2, caption="Image 2", use_container_width=True)
else:
st.image(placeholder, caption="Time’s up!", use_container_width=True)
choice = st.radio("Select the real image: ", options=["1", "2"], horizontal = True) #, index=None
if st.button("Next"):
if (choice == "1" and pair[0][0] == "GT") or (choice == "2" and pair[1][0] == "GT"):
correct_guess = 1
else:
correct_guess = 0
st.session_state.results.append(correct_guess)
# Passer à la paire suivante
st.session_state.current_index += 1
st.session_state.start_time = time.time()
st.session_state.page_changed = True
st.rerun()
if st.session_state.page == "detailed_results":
st.title("Detailed Results")
results = np.array(st.session_state.results)
for i in range(NUM_PAIRS):
pair = st.session_state.list_pair[i]
if pair[0][0] == "GT":
imgGT = Image.open(pair[0][1])
imgGT = imgGT.convert("L")
imgPred = Image.open(pair[1][1])
imgPred = imgPred.convert("L")
else:
imgGT = Image.open(pair[1][1])
imgGT = imgGT.convert("L")
imgPred = Image.open(pair[0][1])
imgPred = imgPred.convert("L")
col1, col2 = st.columns(2)
with col1:
st.image(imgGT, caption="Real", use_container_width=True)
with col2:
st.image(imgPred, caption="AI", use_container_width=True)
result = results[i]
if result:
st.success("✅ Correct")
else:
st.error("❌ Incorrect")
st.markdown("---")
|