Технология виртуальной примерки позволяет покупателям увидеть, как товар выглядит на них. Это позволяет им практически «примерить» товар перед покупкой. Теперь покупатели могут виртуально примерять продукты, такие как одежда, косметика, украшения, защитные очки и т. д.

В настоящее время многие бренды электронной коммерции используют технологию виртуальной примерки для маркетинга. Виртуальная примерка является частью дополненной реальности (AR). Дополненная реальность — это будущее всего. Он не ограничивается только покупками. Образование, здравоохранение, розничная торговля, развлечения и т. д. везде, где мы его используем.

В сфере разработки есть множество библиотек, предоставляющих виртуальный пробный функционал, но большинство из них платные. Apple также каждый год работает над новыми фреймворками. Они предоставляют множество быстрых API для работы с дополненной реальностью.

Начать

В этой статье я расскажу, как с помощью Swift Framework нанести любой цвет на человеческие волосы. Я поиграю с примером проекта, с помощью которого пользователь может сделать селфи и нанести на волосы любой цвет. Давайте разобьем эту статью на 2 этапа. Первый шаг — сделать селфи, а второй шаг — применить цвет волос к захваченному селфи.

Шаг 1: Камера

Давайте начнем сначала, чтобы взять селфи. Я предполагаю, что вы уже знаете о том, как фотографировать с помощью фреймворка AVFoundation. Я не буду углубляться в это, прыгая по высоким узлам, чтобы сделать требуемое фото. Давайте посмотрим код:

guard let videoDevice = AVCaptureDevice.default(.builtInTrueDepthCamera, for: .video, position: .front) else { return }
guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else { return }
guard self.captureSession.canAddInput(videoDeviceInput) else { return }
self.captureSession.addInput(videoDeviceInput)

В приведенных выше строках, во-первых, я проверяю trueDepthCamera. Это основное требование. Если доступна trueDepthCamera, добавьте устройство ввода с фронтальной камерой.

Согласно Apple, встроенная камера InTrueDepthCamera представляет собой комбинацию камер и других датчиков, которая создает устройство захвата, способное захватывать фото, видео и глубину.

guard self.captureSession.canAddOutput(photoOutput) else { return }
self.captureSession.addOutput(photoOutput)

Теперь добавил фотовыход с сессии.

self.photoOutput.enabledSemanticSegmentationMatteTypes = photoOutput.availableSemanticSegmentationMatteTypes
self.photoOutput.isDepthDataDeliveryEnabled = true
self.photoOutput.isPortraitEffectsMatteDeliveryEnabled = true
self.photoOutput.isHighResolutionCaptureEnabled = true

Эти четыре строки являются основным кодом, который применяется к выходным данным. Давайте подробно обсудим некоторые моменты, прежде чем перейти к объяснению этих линий.

AVSemanticSegmentationMatte упаковывает матовое изображение для определенной семантической сегментации. Матирующее изображение хранит свои пиксельные данные в виде объектов CVPixelBuffer в формате kCVPixelFormatType_OneComponent8. Файл изображения содержит подложку семантической сегментации в качестве вспомогательного изображения.

matteType — это тип матового изображения семантической сегментации.

Вернемся к 4 строчкам выше:

  • Во-первых, я включаю все типы подложек семантической сегментации, которые могут быть захвачены и доставлены вместе с фотографией.
  • Во-вторых, указание конфигурации конвейера захвата для данных о глубине.
  • В-третьих, при захвате вывода создается матовый портретный эффект.
  • В-четвертых, чтобы включить захват с высоким разрешением.

Теперь давайте добавим некоторые параметры AVCapturePhotoSettings в качестве типа кодека, вспышки, формата предварительного просмотра фотографий, данных о глубине, подложки портретного эффекта и типов подложки семантической сегментации.

