代码之家  ›  专栏  ›  技术社区  ›  Stephen Furlani

iOS 12上的过滤深度数据似乎是旋转的

  •  0
  • Stephen Furlani  · 技术社区  · 7 年前

    我遇到了一个问题 .builtInDualCamera isFilteringEnabled = true

    这是我的密码:

    fileprivate let session = AVCaptureSession()
    
    fileprivate let meta = AVCaptureMetadataOutput()
    fileprivate let video = AVCaptureVideoDataOutput()
    fileprivate let depth = AVCaptureDepthDataOutput()
    
    fileprivate let camera: AVCaptureDevice
    fileprivate let input: AVCaptureDeviceInput
    
    fileprivate let synchronizer: AVCaptureDataOutputSynchronizer
    
    init(delegate: CaptureSessionDelegate?) throws {
        self.delegate = delegate
        session.sessionPreset = .vga640x480
    
        // Setup Camera Input
        let discovery = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera], mediaType: .video, position: .unspecified)
        if let device = discovery.devices.first {
            camera = device
        } else {
            throw SessionError.CameraNotAvailable("Unable to load camera")
        }
    
        input = try AVCaptureDeviceInput(device: camera)
        session.addInput(input)
    
        // Setup Metadata Output (Face)
        session.addOutput(meta)
        if meta.availableMetadataObjectTypes.contains(AVMetadataObject.ObjectType.face) {
            meta.metadataObjectTypes = [ AVMetadataObject.ObjectType.face ]
        } else {
            print("Can't Setup Metadata: \(meta.availableMetadataObjectTypes)")
        }
    
        // Setup Video Output
        video.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
        session.addOutput(video)
        video.connection(with: .video)?.videoOrientation = .portrait
    
        // ****** THE ISSUE IS WITH THIS BLOCK HERE ******
        // Setup Depth Output
        depth.isFilteringEnabled = true
        session.addOutput(depth)
        depth.connection(with: .depthData)?.videoOrientation = .portrait
    
        // Setup Synchronizer
        synchronizer = AVCaptureDataOutputSynchronizer(dataOutputs: [depth, video, meta])
    
    
        let outputRect = CGRect(x: 0, y: 0, width: 1, height: 1)
        let videoRect = video.outputRectConverted(fromMetadataOutputRect: outputRect)
        let depthRect = depth.outputRectConverted(fromMetadataOutputRect: outputRect)
    
        // Ratio of the Depth to Video
        scale = max(videoRect.width, videoRect.height) / max(depthRect.width, depthRect.height)
    
        // Set Camera to the framerate of the Depth Data Collection
        try camera.lockForConfiguration()
        if let fps = camera.activeDepthDataFormat?.videoSupportedFrameRateRanges.first?.minFrameDuration {
            camera.activeVideoMinFrameDuration = fps
        }
        camera.unlockForConfiguration()
    
        super.init()
        synchronizer.setDelegate(self, queue: syncQueue)
    }
    
    func dataOutputSynchronizer(_ synchronizer: AVCaptureDataOutputSynchronizer, didOutput data: AVCaptureSynchronizedDataCollection) {
        guard let delegate = self.delegate else {
            return
        }
    
        // Check to see if all the data is actually here
        guard
            let videoSync = data.synchronizedData(for: video) as? AVCaptureSynchronizedSampleBufferData,
            !videoSync.sampleBufferWasDropped,
            let depthSync = data.synchronizedData(for: depth) as? AVCaptureSynchronizedDepthData,
            !depthSync.depthDataWasDropped
        else {
            return
        }
    
        // It's OK if the face isn't found.
        let face: AVMetadataFaceObject?
        if let metaSync = data.synchronizedData(for: meta) as? AVCaptureSynchronizedMetadataObjectData {
                face = (metaSync.metadataObjects.first { $0 is AVMetadataFaceObject }) as? AVMetadataFaceObject
        } else {
                face = nil
        }
    
        // Convert Buffers to CIImage
        let videoImage = convertVideoImage(fromBuffer: videoSync.sampleBuffer)
        let depthImage = convertDepthImage(fromData: depthSync.depthData, andFace: face)
    
        // Call Delegate
        delegate.captureImages(video: videoImage, depth: depthImage, face: face)
    }
    
    fileprivate func convertVideoImage(fromBuffer sampleBuffer: CMSampleBuffer) -> CIImage {
        // Convert from "CoreMovie?" to CIImage - fairly straight-forward
        let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
        let image = CIImage(cvPixelBuffer: pixelBuffer!)
        return image
    }
    
    fileprivate func convertDepthImage(fromData depthData: AVDepthData, andFace face: AVMetadataFaceObject?) -> CIImage {
    
        var convertedDepth: AVDepthData
    
        // Convert 16-bif floats up to 32
        if depthData.depthDataType != kCVPixelFormatType_DisparityFloat32 {
            convertedDepth = depthData.converting(toDepthDataType: kCVPixelFormatType_DisparityFloat32)
        } else {
            convertedDepth = depthData
        }
    
        // Pixel buffer comes straight from depthData
        let pixelBuffer = convertedDepth.depthDataMap
    
        let image = CIImage(cvPixelBuffer: pixelBuffer)
        return image
    }
    

    原始视频如下:(供参考)

    Original Video Image

    当值为:

    // Setup Depth Output
    depth.isFilteringEnabled = false
    depth.connection(with: .depthData)?.videoOrientation = .portrait
    

    图像如下所示:(你可以看到较近的夹克是白色的,较远的夹克是灰色的,距离是深灰色的-如预期的那样)

    Filtering=False, Orientation=Portrait

    // Setup Depth Output
    depth.isFilteringEnabled = true
    depth.connection(with: .depthData)?.videoOrientation = .portrait
    

    图像如下所示:(可以看到颜色值似乎在正确的位置,但平滑过滤器中的形状似乎是旋转的)

    Filtering=True, Orientation=Portrait

    当值为:

    // Setup Depth Output
    depth.isFilteringEnabled = true
    depth.connection(with: .depthData)?.videoOrientation = .landscapeRight
    

    图像如下所示:(颜色和形状看起来都是水平的)

    Filtering=True, Orientation=Landscape_Right

    我是不是做错了什么来获取这些不正确的值?

    // Setup Depth Output
    depth.connection(with: .depthData)?.videoOrientation = .portrait
    depth.isFilteringEnabled = true
    

    但那没用。

    感谢您的帮助,谢谢!

    0 回复  |  直到 7 年前
        1
  •  2
  •   App Dev Guy    5 年前

    不同的建议,审查其他答案后,旋转图像创建,我发现没有工作,在 AVDepthData documentation

    depthDataByApplyingExifOrientation: 返回 平均深度数据 在应用方向的情况下,也就是说,通过传入所选的参数,您可以按所需的正确方向创建图像。

    这是我的helper方法,它返回 UIImage

    - (UIImage *)createDepthMapImageFromCapturePhoto:(AVCapturePhoto *)photo {
        // AVCapturePhoto which has depthData - in swift you should confirm this exists
        AVDepthData *frontDepthData = [photo depthData];
        // Overwrite the instance with the correct orientation applied.
        frontDepthData = [frontDepthData depthDataByApplyingExifOrientation:kCGImagePropertyOrientationRight];
        // Create the CIImage from the depth data using the available method.
        CIImage *ciDepthImage = [CIImage imageWithDepthData:frontDepthData];
        // Create CIContext which enables converting CIImage to CGImage
        CIContext *context = [[CIContext alloc] init];
        // Create the CGImage
        CGImageRef img = [context createCGImage:ciDepthImage fromRect:[ciDepthImage extent]];
        // Create the final image.
        UIImage *depthImage = [UIImage imageWithCGImage:img];
        // Return the depth image.
        return depthImage;
    }
    
    推荐文章