Intro
face mesh 기능을 제공하는 대표적인 Flutter 패키지로는 `google_mlkit_face_mesh_detection` 이 있다.
ML Kit 기반으로 구현되어 있는데, ML Kit face mesh가 iOS를 지원하지 않아 해당 패키지도 iOS를 지원하지 않는다.
그래서 iOS/Android 둘 다 지원하는 face mesh Flutter 패키지를 직접 만들었다.
https://pub.dev/packages/mediapipe_face_mesh
mediapipe_face_mesh | Flutter package
Flutter plugin for MediaPipe Face Mesh inference on Android/iOS, supporting RGBA and NV21 inputs via an FFI-powered TFLite core.
pub.dev

`mediapipe_face_mesh` 는 FFI Plugin 패키지로 주요 로직을 C++로 구현하고 Dart FFI로 호출한다.
FFI는 iOS/Android 동일하게 사용할 수 있어 별도 네이티브 코드를 작성할 필요가 없다. 의존성도 깔끔하다.
dependencies:
flutter:
sdk: flutter
ffi: ^2.1.3
plugin_platform_interface: ^2.0.2
Google MediaPipe의 Face Mesh 모델(468 landmarks)을 사용한다.
현재(발행일 기준) Face Mesh 기능을 제공하며, Face Detection 기능을 제공하진 않는다.
카메라 스트림에서 Face Mesh를 사용하려는 경우 `google_mlkit_face_detection` 패키지를 같이 사용해
CameraImage → Face bounding box → Face Mesh 순으로 처리하는 걸 권장한다. (예제는 맨 아래에 링크)
참고로 `google_mlkit_face_mesh_detection` 은 iOS를 지원하지 않지만
`google_mlkit_face_detection` 은 iOS/Android를 지원한다.
몇 가지 개발 포인트를 정리해본다.
TFLite Model
https://github.com/google-ai-edge/mediapipe/blob/master/docs/solutions/models.md
mediapipe repo에서 제공하는 tflite 모델을 사용한다. (기본 face landmark model 사용)
Build TFLite C API
LiteRT = TFLite 새 이름이다.
TFLite를 C 환경에서 사용하기 위해서 플랫폼에 맞는 TFLite C API 바이너리를 빌드한다.
(iOS와 Android는 운영체제, 런타임 로더, CPU 아키텍처/ABI, 기본 C/C++ 표준 라이브러리까지 서로 다르기 때문에 별도의 빌드 산출물이 필요하다.)
TFLite C API Interface
TFLite 구현 소스는 빌드한 바이너리 안에 있고 동적 로딩해서 사용한다. 그때 필요한 헤더이다.
https://github.com/tensorflow/tensorflow/tree/master/tensorflow
tensorflow repo에서 필요한 헤더를 가져온다.
Structure
create: TFLite Runtime 초기화
process: preprocess → inference → postprocess
- 위 로직을 Cpp로 구현한다. pre/post process는 이미지 처리, 텐서 처리, 상태 관리 등의 작업을 수행한다.
- `ffigen.yaml` 으로 바인딩(`bindings.dart`)을 생성하고 Cpp 로직을 Dart에서 호출한다.
- 사용자는 내부 구현을 직접 다루지 않고, 의도된 Public Dart API 를 통해 기능을 사용한다.
그래서 호출 흐름은 다음과 같다.
Dart API → FFI bindings → Cpp core → FFI bindings → Dart API
(FFI bindings 는 Cpp과 인터페이스 역할을 하는 Dart Wrapper 이다.)
Usage
Processor 객체를 만든다.
import 'package:mediapipe_face_mesh/mediapipe_face_mesh.dart';
final faceMeshProcessor = await FaceMeshProcessor.create(
delegate: FaceMeshDelegate.xnnpack, // FaceMeshDelegate.cpu is default
);
2가지 사용 패턴이 있다.
하나는 단일 프레임을 전달하는 방식이고
하나는 프레임 스트림을 전달하는 방식이다.
프레임당 연산은 동일하지만, 프레임 흐름을 직접 제어하느냐 스트림 기반으로 패키지가 처리·결과 방출을 맡느냐가 다르다.
// single-image
faceMeshProcessor.processNv21(
nv21,
box: box,
boxScale: 1.2,
boxMakeSquare: true,
rotationDegrees: rotationCompensation,
);
// stream-based
_faceMeshStreamProcessor = FaceMeshStreamProcessor(faceMeshProcessor);
...
_meshStreamSubscription = _faceMeshStreamProcessor
.processNv21(
_nv21StreamController!.stream,
boxResolver: _resolveFaceMeshBoxForNv21,
boxScale: 1.2,
boxMakeSquare: true,
rotationDegrees: rotationDegrees,
)
.listen(_handleMeshResult, onError: _handleMeshError);
스트림 처리 방식도 동일하게 Processor 객체를 사용한다.
현재 지원하는 이미지 포맷은 RGBA / BGRA / NV21 이다.
create와 process 호출 시 몇 가지 optional parmeter가 있으며, 자세한 내용은 패키지 README를 참고하자.
하나만 보자면 `boxScale` 은 face bounding box를 조절하기 위한 파라미터이다.
mlkit face detection은 얼굴 전체가 아니라 턱선이 완전히 포함되지 않은 박스를 반환하는데,
이때 `boxScale` 값을 키우면 얼굴 영역이 더 안정적으로 포함되어 Face Mesh 추론 결과가 개선된다.
Example
https://github.com/cornpip/mediapipe_face_mesh
`mediapipe_face_mesh` repo의 example은 asset 이미지를 로드한 뒤,
bounding box(bbox)를 사용하지 않고 전체 프레임(full frame)에 대해 face mesh 추론을 수행한다.
https://github.com/cornpip/flutter_vision_ai_demos
카메라 리소스를 사용하는 예제는 여기서 확인할 수 있다.
위 예제는 2가지 사용 패턴을 모두 다루며, `google_mlkit_face_detection`을 사용해 face bbox를 얻는다.
앞서 말한 CameraImage → Face bounding box → Face Mesh 순으로 처리한 예제이다.
'flutter' 카테고리의 다른 글
| Flutter Yolo11n Sample (0) | 2025.12.13 |
|---|---|
| Flutter FFI Plugin Project (0) | 2025.11.26 |
| Flutter ML Kit FaceMesh 실시간 얼굴 인식 예제 (0) | 2025.10.24 |
| Flutter Camera ImageStream Issue: The Previous frames remained (0) | 2025.08.12 |
| Flutter Camera Preview Blank - Android10 (0) | 2025.08.04 |