如何将额外参数传递给 Vision 框架?
How to pass an extra parameter to Vision framework?
我有一个 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] 验证输入失败。 no results:Error Domain=com.apple.vis Code=3 "The VNCoreMLTransform request failed" UserInfo={NSLocalizedDescription=VNCoreMLTransform 请求失败,NSUnderlyingError=0x280cbbab0 {Error Domain=com.apple.CoreML Code=0 "Required input feature not passed to neural network."
所以,我似乎没有将第二个参数正确传递给请求处理程序。我一直没能找到答案。
- 将这样的参数传递给 Vision 的正确方法是什么?
- 你知道我是否可以使用 Vision 直接输出图像?
谢谢你的帮助。
看看 VNCoreMLRequest
的 featureProvider
属性。这是一个提供额外输入的对象,即除了图像输入之外的任何东西。
我在下面提供的代码似乎工作正常。它可能不是最佳的,但至少它是有效的,这是一个很好的第一步。主要困难是理解 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
}
}
此 class 定义了一个名为 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
class 不需要我的模型的第一个参数 my_input
。它是使用 inputImageFeatureName
属性 指定的。最后,我通过遍历所有结果来访问 my_output
。
我希望这会对某人有所帮助。
我有一个 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] 验证输入失败。 no results:Error Domain=com.apple.vis Code=3 "The VNCoreMLTransform request failed" UserInfo={NSLocalizedDescription=VNCoreMLTransform 请求失败,NSUnderlyingError=0x280cbbab0 {Error Domain=com.apple.CoreML Code=0 "Required input feature not passed to neural network."
所以,我似乎没有将第二个参数正确传递给请求处理程序。我一直没能找到答案。
- 将这样的参数传递给 Vision 的正确方法是什么?
- 你知道我是否可以使用 Vision 直接输出图像?
谢谢你的帮助。
看看 VNCoreMLRequest
的 featureProvider
属性。这是一个提供额外输入的对象,即除了图像输入之外的任何东西。
我在下面提供的代码似乎工作正常。它可能不是最佳的,但至少它是有效的,这是一个很好的第一步。主要困难是理解 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
}
}
此 class 定义了一个名为 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
class 不需要我的模型的第一个参数 my_input
。它是使用 inputImageFeatureName
属性 指定的。最后,我通过遍历所有结果来访问 my_output
。
我希望这会对某人有所帮助。