CoreML模型传入图片触发运行时异常,求错误原因排查
问题分析与解决方案
你遇到的EXC_BAD_INSTRUCTION崩溃,核心原因非常明确:你直接把UIImage类型强制转换为CVPixelBuffer了——这两个是完全不相关的类型,强制转换as!会直接触发运行时错误,因为UIImage根本不是CVPixelBuffer的实例。
问题拆解
你的代码里cropImage返回的应该还是UIImage类型(从函数名和参数逻辑能看出来),之后你用as! CVPixelBuffer强行转换,这是完全错误的操作。CoreML模型要求的CVPixelBuffer是一种底层像素存储格式,和UIImage的封装逻辑完全不同,必须通过正确的转换流程来生成。
修复步骤
1. 实现UIImage转CVPixelBuffer的工具方法
首先需要一个可靠的转换函数,把UIImage转换成符合CoreML要求的CVPixelBuffer。你可以给UIImage写一个扩展:
extension UIImage { func convertToCVPixelBuffer() -> CVPixelBuffer? { // 这里要匹配你的CoreML模型输入的尺寸,比如假设模型要求224x224 let targetWidth = 224 let targetHeight = 224 let attributes = [ kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue ] as CFDictionary var pixelBuffer: CVPixelBuffer? let status = CVPixelBufferCreate( kCFAllocatorDefault, targetWidth, targetHeight, kCVPixelFormatType_32BGRA, // 大多数CoreML模型采用该像素格式 attributes, &pixelBuffer ) guard status == kCVReturnSuccess, let buffer = pixelBuffer else { return nil } CVPixelBufferLockBaseAddress(buffer, []) defer { CVPixelBufferUnlockBaseAddress(buffer, []) } guard let context = CGContext( data: CVPixelBufferGetBaseAddress(buffer), width: targetWidth, height: targetHeight, bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(buffer), space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue ) else { return nil } context.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: targetWidth, height: targetHeight)) return buffer } }
注意:请把
targetWidth和targetHeight改成你的CoreML模型实际要求的输入尺寸——你可以在Xcode里打开.mlmodel文件,查看输入image的规格参数。
2. 修复按钮点击的代码
接下来修改你的applePressed方法,去掉不安全的强制解包和错误的类型转换:
@IBAction func applePressed(_ sender: Any){ // 安全获取图片,避免强制解包崩溃 guard let originalImage = UIImage(named: "apple") else { print("无法加载apple图片") return } // 裁剪图片(假设cropImage返回UIImage类型) let croppedImage = cropImage(imageToCrop: originalImage) // 转换为符合要求的CVPixelBuffer guard let pixelBuffer = croppedImage.convertToCVPixelBuffer() else { print("图片转换为CVPixelBuffer失败") return } // 调用模型预测,用do-catch处理错误而非fatalError do { let fruitName = try model.prediction(image: pixelBuffer) print(fruitName.classLabel) } catch { print("预测出错:\(error.localizedDescription)") } }
额外注意事项
- 永远避免用
!强制解包可选类型,一旦值为nil就会崩溃,改用guard let或者if let处理更安全。 - 确认你的
cropImage函数返回的图片尺寸和模型要求的输入尺寸一致,如果不一致,转换后的CVPixelBuffer尺寸不匹配也会导致预测失败。 - 可以在Xcode的调试面板里查看
pixelBuffer的参数,确认它的尺寸、像素格式和模型要求完全匹配。
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

