6

如何从成功的 VNRectangleObservation 对象中拍摄照片(获取 CIImage)?

我正在运行一个视频捕获会话,并在func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection)其中进行处理,即

func captureOutput(_ output: AVCaptureOutput,
                   didOutput sampleBuffer: CMSampleBuffer,
                   from connection: AVCaptureConnection) {
    guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }

    do {
        try handler.perform([request], on: pixelBuffer)
    } catch {
        print(error)
    }
}

我应该将传递给处理程序并在该缓冲区上操作的像素缓冲区保存在某处吗?很遗憾,我无法将图像作为观察对象的属性访问:(

有任何想法吗?

4

1 回答 1

13

因此,您正在使用产生VNRectangleObservations 的 Vision 请求,并且您想提取由这些观察结果识别的主题图像的区域?也许也可以透视投影它们,以便它们在图像平面上是矩形的?( WWDC17 的 Vision session 中有一个演示。)

CIPerspectiveCorrection您可以使用Core Image中的过滤器提取和纠正该区域。要进行设置,您需要传递图像观察中的点,转换为像素坐标。看起来像这样:

func extractPerspectiveRect(_ observation: VNRectangleObservation, from buffer: CVImageBuffer) -> CIImage {
    // get the pixel buffer into Core Image
    let ciImage = CIImage(cvImageBuffer: buffer)

    // convert corners from normalized image coordinates to pixel coordinates
    let topLeft = observation.topLeft.scaled(to: ciImage.extent.size)
    let topRight = observation.topRight.scaled(to: ciImage.extent.size)
    let bottomLeft = observation.bottomLeft.scaled(to: ciImage.extent.size)
    let bottomRight = observation.bottomRight.scaled(to: ciImage.extent.size)

    // pass those to the filter to extract/rectify the image
    return ciImage.applyingFilter("CIPerspectiveCorrection", parameters: [
        "inputTopLeft": CIVector(cgPoint: topLeft),
        "inputTopRight": CIVector(cgPoint: topRight),
        "inputBottomLeft": CIVector(cgPoint: bottomLeft),
        "inputBottomRight": CIVector(cgPoint: bottomRight),
    ])
}

旁白:scaled上面的函数是一个方便的扩展,CGPoint可以使调用站点的坐标数学更小一些:

extension CGPoint {
   func scaled(to size: CGSize) -> CGPoint {
       return CGPoint(x: self.x * size.width,
                      y: self.y * size.height)
   }
}

现在,这为您提供了一个CIImage对象——它们本身并不是真正可显示的图像,只是有关如何处理和显示图像的说明,可以通过许多不同的可能方式来完成。显示图像的许多方法都涉及CIContext——您可以将其渲染到另一个像素缓冲区,或者如果您尝试实时进行此处理,也可以将其渲染到金属纹理中——但不是全部。另一方面,如果您只是不太频繁地显示静态图像,您可以直接从 CIImage 创建一个 UIImage并将其显示在 aUIImageView中,UIKit 将管理底层CIContext和渲染过程。

于 2018-01-09T20:09:53.053 回答