Reject portrait photos with a tiny YuNet face detector
I run Aotearoa, Again, which picks up old archival photos, colourises one a day, and publishes to YouTube, email, Bluesky, and Instagram. Before anything hits human review, the harvester already throws out a lot of stuff I don’t want: colour originals, book covers, newspaper spreads, and so on.
Portraits were the awkward gap for me: a studio shot of one or two people is usually a bad fit, because I don’t know who they are and colourising their face for a daily post feels wrong. I still want crowd scenes and tiny background faces in the frame.
I’d been manually discarding studio shots for a while, and what I wanted was a rough “probably a portrait” signal so I’m not clicking discard on quite so many candidates myself.
YuNet
I’ve vendored OpenCV Zoo
YuNet
(face_detection_yunet_2023mar.onnx, MIT). The ONNX file in the repo is 227 KB,
and it runs through the onnxruntime gem with resize and prep using libvips
like everything else in the app.
I have a thin wrapper over the model, which pads the photo to 640×640, runs
inference, decodes boxes the same way OpenCV’s FaceDetectorYN does, runs NMS,
and returns each face as a fraction of the image area (bounding box area over
the photo area).
When to discard
For my specific use case, I found that discarding when there’s one or two faces and the largest covers at least 1% of the frame was a good compromise between false positives and false negatives. Three or more faces stay even if they take up a decent proportion of the frame, and a single tiny face stays too. In tests, a seated studio portrait landed around 0.013; a rider in a wider scene around 0.003.