我正在尝试在 swift 中将我的 CoreMl 模型与 Vision 框架结合使用。我的模型输出一个 MLMultiArray。当我通过 Vision 运行它时,我确实得到了一个输出,但是输出的类型是 VNObservation,我无法使用它,也无法将其转换为 MLMultiArray。有谁知道如何获取 MLMultiArray 作为输出,或将 VNObservation 转换为 MLMultiArray?谢谢!!
我的代码显示了 AVCaptureSession(相机)的函数 captureOutput,每个捕获帧(sampleBuffer)正在由模型处理。
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {return}
guard let model = try? VNCoreMLModel(for:mobilenet_v2_nail_model_update().model) else {
print("returned huh")
return}
let request = VNCoreMLRequest(model: model) {
finishReq, err in
guard let results = finishReq.results as? [VNObservation] else { return }
guard let vnObservationObject = results.first as? VNObservation else { return }
//this is where I am stuck, cannot convert result into MLMultiArray
}
do {
try VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]).perform([request])
if let mlMultiArray = self.currentMLArray {
let aWidth = CGFloat(mlMultiArray.shape[0].intValue)
let aHeight = CGFloat(mlMultiArray.shape[1].intValue)
UIGraphicsBeginImageContext(
CGSize(width: aWidth, height: aHeight))
if let ctx = UIGraphicsGetCurrentContext() {
ctx.clear(CGRect(x: 0.0, y: 0.0, width: Double(aWidth), height: Double(aHeight)));
for j in 0..<Int(aHeight) {
for i in 0..<Int(aWidth) {
let aValue = (mlMultiArray[j * Int(aHeight) + i].floatValue >= 0.5) ?
1.0 : 0.0
let aRect = CGRect(
x: CGFloat(i),
y: CGFloat(j),
width: 1.0,
height: 1.0)
let aColor: UIColor = UIColor(
displayP3Red: 0.0,
green: 0.0,
blue: 0.0,
alpha: CGFloat(aValue))
aColor.setFill()
UIRectFill(aRect)
}
}
let anImage = UIGraphicsGetImageFromCurrentImageContext()
DispatchQueue.main.async { [weak self] in
self?.imageView.image = anImage
}
} else {
print("nil")
}
}
} catch {
print("error")
}
}
这也是对象打印出来时的样子!整个 MLMultiArray 未显示,因为它太大了!
<VNCoreMLFeatureValueObservation: 0x282ecbd40> 6A57503A-5613-4C6A-BA14-5DCC7E90F7A4 VNCoreMLRequestRevision1 置信度=1.000000“var_1027”-“MultiArray:Float32 480×320 矩阵 [0.0002018213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6.401539e-05,6.759167e-05,7.200241e-05,7.200241e -05,7.140636e-05,7.140636e-05,7.086992e-05,7.086992e-05,7.033348e-05,6.973743e-05,6.657839e-05,6.711483e-05,6.920099e-05,7。 31349e -05,7.843971e-05,8.028746e-05,8.028746e-05,7.724762e-05,7.253885e-05,7.31349e-05,7.486343e-05,7.724762e-05,7.724762e-05,7.4 26739e -05,7.253885e-05,7.253885e-05,7.367134e-05,7.599592e-05,7.724762e-05,7.784367e-05,8.028746e-05,8.094311e-05.....
你几乎成功了!这个诀窍在于理解 Vision 如何处理 CoreML 模型的输出。Vision 不会直接给你
MLMultiArray
,而是将其封装在一个
VNCoreMLFeatureValueObservation
对象中。
以下是提取
MLMultiArray
的方法:
guard let results = finishReq.results as? [VNCoreMLFeatureValueObservation] else { return }
guard let observation = results.first else { return }
// 访问 featureValue 属性来获取 MLMultiArray
guard let mlMultiArray = observation.featureValue.multiArrayValue else {
print("无法获取 MLMultiArray")
return
}
// 现在你可以使用 mlMultiArray
let aWidth = CGFloat(mlMultiArray.shape[0].intValue)
let aHeight = CGFloat(mlMultiArray.shape[1].intValue)
// ...其余代码...
解释:
-
将
results
转换为[VNCoreMLFeatureValueObservation]
: 你的模型返回VNCoreMLFeatureValueObservation
对象数组,而不是VNObservation
。 - 获取第一个观察结果: 通常,你只会得到一个观察结果,除非你的模型有多个输出。
-
访问
featureValue.multiArrayValue
:VNCoreMLFeatureValueObservation
对象有一个featureValue
属性,其中包含实际输出。由于你的模型输出MLMultiArray
,你可以使用multiArrayValue
属性来访问它。
代码中其他需要注意的事项:
-
错误处理:
添加了额外的错误处理,以防无法获取
MLMultiArray
。 -
类型安全:
确保使用
guard let
语句和类型转换来安全地访问值。
进行这些更改后,你的代码应该能够从 Vision 请求中成功提取并处理
MLMultiArray
。