结合 CoreML 和 ARKit

Posted

技术标签:

【中文标题】结合 CoreML 和 ARKit【英文标题】:Combining CoreML and ARKit 【发布时间】:2017-12-26 13:35:12 【问题描述】:

我正在尝试使用 Apple website 上给定的 inceptionV3 模型在我的项目中。

我从 ARKit 的标准模板开始(Xcode 9 beta 3)

我没有启动新的相机会话,而是重用 ARSCNView 已启动的会话。

在我的 viewDelegate 结束时,我写道:

sceneView.session.delegate = self

然后我扩展我的 viewController 以符合 ARSessionDelegate 协议(可选协议)

// MARK: ARSessionDelegate
extension ViewController: ARSessionDelegate 

    func session(_ session: ARSession, didUpdate frame: ARFrame) 

        do 
            let prediction = try self.model.prediction(image: frame.capturedImage)
            DispatchQueue.main.async 
                if let prob = prediction.classLabelProbs[prediction.classLabel] 
                    self.textLabel.text = "\(prediction.classLabel) \(String(describing: prob))"
                
            
        
        catch let error as NSError 
            print("Unexpected error ocurred: \(error.localizedDescription).")
        
    

起初我尝试了该代码,但后来注意到 inception 需要一个 Image 类型的像素缓冲区。 。

虽然没有重新开始,但我想我会调整框架的大小,然后尝试从中获得预测。我正在使用这个函数调整大小(取自https://github.com/yulingtianxia/Core-ML-Sample)

func resize(pixelBuffer: CVPixelBuffer) -> CVPixelBuffer? 
    let imageSide = 299
    var ciImage = CIImage(cvPixelBuffer: pixelBuffer, options: nil)
    let transform = CGAffineTransform(scaleX: CGFloat(imageSide) / CGFloat(CVPixelBufferGetWidth(pixelBuffer)), y: CGFloat(imageSide) / CGFloat(CVPixelBufferGetHeight(pixelBuffer)))
    ciImage = ciImage.transformed(by: transform).cropped(to: CGRect(x: 0, y: 0, width: imageSide, height: imageSide))
    let ciContext = CIContext()
    var resizeBuffer: CVPixelBuffer?
    CVPixelBufferCreate(kCFAllocatorDefault, imageSide, imageSide, CVPixelBufferGetPixelFormatType(pixelBuffer), nil, &resizeBuffer)
    ciContext.render(ciImage, to: resizeBuffer!)
    return resizeBuffer
 

不幸的是,这还不足以让它发挥作用。这是捕获的错误:

Unexpected error ocurred: Input image feature image does not match model description.
2017-07-20 AR+MLPhotoDuplicatePrediction[928:298214] [core] 
    Error Domain=com.apple.CoreML Code=1 
    "Input image feature image does not match model description" 
    UserInfo=NSLocalizedDescription=Input image feature image does not match model description, 
    NSUnderlyingError=0x1c4a49fc0 Error Domain=com.apple.CoreML Code=1 
    "Image is not expected type 32-BGRA or 32-ARGB, instead is Unsupported (875704422)" 
    UserInfo=NSLocalizedDescription=Image is not expected type 32-BGRA or 32-ARGB, instead is Unsupported (875704422)

不确定我能从这里做什么。

如果有更好的建议将两者结合起来,我会全力以赴。

编辑:我也尝试了@dfd建议的YOLO-CoreML-MPSNNGraph中的resizePixelBuffer方法,错误是完全一样的。

Edit2:所以我把像素格式改成了kCVPixelFormatType_32BGRA(和resizePixelBuffer中传入的pixelBuffer格式不一样)。

let pixelFormat = kCVPixelFormatType_32BGRA // line 48

我没有错误了。但是一旦我尝试做出预测, AVCaptureSession 就会停止。似乎我在 apple developers forum 上运行 Enric_SA 时遇到了同样的问题。

Edit3:所以我尝试实施 rickster 解决方案。与 inceptionV3 配合良好。我想尝试一个特征观察(VNClassificationObservation)。目前,它无法使用TinyYolo。边界是错误的。试图弄清楚。

【问题讨论】:

到目前为止,我给出的建议是博客 (machinethink.net/blog/yolo-coreml-versus-mps-graph) 和相关的 repo (github.com/hollance/YOLO-CoreML-MPSNNGraph)。是的,这与 YOLO 和 CoreML 一样多(并且对 ML 非常深入),但是代码有一个很好的方法来将 UIImage 调整为 224x224 并返回一个 CVPixelBuffer。大约 2 天前,我在这里评论了另一个问题 - 您可能会通过搜索“像素缓冲区”和“Swift”找到该代码,并按问题日期排序。 @dfd 试过了,结果(错误)是一样的。该项目直接使用相机会话,它不会尝试重用 ARSCNView 会话。 【参考方案1】:

不要自己处理图像以将它们提供给 Core ML。使用Vision。 (不,不是那个。This one。)Vision 采用 ML 模型和多种图像类型中的任何一种 (including CVPixelBuffer) 并自动将图像获取到正确的大小、纵横比和像素格式以供模型评估,然后给你模型的结果。

这是您需要的代码的粗略框架:

var request: VNRequest

func setup() 
    let model = try VNCoreMLModel(for: MyCoreMLGeneratedModelClass().model)
    request = VNCoreMLRequest(model: model, completionHandler: myResultsMethod)


func classifyARFrame() 
    let handler = VNImageRequestHandler(cvPixelBuffer: session.currentFrame.capturedImage,
        orientation: .up) // fix based on your UI orientation
    handler.perform([request])


func myResultsMethod(request: VNRequest, error: Error?) 
    guard let results = request.results as? [VNClassificationObservation]
        else  fatalError("huh") 
    for classification in results 
        print(classification.identifier, // the scene label
              classification.confidence)
    

请参阅this answer 到另一个问题以获取更多指示。

【讨论】:

你好@rickster。它适用于 VNClassificationObservation,但我直接从 tiny-yolo 示例 (github.com/hollance/YOLO-CoreML-MPSNNGraph) 遇到 VNCoreMLFeatureValueObservation 问题。就像我的边界框大小不合适。很奇怪,但我不知道为什么。 很难说没有更详细的诊断(即使那时它也有点超出我的管辖范围),但如果我不得不冒险猜测它可能与像素尺寸、标准化图像坐标与裁剪/比例有关选项,视频清洁光圈也有一些可能性。 @ina :从那以后我没有花太多时间研究它。但我最有根据的猜测是将请求结果转换为? [VNCoreMLFeatureValueObservation] 没有以应有的方式解析观察结果的 multiArrayValue。这可以解释为什么边界框是关闭的。不过我不确定,我必须通过矩阵或类似的东西来运行数组。

以上是关于结合 CoreML 和 ARKit的主要内容,如果未能解决你的问题,请参考以下文章

使用 ARKit 和 CoreML 从远距离检测物体

带有 ARkit 和 CoreML 的视觉框架

对象检测 ARKit 与 CoreML

ARkit简介

Vision 和 CoreML – CGImagePropertyOrientation 需要错误的类型

ARKit 和视觉框架——检测墙壁边缘