if  photoOutput.availablePhotoCodecTypes.contains(.hevc) {
self.photoSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.hevc])
}
if videoDeviceInput.device.isFlashAvailable {
self.photoSettings.flashMode = .auto
}
self.photoSettings.isHighResolutionPhotoEnabled = true
if let previewPhotoPixelFormatType = self.photoSettings.availablePreviewPhotoPixelFormatTypes.first {
self.photoSettings.previewPhotoFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewPhotoPixelFormatType]
}
self.photoSettings.isDepthDataDeliveryEnabled = photoOutput.isDepthDataDeliveryEnabled
self.photoSettings.isPortraitEffectsMatteDeliveryEnabled = photoOutput.isPortraitEffectsMatteDeliveryEnabled
if self.photoSettings.isDepthDataDeliveryEnabled {
if !photoOutput.availableSemanticSegmentationMatteTypes.isEmpty {
self.photoSettings.enabledSemanticSegmentationMatteTypes = photoOutput.availableSemanticSegmentationMatteTypes
}
}

После этого добавьте AVCaptureVideoPreviewLayer в представление и запустите сеанс. Как только вы сделаете снимок, вы получите AVCapturePhoto в функции делегата AVCapturePhotoCaptureDelegate.

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
}

Вот и пройден первый этап.

Шаг 2: Цвет волос

Теперь у вас есть AVCapturePhoto. Чтобы применить какой-либо фильтр к этой фотографии захвата, сначала вам нужно извлечь изображение буфера пикселей для предварительного просмотра и матовое изображение семантической сегментации для типа волос. Затем я могу применить CIFilters с помощью этих изображений.

Давайте получим матовое изображение семантической сегментации для типа волос с ориентацией из захваченного AVCapturePhoto. Ниже приведен код для этого. Он вернет объект CIImage.

extension AVCapturePhoto {
func hairSemanticSegmentationMatteImage() -> CIImage? {
if var matte = self.semanticSegmentationMatte(for: .hair) {
if let orientation = self.metadata[String(kCGImagePropertyOrientation)] as? UInt32, let exifOrientation = CGImagePropertyOrientation(rawValue: orientation) {
matte = matte.applyingExifOrientation(exifOrientation)
}
return CIImage(cvPixelBuffer: matte.mattingImage)
}
return nil
}
}

Теперь давайте получим изображение буфера пикселей для предварительного просмотра из захваченной фотографии. Вот код:

extension AVCapturePhoto {
func getPreviewPixelBufferImage() -> CIImage? {
if let pixelBuffer = self.previewPixelBuffer {
if let orientation = self.metadata[String(kCGImagePropertyOrientation)] as? UInt32, let exifOrientation = CGImagePropertyOrientation(rawValue: orientation) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer).oriented(forExifOrientation: Int32(exifOrientation.rawValue))
return ciImage
} else {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
return ciImage
}
}
return nil
}
}

Обе функции возвращают объект типа CIImage.

Теперь давайте нанесем цвет на волосы с помощью фильтров CIColorMatrix и CIBlendWithMask. Вот процесс:

  1. Получите изображение буфера пикселей предварительного просмотра из захваченного AVCapturePhoto.
  2. Получите матовое изображение семантической сегментации для типа волос из захваченного AVCapturePhoto.
  3. Получите RGB цвета, который вы хотите применить к волосам.
  4. Примените фильтр CIColorMatrix к изображению буфера пикселей предварительного просмотра со значениями цвета RGB.
  5. Теперь примените фильтр CIBlendWithMask к выходному изображению CIColorMatrix с маскированием матового изображения семантической сегментации. Тогда результирующее выходное изображение будет с окрашенными волосами.

Предположим, вы знаете, как использовать CIFilter. Если нет, то нет проблем. В конце этой статьи я поделюсь ссылкой на полный исходный код этого задания.

Итак, мы также завершили шаг 2. После выполнения шага 2 результирующее изображение будет таким. Посмотрите на волосы этого мальчика.

На этом фото он мой малыш 😊. Он играл, поэтому использовал свое лицо для этого задания 😂.

Я попробовал применить три цвета — красный, зеленый и черный. Вы можете видеть, что волосы окрашены. В позиции ниже левое — исходное изображение, а правое — матовое изображение сегментированных волос.

Краткое содержание

Apple сделала это довольно просто и бесплатно, иначе это будет очень дорого, если вы будете использовать стороннюю библиотеку. Я уверен, что на грядущей конференции WWDC Apple добьется того же с потоковым видео. Тогда это будут огромные изменения.

Вот ссылка на полный исходный код: https://github.com/sanjeevworkstation/SGHairColor

Спасибо. Удачного кодирования! 👍

Наслаждайтесь моими предыдущими статьями!