Вот как я адаптировал образец, чтобы он работал на моем 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)
После этого должно работать отслеживание, и результаты должны быть правильными.