iOS, как сделать отслеживание лица с помощью задней камеры? - PullRequest
1 голос
/ 05 апреля 2020

Я планирую использовать канал камеры ARKit в качестве входных данных для API Apple Vision, чтобы я мог распознавать лица людей в пространстве экрана, информация о глубине не требуется. Чтобы упростить процесс, я пытаюсь изменить пример отслеживания лица Apple по кадрам: Отслеживание лица пользователя в реальном времени

Я подумал, что я мог бы просто изменить функцию здесь:

 fileprivate func configureFrontCamera(for captureSession: AVCaptureSession) throws -> (device: AVCaptureDevice, resolution: CGSize) {
        let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .front)

        if let device = deviceDiscoverySession.devices.first {
            if let deviceInput = try? AVCaptureDeviceInput(device: device) {
                if captureSession.canAddInput(deviceInput) {
                    captureSession.addInput(deviceInput)
                }

                if let highestResolution = self.highestResolution420Format(for: device) {
                    try device.lockForConfiguration()
                    device.activeFormat = highestResolution.format
                    device.unlockForConfiguration()

                    return (device, highestResolution.resolution)
                }
            }
        }

        throw NSError(domain: "ViewController", code: 1, userInfo: nil)
    }

В первой строке функции одним из аргументов является .front для фронтальной камеры. Я изменил это на .back. Это успешно дает мне камеру заднего вида. Однако область распознавания кажется немного изменчивой, и как только она фиксируется на лице на изображении, XCode сообщает об ошибке:

VisionFaceTrack[877:54517] [ServicesDaemonManager] interruptionHandler is called. -[FontServicesDaemonManager connection]_block_invoke
Message from debugger: Terminated due to memory issue

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

Лучшее решение будет также включать информацию о том, как этого добиться с помощью камеры arkit, но я почти уверен, что та же идея с CVPixelBuffer .

Как мне адаптировать этот пример для использования задней камеры?

РЕДАКТИРОВАТЬ: Я думаю, что проблема заключается в том, что мое устройство имеет слишком мало памяти для поддержки алгоритма с использованием задней камеры, в качестве Задняя камера имеет более высокое разрешение.

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

1 Ответ

1 голос
/ 07 апреля 2020

Вот как я адаптировал образец, чтобы он работал на моем iPad Pro.


1) Загрузите образец проекта отсюда: Отслеживание лица пользователя в реальном времени.


2) Измените функцию загрузки фронтальной камеры на обратную. Переименуйте его в configureBackCamera и вызовите этот метод setupAVCaptureSession:

fileprivate func configureBackCamera(for captureSession: AVCaptureSession) throws -> (device: AVCaptureDevice, resolution: CGSize) {
    let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .back)

    if let device = deviceDiscoverySession.devices.first {
        if let deviceInput = try? AVCaptureDeviceInput(device: device) {
            if captureSession.canAddInput(deviceInput) {
                captureSession.addInput(deviceInput)
            }

            if let highestResolution = self.highestResolution420Format(for: device) {
                try device.lockForConfiguration()
                device.activeFormat = highestResolution.format
                device.unlockForConfiguration()

                return (device, highestResolution.resolution)
            }
        }
    }

    throw NSError(domain: "ViewController", code: 1, userInfo: nil)
}

3) Измените реализацию метода highestResolution420Format. Проблема в том, что теперь, когда используется камера с обратной стороны, у вас есть доступ к форматам с гораздо более высоким разрешением, чем с камерой с фронтальной стороной, что может повлиять на производительность отслеживания. Вы должны адаптироваться к своему варианту использования, но вот пример ограничения разрешения до 1080p.

fileprivate func highestResolution420Format(for device: AVCaptureDevice) -> (format: AVCaptureDevice.Format, resolution: CGSize)? {
    var highestResolutionFormat: AVCaptureDevice.Format? = nil
    var highestResolutionDimensions = CMVideoDimensions(width: 0, height: 0)

    for format in device.formats {
        let deviceFormat = format as AVCaptureDevice.Format

        let deviceFormatDescription = deviceFormat.formatDescription
        if CMFormatDescriptionGetMediaSubType(deviceFormatDescription) == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange {
            let candidateDimensions = CMVideoFormatDescriptionGetDimensions(deviceFormatDescription)
            if (candidateDimensions.height > 1080) {
                continue
            }
            if (highestResolutionFormat == nil) || (candidateDimensions.width > highestResolutionDimensions.width) {
                highestResolutionFormat = deviceFormat
                highestResolutionDimensions = candidateDimensions
            }
        }
    }

    if highestResolutionFormat != nil {
        let resolution = CGSize(width: CGFloat(highestResolutionDimensions.width), height: CGFloat(highestResolutionDimensions.height))
        return (highestResolutionFormat!, resolution)
    }

    return nil
}

4) Теперь отслеживание будет работать, но положения лица будут неправильными. Причина в том, что представление пользовательского интерфейса неверно, потому что оригинальный образец был разработан для фронтальных камер с зеркальным дисплеем, в то время как обратная камера не нуждается в зеркалировании.

Для настройки просто измените updateLayerGeometry() метод. В частности, вам нужно изменить это:

// Scale and mirror the image to ensure upright presentation.
let affineTransform = CGAffineTransform(rotationAngle: radiansForDegrees(rotation))
    .scaledBy(x: scaleX, y: -scaleY)
overlayLayer.setAffineTransform(affineTransform)

на это:

// Scale the image to ensure upright presentation.
let affineTransform = CGAffineTransform(rotationAngle: radiansForDegrees(rotation))
    .scaledBy(x: -scaleX, y: -scaleY)
overlayLayer.setAffineTransform(affineTransform)

После этого должно работать отслеживание, и результаты должны быть правильными.

...