我能否在ARkit相机输入流中应用CIFilter?

7

我想在ARSCNView相机实时图像中应用模糊效果。我已经查看了WWDC视频,他们只提到了使用Metal进行自定义渲染,但是我没有在网上找到任何完整的示例。有什么办法可以做到这一点吗?


更新1 我试图对背景应用过滤器。它显示不正确的方向。我该怎么解决?

let bg=self.session.currentFrame?.capturedImage

        if(bg != nil){
            let context = CIContext()
            let filter:CIFilter=CIFilter(name:"CIColorInvert")!
            let image:CIImage=CIImage(cvPixelBuffer: bg!)
            filter.setValue(image, forKey: kCIInputImageKey)
            let result=filter.outputImage!
            self.sceneView.scene.background.contents = context.createCGImage(result, from: result.extent)

        }

1
可能你可以在SceneKit中使用ScnTechnique的后处理功能;我自己没有尝试过。https://developer.apple.com/documentation/scenekit/scntechnique - M. Bedi
看起来直播流图像被设置为场景背景,我不确定如何添加滤镜。您还可以通过sceneView.session.currentFrame?.capturedImage访问像素缓冲区,因此您可能能够将滤镜应用于它并更新背景。 - Guig
@Guig 谢谢!它起作用了!我现在可以在背景上应用一些CIFilters!但是方向不正确... - Wayne Tam
如果您可以处理YCbCr像素缓冲区,这个解决方案适用 - diviaki
2个回答

5

我找到了一个相当不错的解决方案,就是在设备方向改变时,简单地对background属性应用相应的几何变换:

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    let image = CIImage(cvPixelBuffer: frame.capturedImage)
    filter.setValue(image, forKey: kCIInputImageKey)

    let context = CIContext()
    if let result = filter.outputImage,
        let cgImage = context.createCGImage(result, from: result.extent) {

        sceneView.scene.background.contents = cgImage
        if let transform = currentScreenTransform() {
            sceneView.scene.background.contentsTransform = transform
        }
    }
}

private func currentScreenTransform() -> SCNMatrix4? {
    switch UIDevice.current.orientation {
    case .landscapeLeft:
        return SCNMatrix4Identity
    case .landscapeRight:
        return SCNMatrix4MakeRotation(.pi, 0, 0, 1)
    case .portrait:
        return SCNMatrix4MakeRotation(.pi / 2, 0, 0, 1)
    case .portraitUpsideDown:
        return SCNMatrix4MakeRotation(-.pi / 2, 0, 0, 1)
    default:
        return nil
    }
}

在你的viewDidLoad方法中首先调用UIDevice.current.beginGeneratingDeviceOrientationNotifications()


1
你好,我想在ARKit中使用CIFilter集成颜色滤镜,我已经尝试了上面的代码,但是在运行时输出被拉伸了,我已经发布了相关问题,请看一下,https://dev59.com/Tbfna4cB1Zd3GeqPlgw8 - Anand Nanavaty

0

我曾经遇到同样的问题。你可以试试这个

let bg = sceneView.session.currentFrame?.capturedImage
    if (bg != nil) {
        let context = CIContext()
        let filter:CIFilter = CIFilter(name: "CIColorInvert")!

        let image:CIImage = CIImage(cvPixelBuffer: bg!, options: nil)

        let cgImage:CGImage = context.createCGImage(image, from: image.extent)!
        let uiImage:UIImage = UIImage.init(cgImage: cgImage)
        let resultImage = CIImage(image: uiImage)?.oriented(forExifOrientation: imageOrientationToDeviceOrientation(value: UIDevice.current.orientation))

        filter.setValue(resultImage, forKey: kCIInputImageKey)

        let result = filter.outputImage!
        self.sceneView.scene.background.contents = context.createCGImage(result, from: result.extent)
    }


func imageOrientationToDeviceOrientation(value: UIDeviceOrientation) -> Int32 {
            switch (value) {
            case .portrait:
                return 6
            case .landscapeLeft:
                return 1
            case .landscapeRight:
                return 3
            default:
                return 6
            }
        }

3
这个解决方案在iPhone7P上可行,但速度太慢不实用。 - diviaki
对我来说,它将 iPhone7P 的帧时间从2毫秒飙升到20毫秒。你的测量结果是多少? - diviaki
你是如何衡量的? - Anna Sukhorukova
viewDidLoad 中设置 self.sceneView.showsStatistics = YES; 链接,然后运行应用程序并点击“+”以打开它。 - diviaki
嗯...是的,它是20毫秒...但视觉上图片并没有变慢...你能给我们其他的解决方案吗? - Anna Sukhorukova
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接