Make reading grouped annotations faster.
parent
a658cb72e0
commit
d288daecd1
|
|
@ -42,7 +42,7 @@ def process_images(base_dir):
|
||||||
print(f"Error: Directory '{search_path}' not found.")
|
print(f"Error: Directory '{search_path}' not found.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
for img_path in search_path.glob("*/*.jpg"):
|
for img_path in sorted(search_path.glob("*/*.jpg")):
|
||||||
student_name = img_path.stem # Filename without extension
|
student_name = img_path.stem # Filename without extension
|
||||||
|
|
||||||
# 4. Find Score
|
# 4. Find Score
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import sys
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import collections
|
import collections
|
||||||
|
import concurrent.futures
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
@ -14,7 +15,9 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la
|
||||||
Modifies data based on actions, pastes label-specific note crops,
|
Modifies data based on actions, pastes label-specific note crops,
|
||||||
regenerates label images for consistency, saves dirty ones,
|
regenerates label images for consistency, saves dirty ones,
|
||||||
and generates Concat.jpg in the BGnot/Copie{id} directory.
|
and generates Concat.jpg in the BGnot/Copie{id} directory.
|
||||||
|
Returns a string of accumulated log messages.
|
||||||
"""
|
"""
|
||||||
|
logs = [f"\nProcessing compilation for: Copie{student_id}"]
|
||||||
output_dir = os.path.join(root_dir, "BGnot", f"Copie{student_id}")
|
output_dir = os.path.join(root_dir, "BGnot", f"Copie{student_id}")
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
|
|
@ -44,23 +47,23 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la
|
||||||
if act['type'] == 'score':
|
if act['type'] == 'score':
|
||||||
result['score'] = act['value']
|
result['score'] = act['value']
|
||||||
dirty_labels.add(label)
|
dirty_labels.add(label)
|
||||||
print(f" > Updated score for {label} to {act['value']}")
|
logs.append(f" > Updated score for {label} to {act['value']}")
|
||||||
|
|
||||||
elif act['type'] == 'del_global':
|
elif act['type'] == 'del_global':
|
||||||
if act['index'] < len(global_fb):
|
if act['index'] < len(global_fb):
|
||||||
global_fb[act['index']]["to_delete"] = True
|
global_fb[act['index']]["to_delete"] = True
|
||||||
dirty_labels.add(label)
|
dirty_labels.add(label)
|
||||||
print(f" > Deleted global feedback in {label}")
|
logs.append(f" > Deleted global feedback in {label}")
|
||||||
|
|
||||||
elif act['type'] in ('del_local', 'del_local_rect'):
|
elif act['type'] in ('del_local', 'del_local_rect'):
|
||||||
if act['index'] < len(local_fb):
|
if act['index'] < len(local_fb):
|
||||||
target = local_fb[act['index']]
|
target = local_fb[act['index']]
|
||||||
if act['type'] == 'del_local':
|
if act['type'] == 'del_local':
|
||||||
target["to_delete"] = True
|
target["to_delete"] = True
|
||||||
print(f" > Deleted local feedback in {label}")
|
logs.append(f" > Deleted local feedback in {label}")
|
||||||
else:
|
else:
|
||||||
target["norectangle"] = True
|
target["norectangle"] = True
|
||||||
print(f" > Deleted rect in {label}")
|
logs.append(f" > Deleted rect in {label}")
|
||||||
dirty_labels.add(label)
|
dirty_labels.add(label)
|
||||||
|
|
||||||
# --- 2. Process Images (Regenerate & Concatenate) ---
|
# --- 2. Process Images (Regenerate & Concatenate) ---
|
||||||
|
|
@ -113,7 +116,7 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la
|
||||||
if (label in dirty_labels) or has_notes:
|
if (label in dirty_labels) or has_notes:
|
||||||
save_path = os.path.join(output_dir, f"{label}.jpg")
|
save_path = os.path.join(output_dir, f"{label}.jpg")
|
||||||
final_img.save(save_path)
|
final_img.save(save_path)
|
||||||
print(f" Saved dirty image: {label}.jpg")
|
logs.append(f" Saved dirty image: {label}.jpg")
|
||||||
|
|
||||||
concat_list.append(final_img)
|
concat_list.append(final_img)
|
||||||
|
|
||||||
|
|
@ -126,11 +129,10 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la
|
||||||
if not perfect_no_comment:
|
if not perfect_no_comment:
|
||||||
concat_list_F.append(final_img)
|
concat_list_F.append(final_img)
|
||||||
|
|
||||||
|
|
||||||
# --- 3. Save Final Outputs ---
|
# --- 3. Save Final Outputs ---
|
||||||
with open(score_path, "w") as f:
|
with open(score_path, "w") as f:
|
||||||
json.dump(d_notes, f, indent=4)
|
json.dump(d_notes, f, indent=4)
|
||||||
print(f" Saved {score_path}")
|
logs.append(f" Saved {score_path}")
|
||||||
|
|
||||||
if concat_list:
|
if concat_list:
|
||||||
max_w = max(i.width for i in concat_list)
|
max_w = max(i.width for i in concat_list)
|
||||||
|
|
@ -143,7 +145,8 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la
|
||||||
y += img.height
|
y += img.height
|
||||||
|
|
||||||
full_img.save(os.path.join(output_dir, "Concat.jpg"))
|
full_img.save(os.path.join(output_dir, "Concat.jpg"))
|
||||||
print(f" Saved regenerated Concat.jpg")
|
logs.append(f" Saved regenerated Concat.jpg")
|
||||||
|
|
||||||
if concat_list_F:
|
if concat_list_F:
|
||||||
max_w = max(i.width for i in concat_list_F)
|
max_w = max(i.width for i in concat_list_F)
|
||||||
total_h = sum(i.height for i in concat_list_F)
|
total_h = sum(i.height for i in concat_list_F)
|
||||||
|
|
@ -155,7 +158,9 @@ def apply_actions_and_regenerate_grouped(root_dir, data, student_id, actions, la
|
||||||
y += img.height
|
y += img.height
|
||||||
|
|
||||||
full_img.save(os.path.join(output_dir, "Concat_F.jpg"))
|
full_img.save(os.path.join(output_dir, "Concat_F.jpg"))
|
||||||
print(f" Saved regenerated Concat_F.jpg")
|
logs.append(f" Saved regenerated Concat_F.jpg")
|
||||||
|
|
||||||
|
return "\n".join(logs)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
@ -223,20 +228,10 @@ if __name__ == "__main__":
|
||||||
'old_header_h': img_info.get("header_height", 0)
|
'old_header_h': img_info.get("header_height", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- 2. Dispatch data back to students and regenerate ---
|
def process_student(sid):
|
||||||
# affected_students = set(actions_by_student.keys()).union(set(notes_by_student.keys()))
|
|
||||||
|
|
||||||
# if not affected_students:
|
|
||||||
# print("\nNo changes detected in any grouped annotations.")
|
|
||||||
# sys.exit(0)
|
|
||||||
|
|
||||||
# for sid in sorted(affected_students, key=natural_key):
|
|
||||||
for sid in sorted(original_data.keys(), key=natural_key):
|
|
||||||
if sid not in original_data:
|
if sid not in original_data:
|
||||||
continue
|
return ""
|
||||||
|
return apply_actions_and_regenerate_grouped(
|
||||||
print(f"\nProcessing compilation for: Copie{sid}")
|
|
||||||
apply_actions_and_regenerate_grouped(
|
|
||||||
root_dir,
|
root_dir,
|
||||||
original_data,
|
original_data,
|
||||||
sid,
|
sid,
|
||||||
|
|
@ -244,3 +239,12 @@ if __name__ == "__main__":
|
||||||
notes_by_student[sid],
|
notes_by_student[sid],
|
||||||
all_labels
|
all_labels
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- 2. Process each student concurrently using 4 threads ---
|
||||||
|
sids = sorted(original_data.keys(), key=natural_key)
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
|
||||||
|
futures = {executor.submit(process_student, sid): sid for sid in sids}
|
||||||
|
for future in concurrent.futures.as_completed(futures):
|
||||||
|
output = future.result()
|
||||||
|
if output:
|
||||||
|
print(output)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue