Skip OP/ED files by default (--all-files to include)

Real-run evidence: the transformation-emblem false positive (frame 1583
of the OP, 717x857, aspect 0.84) is geometrically face-shaped and
passes every box gate; OP/ED music videos are dominated by exactly that
kind of stylized graphics. Episodes carry the character close-ups a
grounding dataset needs. Verified on the second run: feather storm
(frame 29, area .64) now correctly rejected by the area cap.
This commit is contained in:
2026-10-18 11:07:53 -04:00
parent 89b0f708d7
commit 16ef032611
2 changed files with 22 additions and 5 deletions
+1
View File
@@ -64,6 +64,7 @@ context leaks onto the wrong card:
| `--edge-margin` | 0 | require faces this far inside frame edges; `0` accepts edge-touching faces (original hard-rejected them) | | `--edge-margin` | 0 | require faces this far inside frame edges; `0` accepts edge-touching faces (original hard-rejected them) |
| `--scene-threshold` | 30.0 | PySceneDetect ContentDetector threshold (same as original) | | `--scene-threshold` | 30.0 | PySceneDetect ContentDetector threshold (same as original) |
| `--imgsz` | 1280 | inference size; model was trained at 1280, `640` is faster at some recall cost | | `--imgsz` | 1280 | inference size; model was trained at 1280, `640` is faster at some recall cost |
| `--all-files` | off | also scan OP/ED files. Off by default: music videos are full of stylized graphics (feather storms, transformation emblems) that false-positive as face-shaped; episodes carry the real character close-ups |
| `--preview-dir` | off | also write annotated copies (green boxes) of every saved frame for eyeball QC | | `--preview-dir` | off | also write annotated copies (green boxes) of every saved frame for eyeball QC |
## Notes ## Notes
+21 -5
View File
@@ -132,6 +132,15 @@ def parse_arguments():
help="Inference image size. The model was trained at 1280; lower " help="Inference image size. The model was trained at 1280; lower "
"it (640) for speed at some recall cost.", "it (640) for speed at some recall cost.",
) )
parser.add_argument(
"--all-files",
action="store_true",
help="Also scan OP/ED files (name matches 'opening'/'ending'). "
"Skipped by default: music-video files are dominated by "
"stylized graphics (feather storms, transformation "
"emblems) that false-positive face detectors; character "
"close-ups for training datasets come from episodes.",
)
parser.add_argument( parser.add_argument(
"--preview-dir", "--preview-dir",
default=None, default=None,
@@ -367,11 +376,18 @@ def main():
video_extensions = ('.mp4', '.avi', '.mov', '.mkv') video_extensions = ('.mp4', '.avi', '.mov', '.mkv')
grand_total = 0 grand_total = 0
for filename in sorted(os.listdir(args.input_dir)): for filename in sorted(os.listdir(args.input_dir)):
if filename.lower().endswith(video_extensions): if not filename.lower().endswith(video_extensions):
video_path = os.path.join(args.input_dir, filename) continue
print(f"Processing video: {video_path}") if (not args.all_files
grand_total += process_video( and any(k in filename.lower()
video_path, args.output_dir, args, model, device, draw) for k in ("opening", "ending", " op", " ed"))):
print(f"Skipping OP/ED file (use --all-files to include): "
f"{filename}")
continue
video_path = os.path.join(args.input_dir, filename)
print(f"Processing video: {video_path}")
grand_total += process_video(
video_path, args.output_dir, args, model, device, draw)
print(f"Done. {grand_total} stills saved to {args.output_dir}") print(f"Done. {grand_total} stills saved to {args.output_dir}")