Skip to content

muscle_to_landmark

feat.utils.muscle_to_landmark

Facial muscle -> MediaPipe-478 mesh / FACS Action Unit map.

py-feat ships a map from each mimetic facial muscle to (a) the set of MediaPipe-478 mesh vertices its skin insertion deforms and (b) the FACS Action Unit it drives. It is the dense-mesh successor to the sparse dlib-68 muscle polygons in feat.plotting (draw_muscles): instead of a handful of landmark corners per muscle, each muscle is a region of mesh vertices grown geodesically over the canonical mesh surface and walled off by the eye/mouth aperture rings (so a region never covers an eye or the mouth opening).

The map is generated by scripts/map_muscles_canonical_geodesic.py from py-feat's bundled canonical mesh + topology and stored at feat/resources/muscle_to_mesh_map.json. Muscle -> AU follows the Ozel FACS cheat sheet + the pooyadeperson ARKit-blendshape guide.

au_to_muscle_vertices()

Inverse view: {AU: sorted unique MP-478 vertices} (L+R muscles and any sub-regions sharing an AU are merged).

Source code in feat/utils/muscle_to_landmark.py
def au_to_muscle_vertices() -> dict:
    """Inverse view: ``{AU: sorted unique MP-478 vertices}`` (L+R muscles and
    any sub-regions sharing an AU are merged)."""
    by_au: dict = {}
    for spec in load_muscle_to_landmark_map().values():
        by_au.setdefault(spec["au"], set()).update(spec["mp478_vertices"])
    return {au: sorted(v) for au, v in by_au.items()}

load_muscle_to_landmark_map()

Load the muscle -> MP-478 vertex / AU map. Parsed once, then a fresh copy is returned each call so callers can't mutate the shared cache.

Returns a dict keyed by muscle name (e.g. "zygomaticus_major_L"); each value is {"au": "AU12", "mp478_seed": [...], "mp478_vertices": [...], "n_vertices": int, "hops": int} where mp478_vertices indexes the MediaPipe-478 / canonical-mesh vertices the muscle deforms.

Source code in feat/utils/muscle_to_landmark.py
def load_muscle_to_landmark_map() -> dict:
    """Load the muscle -> MP-478 vertex / AU map. Parsed once, then a fresh
    copy is returned each call so callers can't mutate the shared cache.

    Returns a dict keyed by muscle name (e.g. ``"zygomaticus_major_L"``); each
    value is ``{"au": "AU12", "mp478_seed": [...], "mp478_vertices": [...],
    "n_vertices": int, "hops": int}`` where ``mp478_vertices`` indexes the
    MediaPipe-478 / canonical-mesh vertices the muscle deforms.
    """
    global _MUSCLE_MAP
    if _MUSCLE_MAP is None:
        path = os.path.join(get_resource_path(), _MAP_FILENAME)
        with open(path) as f:
            _MUSCLE_MAP = json.load(f)["muscles"]
    return copy.deepcopy(_MUSCLE_MAP)

muscle_vertices(muscle)

MP-478 vertex indices a single muscle deforms.

Source code in feat/utils/muscle_to_landmark.py
def muscle_vertices(muscle: str) -> list[int]:
    """MP-478 vertex indices a single muscle deforms."""
    return load_muscle_to_landmark_map()[muscle]["mp478_vertices"]