Swift使用CoreML结合DeepLabV3移除图片背景部分场景失效咨询
问题描述
我目前使用CoreML搭配DeepLabV3模型实现图片背景移除功能,所用模型来自苹果官方机器学习模型库。
该方案对主体为人、狗、汽车类的照片背景移除效果良好,但在处理天际线、桌面摆放物件等其他场景时,模型无法正确区分检测目标与背景,效果对比如下:
- 效果正常示例:

- 效果异常示例:

现有实现代码如下:
var imageSegmentationModel = DeepLabV3() var request : VNCoreMLRequest? func setUpModel() { if let visionModel = try? VNCoreMLModel(for: imageSegmentationModel.model) { request = VNCoreMLRequest(model: visionModel, completionHandler: visionRequestDidComplete) request?.imageCropAndScaleOption = .scaleFill } else { fatalError() } } func predict() { DispatchQueue.global(qos: .userInitiated).async { guard let request = self.request else { fatalError() } let handler = VNImageRequestHandler(cgImage: (self.originalImage?.cgImage)!, options: [:]) do { try handler.perform([request]) }catch { print(error) } } } func visionRequestDidComplete(request: VNRequest, error: Error?) { DispatchQueue.main.async { if let observations = request.results as? [VNCoreMLFeatureValueObservation], let segmentationmap = observations.first?.featureValue.multiArrayValue { self.maskImage = segmentationmap.image(min: 0, max: 255) print(self.maskImage!.size) self.maskImage = self.maskImage?.resizedImage(for: self.originalImage!.size) if let image:UIImage = self.maskOriginalImage(){ print("Success") self.outputImageView.image = image } } } } func maskOriginalImage() -> UIImage? { if(self.maskImage != nil && self.originalImage != nil){ let maskReference = self.maskImage?.cgImage! let imageMask = CGImage(maskWidth: maskReference!.width, height: maskReference!.height, bitsPerComponent: maskReference!.bitsPerComponent, bitsPerPixel: maskReference!.bitsPerPixel, bytesPerRow: maskReference!.bytesPerRow, provider: maskReference!.dataProvider!, decode: nil, shouldInterpolate: true) let maskedReference = self.originalImage?.cgImage!.masking(imageMask!) return UIImage(cgImage: maskedReference!) } return nil }
解答
识别不准的核心原因和你的代码逻辑无关,问题出在模型本身:苹果提供的这个DeepLabV3是在Pascal VOC数据集上训练的,只支持分割20类固定物体,刚好覆盖你测试效果好的人、狗、汽车这类常见目标,完全没收录桌面小摆件、自然天际线地貌这类类别,自然没法正确区分前景和背景。
你可以按优先级尝试以下调整:
零成本先调现有参数
你现在写的request?.imageCropAndScaleOption = .scaleFill会强制拉伸图片适配模型的输入尺寸,导致物体比例变形、小目标边缘错位,直接拉低分割准确率。先把这个参数改成.scaleFit,图片会按原比例缩放后补黑边适配模型,分割完成后再把mask对应原图的有效区域裁出来,就能修复一部分比例变形导致的分割错误,改完先测下目标场景的效果。
替换适配通用场景的模型
如果调完参数效果还是不达标,不用换CoreML+Vision的技术栈,只换模型文件就行:
- 别再用通用语义分割的DeepLabV3了,优先选专门做抠图的Matting类模型,比如RVM、MODNet、PP-Matting,这类模型不限制前景类别,只要是视觉上的突出主体都能分出精细边缘,对桌面物件、风景场景的适配性比DeepLabV3好很多。这些模型都有现成的CoreML格式开源版本,替换后你现有的请求调度、mask生成、图片合成逻辑基本不用改,只需要根据新模型输出的数组维度、数值范围,调整生成mask时的min、max参数即可。
- 如果还是想用语义分割方案,可以换在COCO数据集上训练的分割模型,COCO覆盖80+常见物体类别,比Pascal VOC的覆盖范围广很多,对日常小物件的识别率会有明显提升,但泛化能力还是不如专门的抠图模型。
内容的提问来源于stack exchange,提问作者Tom Coomer
相关产品推荐
相关产品推荐

