Synthetic source portraits for argus-mask
argus-curator 0.15.2.dev2+g97021d6 @ 97021d6PyPI (opens in new tab)Source (opens in new tab)Changelog (opens in new tab)
Imported from docs/synthetic-face-sets.md on argus-curator's dev branch at that commit. Fixes go upstream, not here.
This guide covers the suite's tools for making a synthetic source portrait for argus-mask: an image of a person who does not exist, made with an image model, that a photoreal face route builds a talking head from.
It follows argus-mask's Making a synthetic face for input (opens in new tab), which stays the authority on two things: the rule, and what a good portrait looks like. Read that first. This guide says which suite tool handles each step, and what each tool doesn't check.
argus-darkroom ──▶ argus-curator ──▶ (argus-lens) ──▶ you ──▶ argus-mask
generate, guarded shortlist reading aid pick inspect, serve
records every run age, pose, faces captions look-alike check
Real people: a real person's face needs their documented consent (argus-mask#19 (opens in new tab)). Curator support for consented real-person sets is tracked in argus-curator#133 (opens in new tab). This guide covers synthetic faces only.
Not used:
- argus-quarry collects public-domain and CC0 portraits of real people. A licence to use a photo isn't the person's consent to be made into a talking face, so quarry images must never be a mask source, even as a reference for an identity adapter.
- argus-forge and argus-proof are for LoRA training, which this workflow doesn't need.
What the tools check, and what they don't
1. Generate with argus-darkroom
argus-darkroom (opens in new tab) checks the prompt before rendering, renders through ComfyUI, scans each output, and keeps a record of every attempt. Use an SFW policy, either default or one of the sfw-* policies. Under these, darkroom refuses a prompt that any pre-flight check flags, and omits any exposed output.
These are the mask guide's SDXL settings, written as darkroom flags:
for seed in $(seq 1001 1024); do
argus-darkroom generate "$(cat prompt.txt)" -n "$(cat negative.txt)" \
--checkpoint sdxl/sd_xl_base_1.0.safetensors --policy default \
--sampler dpmpp_2m --scheduler karras --steps 35 --cfg 6 \
--width 896 --height 1152 --seed "$seed"
done
- Prompt and negative prompt: use the mask guide's templates. Keep the adult age in the prompt, and
child, minorin the negative. - One at a time: darkroom runs one generation at a time and answers 409 to a second, which is why the loop runs sequentially.
- Checkpoint path: the checkpoint goes under ComfyUI's
checkpoints/sdxl/so darkroom picks thesdxlworkflow template.
Each attempt leaves <id>.json in darkroom's OUTPUT_ROOT, and released images also leave <id>.png. Shortlist only passed records:
mkdir -p candidates
for rec in darkroom-output/*.json; do
[ "$(jq -r .outcome "$rec")" = passed ] || continue
id=$(jq -r .id "$rec")
cp "darkroom-output/$id.png" "darkroom-output/$id.json" candidates/
done
review images had a SingGuard rule fire. Leave them out, even if they look fine.
What the darkroom record covers
The mask guide asks for a generation.json beside the portrait. Most of it is already in the darkroom record:
2. Shortlist with argus-curator
Curator doesn't decide what's a good portrait, but it narrows a batch of 16 to 32 down to the ones worth looking at:
argus-curator scan candidates/ \
--mivolo --face-source --blur-threshold 0 \
--garments --exclude-garment glasses,hat,headband_hair_accessory \
--keep-similar --carry-sidecars \
--csv shortlist.csv --copy-to shortlist/
--mivolo and --garments need their converted models: run argus-curator mivolo-convert and argus-curator garments-convert once (see Face attributes and Garments). Without them the scan refuses up front and names the missing model.
With NudeNet configured (ARGUS_CURATOR_NUDENET_URL), the scan also scores exposure. A head-and-shoulders portrait should score near zero, so add --drop-nsfw to reject anything that doesn't.
Use the face's sharpness, not the image's. The scan's blur filter measures the whole image. The guide's plain mid-grey background has little texture, so a portrait with a sharp face can score under the default --blur-threshold 100 and be rejected as blurry before its face is read. --blur-threshold 0 turns that filter off, and --face-source checks the face box's own sharpness instead.
The eye and mouth checks are measurements from InsightFace's 68 landmarks, not an expression classifier. A smile with closed lips still passes, so judge the expression yourself.
Don't use --detect-watermarks here. It crops a watermark away, and the guide wants the chosen image unedited. Discard a portrait with a watermark or text instead, and regenerate.
3. Read the captions (optional): argus-lens
Several rows of the guide's table have no detector:
- neutral expression with lips closed;
- eyes open and looking into the lens;
- even light;
- a plain background;
- no hands over the face.
argus-lens (opens in new tab) captions can point you at problems, though they don't settle them:
argus-lens caption shortlist/ --format txt --backend hybrid
Lens files caption words under categories: smile, expression, glasses and makeup under identity, and rim light, harsh light, shadows, dramatic lighting and backlighting under lighting. A caption with one of these words is a portrait to look at again. A caption without them is no guarantee the portrait is clean.
4. Pick, and check for look-alikes
Choose against the mask guide's table and checklist by eye. Then run the look-alike check on the one you keep, and record what you searched and when. If the face looks like someone you could name, discard it and change the seed.
5. More than one view
Some splat routes train on several views. The mask guide gives two synthetic-only ways to make them. Either way, every view has to stay the same person.
Curator measures how far each view is from the frontal portrait. Put the portrait in the folder with the views, and name it as the reference:
argus-curator scan views/ --faces --face-reference portrait.png --blur-threshold 0 --csv views.csv
Each face gets a reference_distance: the cosine distance between its InsightFace embedding and the portrait's. The CSV has it as primary_face_reference_distance, and so does each manifest row's primary_face. Sort the views by it: the portrait reads 0, and a view that has drifted reads higher than the rest. --face-source keeps only views within 0.4 of the reference. That's a starting point, not a calibrated value, so compare the views with each other rather than trusting it alone. The reference has to pass the scan's own filters, because a rejected image is never face-checked. A portrait on a plain mid-grey background can score under the default --blur-threshold 100 (see section 2), hence --blur-threshold 0 above. If the reference is rejected, the summary's reference_skipped says so and every reference_distance stays empty.
Keep lighting and background identical across views. No tool here compares them.
6. Hand off to argus-mask
Lay out the source as the mask guide says:
assets/<face-id>/source/
portrait.png # the chosen image, unedited (darkroom's <id>.png)
portrait.final.png # after any inpaint and upscale
generation.json # the darkroom record, plus licences, edits and the look-alike check
workflow.json # the darkroom workflow template the record names
Start generation.json from the darkroom <id>.json that came with the image, and add what it lacks: licences, edits and the look-alike check. Then build and inspect the face with argus-mask's inspect --kind synthetic, as its guide shows.
Gaps
These parts of the guide have no tool support yet:
Head level, face size, face sharpness, eyes and mouth, and identity distance per view are measured since argus-curator#130 (opens in new tab). This issue tracks the rest:
- argus-darkroom#33 (opens in new tab): licences in the record, a check for named real people in the prompt, and adding the look-alike check to a record afterwards.
Lighting and background stay checks by eye.