机器学习-CoreML基于图像处理


Vision是建立在Core ML上层的Framework。Vision专门用来处理视觉。Vison可以进行多种应用场景的机器学习处理,使用场景:

  • 人脸检测:支持检测笑脸、侧脸、局部遮挡脸部、戴眼镜和帽子等场景,可以标记出人脸的矩形区域
  • 人脸特征点:可以标记出人脸和眼睛、眉毛、鼻子、嘴、牙齿的轮廓,以及人脸的中轴线
  • 图像配准
  • 矩形检测
  • 二维码/条形码检测
  • 文字检测
  • 目标跟踪

Vision是将各种功能的Request提供给一个 RequestHandler,Handler持有图片信息,并将处理结果分发给每个Request的completion Block中。可以从 results 属性中得到 Observation 数组,然后进行更新 UI 等操作。Vision中包含的重要类:

  • VNImageRequestHandler: 处理单张图片的分析请求的类
  • VNSequenceRequestHandler: 处理连续图片的分析请求的类
  • VNDetectFaceRectanglesRequest: 图片中人脸的分析请求类
  • VNDetectFaceLandmarksRequest: 图片中人脸特征(眼睛、嘴)的分析请求类
  • VNFaceObservation: 通过图片分析请求得到的人脸信息
  • VNDetectBarcodesRequest: 查找图片中二维码的请求
  • VNBarcodeObservation: 图片请求获取的二维码的信息
  • VNCoreMLRequest: 使用 Core ML 处理图片生成的请求类
  • VNClassificationObservation: 图片分析请求获取的场景分类信息
  • VNPixelBufferObservation:Core ML图片分析请求输出的图片信息
  • VNCoreMLFeatureValueObservation: Core ML 图片分析请求获取的一系列 key-value 信息

Vision支持的图片类型包括:

  • CVPixelBufferRef
  • CGImageRef
  • CIImage
  • NSURL
  • NSData

关联关系如下:

到官网先下载一个模型,比如GoogLeNetPlaces(链接),一个识别场景的模型,创建一个Single View App工程,拖入下载好的模型 ,搭建基本的UI页面

使用两种方式分析图片场景,coreML和Vision。

Vision处理图片

1
2
3
4
5
6
func coreMLprocessImage(image:UIImage) {
let hander = VNImageRequestHandler(cgImage:image.cgImage!)
let model = try! VNCoreMLModel(for:modelFile.model)
let request = VNCoreMLRequest(model:model,completionHandler:completionHandler)
try? hander.perform([request])
}

处理结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func completionHandler(request:VNRequest,error:Error?) {
guard let results = request.results as? [VNClassificationObservation] else {
fatalError("no result")
}

// result
var bestPredication = ""
var bestConfidence:VNConfidence = 0

for classIdentifier in results {
if classIdentifier.confidence > bestConfidence {
bestPredication = classIdentifier.identifier
bestConfidence = classIdentifier.confidence
}
}
DispatchQueue.main.async {
self.resultLabel.text = "Predication:\(bestPredication) Confidence:\(lroundf(bestConfidence * 100))%"
}
}

coreML处理图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func coreMLAndVisionProcessImage(image:UIImage) {
let imageWidth:CGFloat = 224.0
let imageHeight:CGFloat = 224.0
UIGraphicsBeginImageContext(CGSize(width:imageWidth, height:imageHeight))
image.draw(in:CGRect(x:0, y:0, width:imageHeight, height:imageHeight))
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard resizedImage != nil else {
fatalError("resized Image fail")
}

// image->CVPixelBuffer
guard let pixelBuffer = imageCovertToPixelBuffer(from: resizedImage!) else {
fatalError("UIImage->CVPixelBuffer failed")
}

guard let outPut = try? modelFile.prediction(sceneImage: pixelBuffer) else {
fatalError("failed")
}

DispatchQueue.main.async {
self.resultLabel.text = "Predication:\(outPut.sceneLabel) Confidence:\(lroundf(Float(outPut.sceneLabelProbs[outPut.sceneLabel]! * 100)))%"
}
}

将UIImage转成CVPixelBuffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func imageCovertToPixelBuffer(from image: UIImage) -> CVPixelBuffer? {
let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
var pixelBuffer : CVPixelBuffer?
let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(image.size.width), Int(image.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer)
guard (status == kCVReturnSuccess) else {
return nil
}

CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!)

let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGContext(data: pixelData, width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)

context?.translateBy(x: 0, y: image.size.height)
context?.scaleBy(x: 1.0, y: -1.0)

UIGraphicsPushContext(context!)
image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
UIGraphicsPopContext()
CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))

return pixelBuffer
}

结果演示

上图可以看到,同样的场景图片,coreML和Vision预测的结果并不一样,同一场景或图片,coreML预测的结果可信度更高,Vision可能在封装coreML时做了一些其他操作,具体不得而知。但是使用coreML处理过程较Vision更为繁琐,首先需要将图片裁剪成模型需要的指定大小,而后需要将图片格式转化为模型需要的CVPixelBuffer类型。选择哪种模式需根据具体需求而定。

Demo下载


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

本站总访问量 本文总阅读量