【问题标题】:How to read depth data at a CGPoint from AVDepthData buffer如何从 AVDepthData 缓冲区读取 CGPoint 处的深度数据
【发布时间】:2017-11-10 19:15:18
【问题描述】:

我试图在捕获的图像中的某个点找到深度数据,并在meters 中返回距离。

我已启用深度数据并在图像旁边捕获数据。我从图像中心的 X、Y 坐标(按下时)获取点,并使用

将其转换为缓冲区索引
Int((width - touchPoint.x) * (height - touchPoint.y))

WIDTHHEIGHT 是捕获图像的尺寸。我不确定这是否是实现这一目标的正确方法。

我这样处理深度数据:

func handlePhotoDepthCalculation(point : Int) {

    guard let depth = self.photo else {
        return
    }

    //
    // Convert Disparity to Depth
    //
    let depthData = (depth.depthData as AVDepthData!).converting(toDepthDataType: kCVPixelFormatType_DepthFloat32)
    let depthDataMap = depthData.depthDataMap //AVDepthData -> CVPixelBuffer

    //
    // Set Accuracy feedback
    //
    let accuracy = depthData.depthDataAccuracy
    switch (accuracy) {
    case .absolute:
        /* 
        NOTE - Values within the depth map are absolutely 
        accurate within the physical world.
        */
        self.accuracyLbl.text = "Absolute"
        break
    case .relative:
        /* 
        NOTE - Values within the depth data map are usable for 
        foreground/background separation, but are not absolutely 
        accurate in the physical world. iPhone always produces this.
        */
        self.accuracyLbl.text = "Relative"
    }

    //
    // We convert the data
    //
    CVPixelBufferLockBaseAddress(depthDataMap, CVPixelBufferLockFlags(rawValue: 0))
    let depthPointer = unsafeBitCast(CVPixelBufferGetBaseAddress(depthDataMap), to: UnsafeMutablePointer<Float32>.self)

    //
    // Get depth value for image center
    //
    let distanceAtXYPoint = depthPointer[point]

    //
    // Set UI
    //
    self.distanceLbl.text = "\(distanceAtXYPoint) m" //Returns distance in meters?
    self.filteredLbl.text = "\(depthData.isDepthDataFiltered)" 
}

我不相信我得到了正确的位置。从我的研究来看,准确度似乎只在.relative.absolute 中返回,而不是浮点数/整数?

【问题讨论】:

    标签: ios swift avcapturesession


    【解决方案1】:

    要访问 CGPoint 的深度数据,请执行以下操作:

    let point = CGPoint(35,26)
    let width = CVPixelBufferGetWidth(depthDataMap)
    let distanceAtXYPoint = depthPointer[Int(point.y * CGFloat(width) + point.x)]
    

    我希望它有效。

    【讨论】:

    • 这是正确答案。深度数据是代表所有点的一维数组。要查找 x,y 的数据,您需要 y*width + x
    • 这种方法导致我的值不正确和波动,我的解决方案结帐stackoverflow.com/a/66636994/9142902
    【解决方案2】:

    在像素位置访问深度数据:

    let depthDataMap: CVPixelBuffer = ...
    let pixelX: Int = ...
    let pixelY: Int = ...
    
    CVPixelBufferLockBaseAddress(self, .readOnly)
    let bytesPerRow = CVPixelBufferGetBytesPerRow(depthDataMap)
    let baseAddress = CVPixelBufferGetBaseAddress(depthDataMap)!
    assert(kCVPixelFormatType_DepthFloat32 == CVPixelBufferGetPixelFormatType(depthDataMap))
    
    let rowData = baseAddress + pixelY * bytesPerRow
    let distance = rowData.assumingMemoryBound(to: Float32.self)[pixelX]
    
    CVPixelBufferUnlockBaseAddress(self, .readOnly)
    

    对我来说,访问深度时的值不正确且不一致

    let depthPointer = unsafeBitCast(CVPixelBufferGetBaseAddress(depthDataMap), to: UnsafeMutablePointer<Float32>.self)
    

    【讨论】:

      【解决方案3】:

      表示深度数据图总体准确度的值。

      深度数据图的准确性在很大程度上取决于用于生成它的相机校准数据。如果在拍摄时无法准确确定相机的焦距,则会引入 z(深度)平面的缩放误差。如果在捕获时不能精确确定相机的光学中心,则会引入主点误差,从而导致视差估计中的偏移误差。 这些值报告地图值相对于其报告单位的准确性。

      案例相对

      深度数据图中的值可用于前景/背景分离,但在物理世界中并非绝对准确。

      案例绝对

      深度图中的值在物理世界中绝对准确。

      您已从 AVDepthData 缓冲区中获取 CGPoint,例如高度和宽度,例如跟随代码。

      // Useful data
       let width = CVPixelBufferGetWidth(depthDataMap) 
       let height = CVPixelBufferGetHeight(depthDataMap) 
      

      【讨论】:

      • 我已经看到了你从哪里复制那个答案的问题。我也已经展示了如何获取我的数据点 - Int((width - touchPoint.x) * (height - touchPoint.y)) 这是相同的。这只是对问题的描述,而不是 imo 的答案。
      【解决方案4】:

      在 Apple 的示例 project 中,他们使用下面的代码。

      Texturepoint 是示例项目中使用的投影到金属视图的触摸点。

      // scale
      let scale = CGFloat(CVPixelBufferGetWidth(depthFrame)) / CGFloat(CVPixelBufferGetWidth(videoFrame))
      let depthPoint = CGPoint(x: CGFloat(CVPixelBufferGetWidth(depthFrame)) - 1.0 - texturePoint.x * scale, y: texturePoint.y * scale)
              
      assert(kCVPixelFormatType_DepthFloat16 == CVPixelBufferGetPixelFormatType(depthFrame))
      CVPixelBufferLockBaseAddress(depthFrame, .readOnly)
      let rowData = CVPixelBufferGetBaseAddress(depthFrame)! + Int(depthPoint.y) * CVPixelBufferGetBytesPerRow(depthFrame)
      // swift does not have an Float16 data type. Use UInt16 instead, and then translate
      var f16Pixel = rowData.assumingMemoryBound(to: UInt16.self)[Int(depthPoint.x)]
      CVPixelBufferUnlockBaseAddress(depthFrame, .readOnly)
              
      var f32Pixel = Float(0.0)
      var src = vImage_Buffer(data: &f16Pixel, height: 1, width: 1, rowBytes: 2)
      var dst = vImage_Buffer(data: &f32Pixel, height: 1, width: 1, rowBytes: 4)
      vImageConvert_Planar16FtoPlanarF(&src, &dst, 0)
              
      // Convert the depth frame format to cm
      let depthString = String(format: "%.2f cm", f32Pixel * 100)
      

      【讨论】:

        猜你喜欢
        • 2020-07-13
        • 2011-11-11
        • 2013-08-03
        • 1970-01-01
        • 1970-01-01
        • 2011-02-05
        • 2018-06-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多