Реализация AI-замены лица (Face Swap) в мобильном приложении
Face Swap — технически более сложная задача, чем просто «наложить стиль». Нужно: детектировать лицо на исходном изображении, детектировать лицо на целевом, выровнять landmarks, произвести blending результата без артефактов по контуру. На мобиле добавляется ограничение памяти и требование работать за разумное время.
Почему on-device face swap — редкость в 2024
Модели класса SimSwap, FaceShifter, GHOST работают с весами 100–300 MB и требуют GPU. TFLite-порты существуют, но с заметной потерей качества. MediaPipe Face Mesh даёт 468 landmarks в реальном времени — это хорошая база для alignment, но сам swap всё равно требует нейросетевого инференса.
Реальная on-device реализация возможна через Core ML на iPhone 14 Pro+ с дистиллированной моделью: время обработки 1–3 секунды на кадр. На Android — GPU-делегат TFLite, но поведение сильно разнится между устройствами (Adreno 730 против PowerVR на бюджетных).
В большинстве продакшен-приложений face swap идёт через API: InsightFace (open-source self-hosted), Akool, DeepFaceLab API. Akool face_swap endpoint принимает source + target изображение и возвращает результат за 5–15 секунд.
Пайплайн обработки на клиенте
До отправки на сервер нужна предобработка:
// Android: детекция и кропирование лица перед отправкой
class FacePreprocessor(private val context: Context) {
private val detector = FaceDetection.getClient(
FaceDetectorOptions.Builder()
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
.build()
)
suspend fun extractFace(bitmap: Bitmap): FaceExtractionResult {
val image = InputImage.fromBitmap(bitmap, 0)
val faces = detector.process(image).await()
if (faces.isEmpty()) throw FaceSwapError.NoFaceDetected
if (faces.size > 1) throw FaceSwapError.MultipleFaces
val face = faces.first()
val bounds = face.boundingBox
// Expand bounds by 40% for better context
val expandedBounds = expandRect(bounds, 0.4f, bitmap.width, bitmap.height)
val croppedBitmap = Bitmap.createBitmap(
bitmap, expandedBounds.left, expandedBounds.top,
expandedBounds.width(), expandedBounds.height()
)
return FaceExtractionResult(croppedBitmap, face.headEulerAngleY)
}
}
Угол поворота головы (headEulerAngleY) важен: при отклонении >30° качество swap резко падает — об этом стоит предупредить пользователя.
Blending и post-processing
Даже хороший face swap даёт артефакты по краям маски. На клиенте можно применить сглаживание:
На iOS: CIFilter(name: "CIGaussianBlur") по маске лица, CIBlendWithMask для плавного перехода. Metal Performance Shaders для более сложной обработки.
Цвет кожи между лицом и шеей/фоном может не совпадать — colour transfer через LAB-цветовое пространство. Core Image фильтры CIColorCube справляются с этим без выхода в OpenCV.
Правовые ограничения и модерация
Face swap — область с жёсткими требованиями App Store (Guideline 1.1 Objectionable Content). Apple отклоняет приложения, которые:
- позволяют вставить чужое лицо без явного согласия
- не имеют watermark или маркировки AI-generated
- могут использоваться для deepfake
Обязательный минимум: watermark на результате, явный дисклеймер в onboarding, Terms of Service с запретом использования реальных лиц без согласия, система репортинга контента.
Google Play аналогично — Policy Center, раздел Sensitive Events.
Content moderation на сервере: перед генерацией прогнать через Amazon Rekognition DetectModerationLabels или Google Cloud Vision Safe Search. Если входное фото flagged — отклонить на backend, не доводить до генерации.
Хранение и удаление
Результаты face swap не должны храниться на сервере дольше, чем нужно для доставки клиенту. Стандартная практика: TTL 24–48 часов, затем автоудаление из S3/GCS. Входные фото — удалять сразу после обработки.
Сроки
Базовая интеграция API с детекцией лица и отображением результата — 4–6 дней. С post-processing blending, модерацией контента, watermarking и соответствием стор-политикам — 3–4 недели. Стоимость рассчитывается индивидуально.







