【问题标题】:How to pass an extra parameter to Vision framework?如何将额外的参数传递给 Vision 框架?
【发布时间】:2020-07-19 18:01:35
【问题描述】:

我有一个运行良好的 Swift / CoreML 代码。我想通过使用 Vision 框架来简化我的代码。 在这段代码中,有一个我想去掉的 UIImage -> CGImage -> CVPixelBuffer 转换。我知道使用 Vision 可以直接将 CGImage 作为输入参数传递。我遇到的问题是我的模型需要 2 个输入(图像 + MLMultiArray)和输出和图像:

Inputs

    my_input : Image (Color 512 x 512)
    my_sigma : MultiArray (Float32 1)

Outputs

    my_output : Image (Color 512 x 512)

我尝试按如下方式传递 sigma 参数:

guard let cgImage = uiImage.cgImage else {
    return nil
}

let options:[VNImageOption: Any] = [VNImageOption(rawValue: "my_sigma"): 0.1]

let handler = VNImageRequestHandler(cgImage: cgImage, options: options)
do {
    try handler.perform(visionRequest)
} catch {
    print(error)
}

这样做,我得到以下错误:

[coreml] 验证输入失败。没有结果:Error Domain=com.apple.vis Code=3 "The VNCoreMLTransform request failed" UserInfo={NSLocalizedDescription=The VNCoreMLTransform request failed, NSUnderlyingError=0x280cbbab0 {Error Domain=com.apple.CoreML Code=0 "Required input feature not传递给神经网络。”

所以,看来我没有正确地将第二个参数传递给请求处理程序。我一直没能找到答案。

  • 将此类参数传递给 Vision 的正确方法是什么?
  • 你知道我是否可以使用 Vision 直接输出图像吗?

感谢您的帮助。

【问题讨论】:

    标签: swift coreml vision


    【解决方案1】:

    我在下面提供的代码似乎工作正常。它可能不是最佳的,但至少它可以工作,这是一个很好的第一步。主要的困难是理解MLFeatureProvider 的工作原理:

    class SigmaProvider: MLFeatureProvider {
    
        let sigma: Double
    
        init(sigma: Double) {
            self.sigma = sigma
        }
    
        var featureNames: Set<String> {
            get {
                return ["my_sigma"]
            }
        }
    
        func featureValue(for featureName: String) -> MLFeatureValue? {
            if (featureName == "my_sigma") {
                let array = try! MLMultiArray(shape: [1], dataType: .float32)
                array[0] = NSNumber(value: self.sigma)
                return MLFeatureValue(multiArray: array)
            }
            return nil
        }
    }
    

    该类定义了一个名为my_sigma 的输入,其类型为MLMultiArray。下面是将 CoreML 模型(名为 model)应用于输入 UIImage 的代码:

    // Input CGImage
    guard let cgImage = uiImage.cgImage else {
        return nil
    }
    
    // Load and setup the Vision model
    guard let visionModel = try? VNCoreMLModel(for: model.model) else {
        fatalError("Cannot load Vision ML model")
    }
    visionModel.inputImageFeatureName = "my_input"
    visionModel.featureProvider = SigmaProvider(sigma: self.sigma)
    
    // Create the request
    let request = VNCoreMLRequest(model: visionModel)
    request.usesCPUOnly = false
    
    // Handler
    let handler = VNImageRequestHandler(cgImage: cgImage)
    
    // Process
    do {
        try handler.perform([request])
    }
    catch {
        print("Error while performing Vision request: \(error)")
        return nil
    }
    
    // Get the result
    guard let results = request.results else {
        print("No request results")
        return nil
    }
    
    // Convert the resulting CVPixelBuffer into a UIImage
    for case let resultingImage as VNPixelBufferObservation in results {
        if resultingImage.featureName == "my_output" {
            let ciOutput = CIImage(cvPixelBuffer: resultingImage.pixelBuffer)
            UIGraphicsBeginImageContextWithOptions(uiImage.size, true, 1.0)
            UIImage(ciImage: ciOutput).draw(at: CGPoint(x: 0, y: 0))
            let output = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return output
        }
    }
    

    请注意,SigmaProvider 类中不需要我的模型的第一个参数my_input。它是使用inputImageFeatureName 属性指定的。最后,我通过遍历所有结果来访问my_output

    我希望这会对某人有所帮助。

    【讨论】:

      【解决方案2】:

      查看VNCoreMLRequestfeatureProvider 属性。这是一个提供额外输入的对象,即除了图像输入之外的任何内容。

      【讨论】:

      • 按照您的建议,我将通过展示适用于这个示例的方法来回答我自己的问题。感谢您的建议。
      • 我可能应该提到 MLDictionaryFeatureProvider 的存在,但你的代码看起来也不错。
      • 你是对的,下面的代码似乎可以解决问题:let array = try! MLMultiArray(shape: [1], dataType: .float32); array[0] = NSNumber(value: self.sigma); visionModel.featureProvider = try? MLDictionaryFeatureProvider(dictionary: ["my_sigma": array])
      • 我认为您甚至不需要 MLMultiArray,即尝试使用 MLDictionaryFeatureProvider(dictionary: ["my_sigma": 3.14])
      • 目前需要:验证输入失败。执行视觉请求时出错:Error Domain=com.apple.vis Code=3 "The VNCoreMLTransform request failed" UserInfo={NSLocalizedDescription=The VNCoreMLTransform request failed, NSUnderlyingError=0x28350b570 {Error Domain=com.apple.CoreML Code=1 "MultiArrayConstraint只允许 MultiArrays" UserInfo={NSLocalizedDescription=MultiArrayConstraint 只允许 MultiArrays}}}
      猜你喜欢
      • 2018-10-07
      • 1970-01-01
      • 2020-03-15
      • 2012-09-01
      • 2016-02-16
      • 1970-01-01
      • 1970-01-01
      • 2011-03-06
      • 2021-02-27
      相关资源
      最近更新 更多