MuseTalk Single-Photo Tutorial: Tested Workflow and Quality Controls

Original fictional portrait beside the actual MuseTalk 1.5 output at 1.6 seconds
Actual input photo and MuseTalk 1.5 output at 1.6 seconds.

Tested 12 October 2026: one permitted fictional portrait and a 3.632-second synthetic speech clip. MuseTalk 1.0 and 1.5 both accepted the PNG directly. All 15 saved MP4s passed full decoding: 1254 × 1254, 25 fps, 90 frames, H.264 video and AAC audio.

Browse the MuseTalk examples gallery for five retained outputs, playable clips, permitted inputs, exact settings and honest limitations.

Get the photo workflow kit · Explore the quality-test evidence · View measured results (CSV)

1. Prepare the photo and audio

Use a sharp, front-facing image with an unobstructed mouth and even lighting. Our original 1254 × 1254 PNG was retained without resizing. Audio was mono WAV at 16 kHz: “Please bring me a blue mug. We can meet on Friday.” Use assets you have permission to process.

Actual original input photo; arrow identifies the mouth
Actual original input photo; arrow identifies the mouth. Raw screenshot

2. Point the configuration at the PNG

Install the official MuseTalk repository and required model weights. These files contain inputs and evidence, not model weights. Replace the absolute paths below with your own paths.

photo_test:
  video_path: /workspace/d19-kit/sample-kit/portrait.png
  audio_path: /workspace/d19-kit/sample-kit/speech.wav
  result_name: result.mp4

The input key is named video_path, but the pinned inference script accepts an image file. No preliminary photo-to-video conversion was used.

Actual saved YAML; arrow identifies the direct PNG input
Actual saved YAML; arrow identifies the direct PNG input. Raw screenshot

3. Run the selected version

From the installed MuseTalk repository, run the command below using its configured Python environment. It reproduces the 1.5 settings; the included wrapper and recorded commands preserve the test seed and numerical controls.

python -m scripts.inference --inference_config photo.yaml   --result_dir results/photo --version v15   --unet_model_path models/musetalkV15/unet.pth   --unet_config models/musetalkV15/musetalk.json   --use_float16 --batch_size 2 --fps 25   --bbox_shift 0 --extra_margin 10 --parsing_mode jaw   --left_cheek_width 90 --right_cheek_width 90

For 1.0, use --version v1, models/musetalk/pytorch_model.bin and models/musetalk/musetalk.json. Its effective blending mode is raw; its crop control is bbox_shift. Set --ffmpeg_path when FFmpeg is outside PATH.

Observed warning: every direct-photo run logged local variable 'save_dir_full' referenced before assignment after writing the final MP4. The stock script refers to a cleanup variable initialized only in its video branch. These outputs existed and decoded completely; do not treat the process exit code alone as proof of success. Upstream source was retained unchanged.

Actual saved inference log; arrow identifies the post-write cleanup warning
Actual saved inference log; arrow identifies the post-write cleanup warning. Raw screenshot

4. Check the native output

Watch the baseline video (MP4) · View native frame 40 (PNG)

Actual output at 1.6 seconds; arrow identifies the synthesized lower face
Actual output at 1.6 seconds; arrow identifies the synthesized lower face. Raw screenshot

Static-head limitation: the input photo is reused as the base frame. This workflow does not generate natural head turns or blinks. Mouth, lower-face and cheek pixels can change through synthesis and blending. Face synthesis uses a 256 × 256 crop; a 1254 × 1254 output canvas does not restore original facial detail.

5. Compare supported quality controls

Each variant changed one command-line setting from its version baseline. Constants: same original PNG/WAV, seed 20261012, batch size 2, 25 fps and FP16 unless the FP32 row says otherwise.

ControlMuseTalk 1.0MuseTalk 1.5Tested values / implication
bbox_shiftSupported crop adjustmentForced to 0 by source1.0: −10 / 0 / +10; 1.5: requested +20 as ignored-control check
extra_marginIgnoredSupported lower-crop extension1.5: 0 / 10 / 20 source-image pixels; 1.0: requested 20 as ignored-control check
parsing_modeEffective raw; CLI mode ignoredjaw / raw / neckAll three modes tested on 1.5; changes blending coverage
Cheek widthsCLI values ignoredUsed by jaw blending mask1.5: 90/90 baseline, 60/90, 90/60; mask uses 512-pixel parser space
PrecisionFP16 testedFP16 and FP32 testedFP32 removes –use_float16. Pixel differences do not establish better quality

Support is verified against the pinned inference source and face parser. These are tested values, not recommended ranges for every portrait.

Actual frame-40 comparison; arrow identifies the changed margin value
Actual frame-40 comparison; arrow identifies the changed margin value. Raw screenshot

Numerical limits: the 1.5 baseline/repeat pair matched all 90 pre-encoding frame hashes. The 1.0 repeat differed, and the 1.5 ignored-bbox check also differed despite the source ignoring that parameter. Consequently, small pixel differences cannot all be attributed to the requested setting. The 1.0 matrix stopped at its repeatability gate; its remaining three controls were run separately under the same conditions and are included. No quality winner is inferred.

The table below measures mean absolute RGB difference at frame 40 on a 0–255 scale, averaged across the full canvas against the same-version baseline. It measures pixel change, not lip-sync accuracy, visual quality or perceived realism. A large unchanged background dilutes this measure.

RunChanged settingProcess secondsFrame-40 RGB difference
v15-baseline{}63.960.0000
v15-repeat{}66.130.0000
v15-margin-0{“extra_margin”: 0}51.900.7090
v15-margin-20{“extra_margin”: 20}67.760.6715
v15-raw{“parsing_mode”: “raw”}60.200.6428
v15-neck{“parsing_mode”: “neck”}67.940.7062
v15-left-60{“left_cheek_width”: 60}51.850.5727
v15-right-60{“right_cheek_width”: 60}68.060.5696
v15-bbox-ignored{“bbox_shift”: 20}52.080.5576
v15-fp32{“precision”: “fp32”}55.180.5593
v1-baseline{}50.900.0000
v1-repeat{}51.860.5648
v1-bbox-minus-10{“bbox_shift”: -10}58.510.6643
v1-bbox-plus-10{“bbox_shift”: 10}55.660.6707
v1-margin-ignored{“extra_margin”: 20}51.620.5636

Each timing is a fresh-process wall time including model loading, preprocessing, inference and encoding. Runs share an RTX 4090 host with the template service; these are diagnostic timings, not a throughput benchmark. One portrait and one short sentence cannot establish general quality.

Optional motion pipeline

If head motion or blinks are required, create a driving video with a separate portrait-animation pipeline, then use that video as MuseTalk input. That adds motion-model setup, dependencies and a second generation stage. It was not tested here and is not required for the direct PNG workflow.

Reproduction record

Official commit: 0a89dec45a0192b824e3cf4daf96c239440c5ed8. MuseTalk model repository revision: 2bcb936e2fddb4d86db4c62fd45b387d0c061571. RTX 4090, Python 3.10.18, Torch 2.0.1+cu118, CUDA 11.8. The evidence archive includes environment/package records, model hashes, per-run commands and warnings. Native inputs, clips and output frames are preserved. Screenshots are real browser captures of saved files and output viewers; separate arrow copies retain the raw originals.

4 thoughts on “MuseTalk Single-Photo Tutorial: Tested Workflow and Quality Controls”

Leave a Comment