feat: RGBA fix, per-person tracking, dry-run, retry-rejected, reset-person
- Fix RGBA→JPEG error: convert all images to RGB before saving - Upload tracker: per-person breakdown in JSON, reset_person(), get_person_summary() - mark_rejected() only fires on face-detection failures (not all HTTP 400s) - New env vars: DRY_RUN, RETRY_REJECTED, RESET_PERSON - Tracker summary printed at startup showing uploaded/rejected counts per person - Document new env vars in compose.yml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,12 @@ logger = logging.getLogger(__name__)
|
||||
_yolo_model = None
|
||||
|
||||
|
||||
def _save_jpeg(img: Image.Image, path: str) -> None:
|
||||
if img.mode != "RGB":
|
||||
img = img.convert("RGB")
|
||||
img.save(path, format="JPEG")
|
||||
|
||||
|
||||
def get_yolo_model():
|
||||
"""Singleton for YOLO model."""
|
||||
global _yolo_model
|
||||
@@ -110,7 +116,7 @@ def process_face_mode(
|
||||
scaled_landmarks = [[lm[0] * scale_x, lm[1] * scale_y] for lm in landmarks]
|
||||
aligned = align_face(img, scaled_landmarks)
|
||||
if aligned is not None:
|
||||
aligned.save(os.path.join(output_dir, f"{count}.jpg"), format="JPEG")
|
||||
_save_jpeg(aligned, os.path.join(output_dir, f"{count}.jpg"))
|
||||
return True
|
||||
|
||||
# Fall back to bounding box crop with configurable margin
|
||||
@@ -124,7 +130,7 @@ def process_face_mode(
|
||||
)
|
||||
|
||||
face_crop = img.crop(crop_box)
|
||||
face_crop.save(os.path.join(output_dir, f"{count}.jpg"), format="JPEG")
|
||||
_save_jpeg(face_crop, os.path.join(output_dir, f"{count}.jpg"))
|
||||
return True
|
||||
|
||||
|
||||
@@ -149,9 +155,9 @@ def process_object_mode(
|
||||
conf = float(box.conf[0])
|
||||
if 0 <= cls_id < len(model.names) and model.names[cls_id] == target_class and conf > 0.5:
|
||||
x1, y1, x2, y2 = box.xyxy[0].tolist()
|
||||
img.crop((x1, y1, x2, y2)).save(
|
||||
_save_jpeg(
|
||||
img.crop((x1, y1, x2, y2)),
|
||||
os.path.join(output_dir, f"{count}_{class_idx}.jpg"),
|
||||
format="JPEG",
|
||||
)
|
||||
class_idx += 1
|
||||
found = True
|
||||
@@ -164,6 +170,6 @@ def process_object_mode(
|
||||
|
||||
def process_full_mode(img: Image.Image, output_dir: str, count: int) -> bool:
|
||||
"""Save full image."""
|
||||
img.save(os.path.join(output_dir, f"{count}.jpg"), format="JPEG")
|
||||
_save_jpeg(img, os.path.join(output_dir, f"{count}.jpg"))
|
||||
return True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user