# Batch face detection on a folder of images # Usage: python batch_process.py --input images/ --output results/ import argparse from pathlib import Path import cv2 from tqdm import tqdm from uniface import SCRFD, RetinaFace from uniface.visualization import draw_detections def get_image_files(input_dir: Path, extensions: tuple) -> list: files = [] for ext in extensions: files.extend(input_dir.glob(f'*.{ext}')) files.extend(input_dir.glob(f'*.{ext.upper()}')) return sorted(files) def process_image(detector, image_path: Path, output_path: Path, threshold: float) -> int: """Process single image. Returns face count or -1 on error.""" image = cv2.imread(str(image_path)) if image is None: return -1 faces = detector.detect(image) # unpack face data for visualization bboxes = [f.bbox for f in faces] scores = [f.confidence for f in faces] landmarks = [f.landmarks for f in faces] draw_detections( image=image, bboxes=bboxes, scores=scores, landmarks=landmarks, vis_threshold=threshold, fancy_bbox=True ) cv2.putText( image, f'Faces: {len(faces)}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, ) cv2.imwrite(str(output_path), image) return len(faces) def main(): parser = argparse.ArgumentParser(description='Batch process images with face detection') parser.add_argument('--input', type=str, required=True, help='Input directory') parser.add_argument('--output', type=str, required=True, help='Output directory') parser.add_argument('--detector', type=str, default='retinaface', choices=['retinaface', 'scrfd']) parser.add_argument('--threshold', type=float, default=0.6, help='Visualization threshold') parser.add_argument('--extensions', type=str, default='jpg,jpeg,png,bmp', help='Image extensions') args = parser.parse_args() input_path = Path(args.input) output_path = Path(args.output) if not input_path.exists(): print(f"Error: Input directory '{args.input}' does not exist") return output_path.mkdir(parents=True, exist_ok=True) extensions = tuple(ext.strip() for ext in args.extensions.split(',')) image_files = get_image_files(input_path, extensions) if not image_files: print(f'No images found with extensions {extensions}') return print(f'Found {len(image_files)} images') detector = RetinaFace() if args.detector == 'retinaface' else SCRFD() success, errors, total_faces = 0, 0, 0 for img_path in tqdm(image_files, desc='Processing', unit='img'): out_path = output_path / f'{img_path.stem}_detected{img_path.suffix}' result = process_image(detector, img_path, out_path, args.threshold) if result >= 0: success += 1 total_faces += result else: errors += 1 print(f'\nFailed: {img_path.name}') print(f'\nDone! {success} processed, {errors} errors, {total_faces} faces total') if __name__ == '__main__': main()