Update app.py
Browse files
app.py
CHANGED
|
@@ -195,6 +195,9 @@ if not master_image_list:
|
|
| 195 |
# #############################################################################
|
| 196 |
# ############# 函数修改点:get_next_trial_info ################################
|
| 197 |
# #############################################################################
|
|
|
|
|
|
|
|
|
|
| 198 |
def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_trial, num_trials_in_this_run_for_trial):
|
| 199 |
global TARGET_DIR, METHOD_ROOTS, SUBJECTS, SENTINEL_TRIAL_INTERVAL
|
| 200 |
global global_shown_pairs_cache, global_history_has_unsaved_changes, exhausted_target_images
|
|
@@ -206,10 +209,13 @@ def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_tri
|
|
| 206 |
target_full_path = os.path.join(TARGET_DIR, img_filename_original)
|
| 207 |
trial_number_for_display = current_trial_idx_in_run + 1
|
| 208 |
|
| 209 |
-
# ---- MODIFICATION START:
|
| 210 |
-
|
| 211 |
-
|
| 212 |
|
|
|
|
|
|
|
|
|
|
| 213 |
for m_root_path in METHOD_ROOTS:
|
| 214 |
method_name = os.path.basename(m_root_path)
|
| 215 |
|
|
@@ -228,12 +234,15 @@ def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_tri
|
|
| 228 |
internal_label = f"{method_name}/{s_id}/{reconstructed_filename}"
|
| 229 |
candidate_tuple = (internal_label, candidate_path)
|
| 230 |
|
| 231 |
-
#
|
| 232 |
if method_name == "image_flited":
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
trial_info = {"image_id": img_filename_original, "target_path": target_full_path, "cur_no": trial_number_for_display, "is_sentinel": False,
|
| 239 |
"left_display_label": "N/A", "left_internal_label": "N/A", "left_path": None,
|
|
@@ -242,15 +251,14 @@ def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_tri
|
|
| 242 |
is_potential_sentinel_trial = (trial_number_for_display > 0 and trial_number_for_display % SENTINEL_TRIAL_INTERVAL == 0)
|
| 243 |
|
| 244 |
if is_potential_sentinel_trial:
|
| 245 |
-
#
|
| 246 |
-
|
| 247 |
-
if not combined_pool:
|
| 248 |
print(f"警告:哨兵图 '{img_filename_original}' (trial {trial_number_for_display}) 无任何候选图。")
|
| 249 |
else:
|
| 250 |
print(f"生成哨兵试验 for '{img_filename_original}' (trial {trial_number_for_display})")
|
| 251 |
trial_info["is_sentinel"] = True
|
| 252 |
sentinel_candidate_target_tuple = ("目标图像", target_full_path)
|
| 253 |
-
random_reconstruction_candidate_tuple = random.choice(
|
| 254 |
candidates_for_sentinel = [
|
| 255 |
(("目标图像", target_full_path), sentinel_candidate_target_tuple[0]),
|
| 256 |
(("重建图", random_reconstruction_candidate_tuple[1]), random_reconstruction_candidate_tuple[0])
|
|
@@ -261,22 +269,22 @@ def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_tri
|
|
| 261 |
"right_display_label": candidates_for_sentinel[1][0][0], "right_path": candidates_for_sentinel[1][0][1], "right_internal_label": candidates_for_sentinel[1][1],
|
| 262 |
})
|
| 263 |
else: # 常规试验
|
| 264 |
-
# ---- MODIFICATION START:
|
| 265 |
-
#
|
| 266 |
-
if not
|
| 267 |
-
print(f"警告:常规图 '{img_filename_original}' (trial {trial_number_for_display})
|
| 268 |
-
f"('
|
| 269 |
-
f"
|
| 270 |
return None, current_trial_idx_in_run
|
| 271 |
|
| 272 |
target_global_history_set = global_shown_pairs_cache.setdefault(img_filename_original, set())
|
| 273 |
|
| 274 |
-
#
|
| 275 |
all_possible_pairs_in_pool = []
|
| 276 |
-
for
|
| 277 |
-
pair_labels_fset = frozenset({
|
| 278 |
-
all_possible_pairs_in_pool.append( ((
|
| 279 |
-
# ---- MODIFICATION END:
|
| 280 |
|
| 281 |
unseen_globally_pairs_with_data = [
|
| 282 |
item for item in all_possible_pairs_in_pool if item[1] not in target_global_history_set
|
|
@@ -290,7 +298,7 @@ def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_tri
|
|
| 290 |
target_global_history_set.add(chosen_pair_frozenset)
|
| 291 |
global_history_has_unsaved_changes = True
|
| 292 |
else:
|
| 293 |
-
print(f"警告:目标图 '{img_filename_original}' (trial {trial_number_for_display}): 所有 ({len(all_possible_pairs_in_pool)}) 个 '
|
| 294 |
if all_possible_pairs_in_pool:
|
| 295 |
print(f"目标图 '{img_filename_original}' 将被标记为已耗尽,未来轮次中将被跳过。")
|
| 296 |
exhausted_target_images.add(img_filename_original)
|
|
@@ -305,6 +313,7 @@ def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_tri
|
|
| 305 |
})
|
| 306 |
return trial_info, current_trial_idx_in_run + 1
|
| 307 |
|
|
|
|
| 308 |
# ==== 批量保存用户选择日志函数 (保持不变) ====
|
| 309 |
def save_single_log_to_hf_dataset(log_entry, user_identifier_str):
|
| 310 |
global DATASET_REPO_ID, INDIVIDUAL_LOGS_FOLDER
|
|
|
|
| 195 |
# #############################################################################
|
| 196 |
# ############# 函数修改点:get_next_trial_info ################################
|
| 197 |
# #############################################################################
|
| 198 |
+
# #############################################################################
|
| 199 |
+
# ############# 函数修改点:get_next_trial_info ################################
|
| 200 |
+
# #############################################################################
|
| 201 |
def get_next_trial_info(current_trial_idx_in_run, current_run_image_list_for_trial, num_trials_in_this_run_for_trial):
|
| 202 |
global TARGET_DIR, METHOD_ROOTS, SUBJECTS, SENTINEL_TRIAL_INTERVAL
|
| 203 |
global global_shown_pairs_cache, global_history_has_unsaved_changes, exhausted_target_images
|
|
|
|
| 209 |
target_full_path = os.path.join(TARGET_DIR, img_filename_original)
|
| 210 |
trial_number_for_display = current_trial_idx_in_run + 1
|
| 211 |
|
| 212 |
+
# ---- MODIFICATION START: 创建两个用于特定方法对比的候选池 ----
|
| 213 |
+
pool_image_flited = []
|
| 214 |
+
pool_reconed_image_color = []
|
| 215 |
|
| 216 |
+
# 这个独立的池用于“哨兵试验”,它需要从“任何”方法中随机抽取一个候选图
|
| 217 |
+
combined_pool_for_sentinel = []
|
| 218 |
+
|
| 219 |
for m_root_path in METHOD_ROOTS:
|
| 220 |
method_name = os.path.basename(m_root_path)
|
| 221 |
|
|
|
|
| 234 |
internal_label = f"{method_name}/{s_id}/{reconstructed_filename}"
|
| 235 |
candidate_tuple = (internal_label, candidate_path)
|
| 236 |
|
| 237 |
+
# 为常规试验,将候选图放入对应的特定池中
|
| 238 |
if method_name == "image_flited":
|
| 239 |
+
pool_image_flited.append(candidate_tuple)
|
| 240 |
+
elif method_name == "reconed_image_color":
|
| 241 |
+
pool_reconed_image_color.append(candidate_tuple)
|
| 242 |
+
|
| 243 |
+
# 将“所有”有效的候选图都添加到哨兵池中
|
| 244 |
+
combined_pool_for_sentinel.append(candidate_tuple)
|
| 245 |
+
# ---- MODIFICATION END: 候选池已填充完毕 ----
|
| 246 |
|
| 247 |
trial_info = {"image_id": img_filename_original, "target_path": target_full_path, "cur_no": trial_number_for_display, "is_sentinel": False,
|
| 248 |
"left_display_label": "N/A", "left_internal_label": "N/A", "left_path": None,
|
|
|
|
| 251 |
is_potential_sentinel_trial = (trial_number_for_display > 0 and trial_number_for_display % SENTINEL_TRIAL_INTERVAL == 0)
|
| 252 |
|
| 253 |
if is_potential_sentinel_trial:
|
| 254 |
+
# 对于哨兵试验,我们从包含所有方法候选图的池中随机选择一个
|
| 255 |
+
if not combined_pool_for_sentinel:
|
|
|
|
| 256 |
print(f"警告:哨兵图 '{img_filename_original}' (trial {trial_number_for_display}) 无任何候选图。")
|
| 257 |
else:
|
| 258 |
print(f"生成哨兵试验 for '{img_filename_original}' (trial {trial_number_for_display})")
|
| 259 |
trial_info["is_sentinel"] = True
|
| 260 |
sentinel_candidate_target_tuple = ("目标图像", target_full_path)
|
| 261 |
+
random_reconstruction_candidate_tuple = random.choice(combined_pool_for_sentinel)
|
| 262 |
candidates_for_sentinel = [
|
| 263 |
(("目标图像", target_full_path), sentinel_candidate_target_tuple[0]),
|
| 264 |
(("重建图", random_reconstruction_candidate_tuple[1]), random_reconstruction_candidate_tuple[0])
|
|
|
|
| 269 |
"right_display_label": candidates_for_sentinel[1][0][0], "right_path": candidates_for_sentinel[1][0][1], "right_internal_label": candidates_for_sentinel[1][1],
|
| 270 |
})
|
| 271 |
else: # 常规试验
|
| 272 |
+
# ---- MODIFICATION START: 新的检查与配对逻辑 ----
|
| 273 |
+
# 检查两个特定的池是否都有候选图
|
| 274 |
+
if not pool_image_flited or not pool_reconed_image_color:
|
| 275 |
+
print(f"警告:常规图 '{img_filename_original}' (trial {trial_number_for_display}) 候选不足以形成 'image_flited' vs 'reconed_image_color' 对。 "
|
| 276 |
+
f"('image_flited' 找到 {len(pool_image_flited)} 个, "
|
| 277 |
+
f"'reconed_image_color' 找到 {len(pool_reconed_image_color)} 个)。此试验无法进行。")
|
| 278 |
return None, current_trial_idx_in_run
|
| 279 |
|
| 280 |
target_global_history_set = global_shown_pairs_cache.setdefault(img_filename_original, set())
|
| 281 |
|
| 282 |
+
# 从两个特定池中各选一个,生成所有可能的配对
|
| 283 |
all_possible_pairs_in_pool = []
|
| 284 |
+
for c_flited, c_reconed in product(pool_image_flited, pool_reconed_image_color):
|
| 285 |
+
pair_labels_fset = frozenset({c_flited[0], c_reconed[0]})
|
| 286 |
+
all_possible_pairs_in_pool.append( ((c_flited, c_reconed), pair_labels_fset) )
|
| 287 |
+
# ---- MODIFICATION END: 新的配对逻辑已完成 ----
|
| 288 |
|
| 289 |
unseen_globally_pairs_with_data = [
|
| 290 |
item for item in all_possible_pairs_in_pool if item[1] not in target_global_history_set
|
|
|
|
| 298 |
target_global_history_set.add(chosen_pair_frozenset)
|
| 299 |
global_history_has_unsaved_changes = True
|
| 300 |
else:
|
| 301 |
+
print(f"警告:目标图 '{img_filename_original}' (trial {trial_number_for_display}): 所有 ({len(all_possible_pairs_in_pool)}) 个 'image_flited' vs 'reconed_image_color' 对均已在全局展示过。")
|
| 302 |
if all_possible_pairs_in_pool:
|
| 303 |
print(f"目标图 '{img_filename_original}' 将被标记为已耗尽,未来轮次中将被跳过。")
|
| 304 |
exhausted_target_images.add(img_filename_original)
|
|
|
|
| 313 |
})
|
| 314 |
return trial_info, current_trial_idx_in_run + 1
|
| 315 |
|
| 316 |
+
|
| 317 |
# ==== 批量保存用户选择日志函数 (保持不变) ====
|
| 318 |
def save_single_log_to_hf_dataset(log_entry, user_identifier_str):
|
| 319 |
global DATASET_REPO_ID, INDIVIDUAL_LOGS_FOLDER
|