机器学习-CoreML目标跟踪


物体跟踪需要处理连续的视频帧,所以需要VNSequenceRequestHandler类来处理多帧图像,之前识别单张图片使用的是VNImageRequestHandler类。跟踪多物体时,可以使用VNDetectedObjectObservation.uuid区分跟踪对象,并做相应处理。这里粗略演示一下追踪单个物体。

  1. 前期UI准备

2 捕获对象,设置精准追踪

3.效果演示



Demo下载


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

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

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

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

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

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

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

机器学习-CoreML人脸识别


使用Vision框架进行人脸识别,不仅可以识别出人脸的面部轮廓,还可以识别出人脸的特征点,比如眼睛、鼻子、嘴巴等。进行人脸请求的类是VNDetectFaceRectanglesRequest,人脸特征请求的类是VNDetectFaceRectanglesRequest,请求结果的信息类是VNFaceObservation。下面直接上代码。

  1. 搭建基本UI

  1. 识别面部轮廓
1
2
3
4
5
6
func processImage(image:UIImage) {
self.resultLabel.text = "processing..."
let handler = VNImageRequestHandler.init(cgImage: image.cgImage!)
let request = VNDetectFaceRectanglesRequest.init(completionHandler: handleFaceDetect)
try? handler.perform([request])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func handleFaceDetect(request:VNRequest,error:Error?) {
guard let obversations = request.results as? [VNFaceObservation] else {
fatalError("no face")
}
self.resultLabel.text = "\(obversations.count)face"

for subView in self.btnImageView.subviews where subView.tag == 100 {
subView.removeFromSuperview()
}

for faceObversion in obversations {
self.showFaceContour(faceObversion: faceObversion, toView: self.btnImageView)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func showFaceContour(faceObversion face : VNFaceObservation, toView view : UIView) {
let boundingBox = face.boundingBox
let imageBoundingBox = view.bounds

let w = boundingBox.size.width * imageBoundingBox.width
let h = boundingBox.size.height * imageBoundingBox.height

let x = boundingBox.origin.x * imageBoundingBox.width
let y = imageBoundingBox.height - boundingBox.origin.y * imageBoundingBox.height - h

let subview = UIView(frame: CGRect(x: x, y: y, width: w, height: h))
subview.layer.borderColor = UIColor.green.cgColor
subview.layer.borderWidth = 1
subview.layer.cornerRadius = 1
subview.tag = 100
view.addSubview(subview)
}

  • 相当于在人脸上画了一个轮廓视图添加上去。boundingBox是CGRect类型,但是boundingBox返回的是x,y,w,h的比例(value:0~1),需要进行转换。原始坐标系的原点是左上角,而这里是左下角,并且y轴的方向和原始坐标系相反。

3.面部轮廓展示

4.识别面部特征

1
2
3
4
5
6
func processImage(image:UIImage) {
self.resultLabel.text = "processing..."
let handler = VNImageRequestHandler.init(cgImage: image.cgImage!)
let request = VNDetectFaceLandmarksRequest.init(completionHandler: handleFaceDetect)
try? handler.perform([request])
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func handleFaceDetect(request:VNRequest,error:Error?) {
guard let obversations = request.results as? [VNFaceObservation] else {
fatalError("no face")
}
self.resultLabel.text = "\(obversations.count) face"

var landmarkRegions : [VNFaceLandmarkRegion2D] = []

for faceObversion in obversations {
landmarkRegions += self.showFaceFeature(faceObversion: faceObversion, toView: self.btnImageView)
resultImage = self.drawOnImage(source: self.resultImage,
boundingRect: faceObversion.boundingBox,
faceLandmarkRegions: landmarkRegions)
}
self.btnImageView.setBackgroundImage(resultImage, for: .normal)
}

获取特征点

1
2
3
4
5
6
7
8
9
10
11
func showFaceFeature(faceObversion face: VNFaceObservation, toView view: UIView) ->[VNFaceLandmarkRegion2D] {
guard let landmarks = face.landmarks else { return [] }
var landmarkRegions: [VNFaceLandmarkRegion2D] = []
if let rightEye = landmarks.rightEye {
landmarkRegions.append(rightEye)
}
if let nose = landmarks.nose {
landmarkRegions.append(nose)
}
return landmarkRegions
}

重新绘制图片(含面部特征)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
func drawOnImage(source: UIImage,
boundingRect: CGRect,
faceLandmarkRegions: [VNFaceLandmarkRegion2D]) -> UIImage {
UIGraphicsBeginImageContextWithOptions(source.size, false, 1)
let context = UIGraphicsGetCurrentContext()!
context.translateBy(x: 0, y: source.size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(CGBlendMode.colorBurn)
context.setLineJoin(.round)
context.setLineCap(.round)
context.setShouldAntialias(true)
context.setAllowsAntialiasing(true)
context.setLineWidth(5.0)
context.setStrokeColor(UIColor.black.cgColor)

// origin image
let rect = CGRect(x: 0, y:0, width: source.size.width, height: source.size.height)
context.draw(source.cgImage!, in: rect)

// face contour
let rectWidth = source.size.width * boundingRect.size.width
let rectHeight = source.size.height * boundingRect.size.height
context.addRect(CGRect(x: boundingRect.origin.x * source.size.width, y:boundingRect.origin.y * source.size.height, width: rectWidth, height: rectHeight))
context.drawPath(using: CGPathDrawingMode.stroke)

// draw face feature
context.setStrokeColor(UIColor.red.cgColor)
for faceLandmarkRegion in faceLandmarkRegions {
var points: [CGPoint] = []
for i in 0..<faceLandmarkRegion.pointCount {
let point = faceLandmarkRegion.normalizedPoints[i]
let p = CGPoint(x: CGFloat(point.x), y: CGFloat(point.y))
points.append(p)
}
let mappedPoints = points.map { CGPoint(x: boundingRect.origin.x * source.size.width + $0.x * rectWidth, y: boundingRect.origin.y * source.size.height + $0.y * rectHeight) }
context.addLines(between: mappedPoints)
context.drawPath(using: CGPathDrawingMode.stroke)
}

let coloredImg : UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return coloredImg
}

VNDetectFaceLandmarksRequest请求返回的也是VNFaceObservation,但是这个时候VNFaceObservation 对象的landmarks属性就会有值,这个属性里面存储了人物面部特征的点
如:

  • faceContour:脸部轮廓
  • leftEye、rightEye: 左眼、右眼
  • nose: 鼻子
  • noseCrest: 鼻嵴
  • outerLips、innerLips: 外唇、内唇
  • leftEyebrow、rightEyebrow: 左眉毛、右眉毛
  • leftPupil、rightPupil: 左瞳、右瞳

5.面部特征点展示



Demo下载


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

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

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

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

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

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

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

机器学习-CoreML文字识别


  1. 获取带有文字的图片
    1
    2
    3
    4
    5
    6
    func btnPressed(_ sender: Any) {
    let picker = UIImagePickerController()
    picker.delegate = self
    picker.sourceType = .savedPhotosAlbum
    present(picker, animated: true, completion: nil)
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 // UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = (info[UIImagePickerControllerOriginalImage] as? UIImage) else {
fatalError("no image")
}
self.btnImageView.setBackgroundImage(image, for: .normal)
// self.btnImageView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
// if self.btnImageView.layer.sublayers != nil {
// for layer in self.btnImageView.layer.sublayers! {
// layer.removeFromSuperlayer()
// }
// }

var textLayers:[CAShapeLayer] = []
if let cgImage = image.cgImage {
let textRecognizedRequest = VNDetectTextRectanglesRequest.init(completionHandler: { (request:VNRequest, error:Error?) in

if (request.results as? [VNTextObservation]) != nil {
textLayers = self.addShapesToText(obversations: request.results as! [VNTextObservation], view: self.btnImageView)
for layer in textLayers {
self.btnImageView.layer.addSublayer(layer)
}
}
})

let handler = VNImageRequestHandler.init(cgImage: cgImage, options: [:])
guard let _ = try? handler.perform([textRecognizedRequest]) else {
fatalError("failed")
}
}
}

2.添加Layer展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func addShapesToText(obversations:[VNTextObservation],view:UIView) -> [CAShapeLayer] {
let layers: [CAShapeLayer] = obversations.map { observation in

let w = observation.boundingBox.size.width * view.bounds.width
let h = observation.boundingBox.size.height * view.bounds.height
let x = observation.boundingBox.origin.x * view.bounds.width
let y = view.bounds.height - observation.boundingBox.origin.y * view.bounds.height - h

let layer = CAShapeLayer()
layer.frame = CGRect(x: x , y: y, width: w, height: h)
layer.borderColor = UIColor.green.cgColor
layer.borderWidth = 2
layer.cornerRadius = 3

return layer
}

return layers
}

3.效果展示



Demo下载


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

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

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

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

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

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

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

机器学习-CoreML结合Siri


使用AVFoundation拍摄照片,再使用Core ML处理分析照片,最后通过Siri告知拍摄的对象是什么。
  1. 前期配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    var captureView : UIView!
    var synthe = AVSpeechSynthesizer()
    var uttrence = AVSpeechUtterance()
    var predicte = ""

    var captureSession : AVCaptureSession!
    var cameraOutput : AVCapturePhotoOutput!
    var previewLayer : AVCaptureVideoPreviewLayer!

    override func viewDidLoad() {
    super.viewDidLoad()

    captureView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: 200, height: 200))
    self.view.addSubview(captureView)
    setupCamera()
    }

    func setupCamera() {
    captureSession = AVCaptureSession()
    captureSession.sessionPreset = AVCaptureSession.Preset.photo
    cameraOutput = AVCapturePhotoOutput()

    let device = AVCaptureDevice.default(for: .video)
    if let input = try? AVCaptureDeviceInput.init(device: device!) {
    if(captureSession.canAddInput(input)) {
    captureSession.addInput(input)

    if(captureSession.canAddOutput(cameraOutput)) {
    captureSession.addOutput(cameraOutput)
    }

    previewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession)
    previewLayer.videoGravity = .resizeAspectFill
    previewLayer.frame = CGRect.init(x: 0, y: 0, width: 200, height: 200)
    captureView.layer.addSublayer(previewLayer)
    captureSession.startRunning()
    }
    }
    }
  2. 获取照片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    func launchUI() {
    let setting = AVCapturePhotoSettings()
    // xcode9's Bug
    let previewPixelType = setting.__availablePreviewPhotoPixelFormatTypes.first!
    let previewFormat = [ kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
    kCVPixelBufferWidthKey as String: "\(captureView.bounds.size.width)",
    kCVPixelBufferHeightKey as String: "\(captureView.bounds.size.height)"] as [String : Any]
    setting.previewPhotoFormat = previewFormat
    cameraOutput.capturePhoto(with: setting, delegate: self)
    }

    // AVCapturePhotoCaptureDelegate
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    if error != nil {
    print("error occured: \(error!.localizedDescription)")
    }

    if let imageData = photo.fileDataRepresentation(),let image = UIImage.init(data: imageData) {
    // Predict
    self.predict(image: image)
    }
    }

在Xcode9上availablePreviewPhotoPixelFormatTypes这个属性前面需要加上双下划线,更高版本则不需要

3.图片处理预测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 func predict(image:UIImage) {
// if let data = UIImagePNGRepresentation(image) {
// let fileName = getDocumentsDirectory().appendingPathComponent("captureImage")
// print("fleName:\(fileName)")
// try? data.write(to: fileName)
// }
let model = try! VNCoreMLModel.init(for: VGG16().model)
let request = VNCoreMLRequest.init(model: model, completionHandler: { (request:VNRequest, error:Error?) in
weak var weakSelf = self
guard let results = request.results as? [VNClassificationObservation] else {
fatalError("no result")
}
var bestPrediction = ""
var bestConfidence:VNConfidence = 0

for classfication:VNClassificationObservation in results {
if classfication.confidence > bestConfidence {
bestConfidence = classfication.confidence
bestPrediction = classfication.identifier
}
}

weakSelf!.say(string: "\(bestPrediction)")

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5, execute: {
weakSelf!.launchUI()
})
})
let handler = VNImageRequestHandler.init(cgImage: image.cgImage!)
try? handler.perform([request])
}

4.语音播报

1
2
3
4
5
6
7
8
func say(string: String) {
uttrence = AVSpeechUtterance.init(string: string)
uttrence.rate = 0.3
uttrence.voice = AVSpeechSynthesisVoice.init(language: "zh_CN")
uttrence.pitchMultiplier = 0.8
uttrence.postUtteranceDelay = 0.2
synthe.speak(uttrence)
}

这里面选择的是汉语,不管选择的是什么语音种类,英语都是支持的

5.效果演示

Demo下载


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

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

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

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

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

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

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

机器学习-CoreML入门 结合ARKit


ARKit:

iOS11引入的全新的框架,允许开发者轻松地为 iPhone 和 iPad 创建无与伦比的增强现实体验。通过将虚拟对象和虚拟信息同用户周围的环境相互融合,ARKit 使得应 用跳出屏幕的限制,让它们能够以全新的方式与现实世界进行交互。

  • 所谓的增强现实 (Augmented Reality, AR),指的是向设备摄像头产生的实时动态视图中,添加 2D 或者 3D 元素,然后用某种方法让这些元素看起来就处于现实世界当中,所产生的一种用户体验。ARKit 提供设备动作追踪、相机场景捕获和高级场景处理,并让AR元素的展示变得极为便利,从而大大简化了建立 AR用户体验的工作难度。

  • ARSession类:
    这是一个单例, 是ARKit的核心类,用于控制设备摄像头,处理传感器数据,对捕获的图像进行分析等

  • ARSessionConfiguration类:
    跟踪设备 向的 个基本配置, 在运行时,需要指定AR运行的配置

  • ARWorldTrackingSessionConfiguration类:
    配置跟踪设备的方向和位置,以及检测设备摄像头所看到的现实世界的表面

  • ARSCNView类:
    用来增强相机通过 3D SceneKit 所捕捉到的内容并展示 AR 效果的一个 view

  • ARSKView类:
    用来增强相机通过 2D SpriteKit 所捕捉到的内容并展示AR 效果的一个 view

  • ARAnchor类:
    真实世界的位置和方向,用于在一个AR场景中放置一个物体

  • ARPlaneAnchor类:
    在一个AR Session会话中检测一个真实世界中平面的位置和方向的相关信息

  • ARHitTestResult类:
    在一个AR Session会话中通过检测相机视图中的一个点来获取真实世界中表面的相关信息

  • ARFrame类:
    捕获一个视频图像和位置追踪信息作为一个AR会话的一部分

  • ARCamera类:
    在一个AR会话中摄像机的位置和成像特征信息为捕获视频帧

  • ARLightEstimate类
    在一个AR会话中估计场景照明信息关联到一个捕获的视频帧

coreML

iOS11引入的一个全新的机器学习框架,同时伴随着Vision框架。Core ML 是特定框架功能的基础,支持用于用户图像分析的 Vision,用于自然语言处理的 Foundation (如 NSLinguisticTagger 类)和用于评估已经学习到的决策树 GamePlayKit。Core ML 本身构建于低层面的原语上,比如 Accelerate、BNNS、Metal Performance Shaders。coreML让我们更容易在App中使用训练过的模型, 而Vision让我们轻松访问苹果的模型,用于面部检测、面部特征点、文字、矩形、条形码和物体等。Vision模型中可以包装任意的图像分析coreML模型。Vision框架其实就是对coreML框架的一层封装,使用起来更加方便。根据官方文档提供的图像可以看出,这两个框架的作用,就是将一个ML模型,转换成我们的app工程可以直接使用的对象。

  • 机器学习(ML:Machine Learning):
    是一种人工智能,计算机会“学习”而不是被明确编程。不用编写算法,机器学习工具通过在大量数据中寻找模式,使计算机能够开发和优化算法。机器学习(ML)是人工智能(AI)的一个分支,深度学习(DL)又是更小分一个分支,大概关系如图所示

Demo:

  1. 建立一个工程,选择Augmented Reality App, 会帮我们创建一个ARSCNView视图

2.到官网下载一个模型 模型下载, 每个模型的作用都有对应的解释,能识别的图像种类也不尽相同,根据不同需求下载不同模型

3.将模型拖入工程中,可能需要加载一会才会显示,如下图所示。选中模型,会出现模型相关信息,大小、功能、类型等。Model Class下会有一个箭头,点击进入会看到模型的源码。Model Evaluation Parameter下会有模型的输入(input)输出(outPuts)信息。输入的需要时大小为224*224的图片,而返回的结果一个是classLabelProbs,即信任度或百分比,而classLabel即得到的结果。不同模型的输输出并不相同。注意右下角的Target Members在Xcode9中默认不会勾选,需要手动选中。

4.创建模型并声明相关变量

1
2
3
4
5
var resentModel = Resnet50()

var hitTestResult: ARHitTestResult!

var visionRequests = [VNRequest]()

5.给当前场景添加一个手势

1
2
3
4
func registerGestureRecognizers() {
let tapGesture = UITapGestureRecognizer(target:self, action:#selector(tapped))
sceneView.addGestureRecognizer(tapGesture)
}

6.点击场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@objc func tapped(tapGesture:UITapGestureRecognizer) {
let sceneView = tapGesture.view as! ARSCNView
let touchLocation = tapGesture.location(in: self.sceneView)
guard let currentFrame = sceneView.session.currentFrame else {
fatalError("no pixel")
}

let hitTestResults = sceneView.hitTest(touchLocation, types: .featurePoint)
if hitTestResults.isEmpty { return }
guard let hitTestResult = hitTestResults.first else {
fatalError("not first object")
}

self.hitTestResult = hitTestResult;
// image->pixel
let pixelBuffer = currentFrame.capturedImage;

// Vision
performVisonRequest(pixelBuffer: pixelBuffer)
}

7.通过Vision处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func performVisonRequest(pixelBuffer:CVPixelBuffer) {
let visionModel = try! VNCoreMLModel(for:self.resentModel.model)
let request:VNCoreMLRequest = VNCoreMLRequest(model:visionModel) { request,error in
if error != nil { return }
guard let observations = request.results else {
fatalError("no result")
}

let observation = observations.first as! VNClassificationObservation
print("name is \(observation.identifier) \n confidence is \(observation.confidence)")

DispatchQueue.main.async {
self.displayPredictions(text: observation.identifier)
}
}
request.imageCropAndScaleOption = .centerCrop;
visionRequests = [request]
let imageRequestHandler:VNImageRequestHandler = VNImageRequestHandler(cvPixelBuffer:pixelBuffer,orientation:.upMirrored,options:[:])

DispatchQueue.global().async {
try? imageRequestHandler.perform(self.visionRequests)
}
}

8.展示预测结果

func displayPredictions(text:String) {
let parentNode = SCNNode()

    // 1cm
    let sphere = SCNSphere(radius:0.01)
    let sphereMaterial = SCNMaterial()
    sphereMaterial.diffuse.contents = UIColor.orange
    sphere.firstMaterial = sphereMaterial

    let sphereNode = SCNNode(geometry:sphere)
    parentNode.addChildNode(sphereNode)

    // text
    let textGeo = SCNText(string:text,extrusionDepth:0)
    textGeo.alignmentMode = kCAAlignmentCenter
    textGeo.firstMaterial?.diffuse.contents = UIColor.orange
    textGeo.firstMaterial?.specular.contents = UIColor.white
    textGeo.firstMaterial?.isDoubleSided = true
    textGeo.font = UIFont(name:"Futura",size:0.20)

    let textNode = SCNNode(geometry:textGeo)
    textNode.position = SCNVector3(x:self.hitTestResult.worldTransform.columns.3.x,
                                   y:self.hitTestResult.worldTransform.columns.3.y,
                                   z:self.hitTestResult.worldTransform.columns.3.z)
    textNode.scale = SCNVector3Make(0.2,0.2,0.2)
    parentNode.addChildNode(textNode)

    parentNode.position = SCNVector3(x:self.hitTestResult.worldTransform.columns.3.x,
                                     y:self.hitTestResult.worldTransform.columns.3.y,
                                     z:self.hitTestResult.worldTransform.columns.3.z)
    // show AR resutl
    self.sceneView.scene.rootNode.addChildNode(parentNode)
}

9.结果展示

运行项目,将真机对准物体,距离适中。注意苹果AR仅支持搭载A9/A10及更先进处理器的iOS 11设备,接下来新出的苹果设备,也同样会支持苹果AR功能。目前支持机型如下:

  • iPhone6s和6S Plus
  • iPhone7和7 Plu
  • iPhone SE
  • iPad Pro (9.7, 10.5和12.9)
  • iPad (2017

最终展示效果如下,结果其实可能并不准确,但是提供了一个可能性。展示结果也可以呈现多样性,比如显示百分比,显示可信度排名前几的分析对象等


Demo下载

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

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

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

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

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

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

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

机器学习-将第三方模型转换成Core ML或自己训练模型


苹果官方提供的model功能有限,我们可以自己训练模型或者将第三方模型转化成苹果可以识别的模型。

将第三方模型转化成苹果可以识别的模型

这里以苹果给出的参考为例,也可以下载Caffee model

其中.txt文件是所有预测结果,.prototxt是模型结构文件。

打开Anaconda的spyder, 使用coremltools转换

1
2
3
4
5
6
7
8
9
coreml_model = coremltools.converters.caffe.convert(('./caffee model/bvlc_alexnet.caffemodel', 
'./caffee model/deploy.prototxt'),
predicted_feature_name='./caffee model/class_labels.txt')

coreml_model.author = "Fish News"
coreml_model.license = "BSD"
coreml_model.short_description = "this is a test description"

coreml_model.save('BVLCObjectClassifier.mlmodel')

上图的model的author、short_description、输入输出等属性可自行设置。

转换成功后会得到一个mlmodel文件,拖入工程后即可使用

自己训练模型

我们使用sklearn库内置的iris数据,或者使用自己提供的csv格式的数据进行训练

1
2
3
4
5
6
7
8
9
10
11
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
import coremltools

iris = datasets.load_iris()
model = LogisticRegression()
model.fit(iris.data,iris.target)
print iris.target_names[model.predict([ [1.0 ,2.0, 2.0, 3.0] ])]
print iris.data.shape
coreml_model = coremltools.converters.sklearn.convert(model,iris.feature_names, 'iris class')
coreml_model.save('iris.mlmodel')

训练好后会生成iris.mlmodel模型,拖入工程进行测试

测试已训练好的模型

  • 搭建UI,iris.mlmodel需要四个参数,分别是speal length,speal width,petal length,petal width

  • 结果展示

Demo下载


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

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

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

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

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

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

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

机器学习-将第三方模型转换成Core ML或自己训练模型环境配置


机器学习中使用到的模型,除了使用苹果官方提供到的一些模型以外,还可以将第三方训练好的模型转成coreML model,甚至可以自己训练模型。苹果官方给出了一些支持第三方模型的工具和版本

配置环境

1.安装Anaconda

选择2.7版本,然后一路安装,Anconda是一个python的IDE,安装成功后打开终端更新Python版本,现在Mac内置的Python版本是2.7,而苹果要求的版本至少是是2.7.13

1
conda install python=2.7.13

安装成功后查看Python版本

2.安装pip

pip是Python种安装和管理包的工具,是easy_install的替代品

1
easy_install pip

3.安装coremlTools

1
pip install -U coremltools

判断是否安装成功,可通过导入模块是否成功来判断

4.安装keras、tensorflow、scikit-learn

1
2
3
pip install keras==1.2.2
pip install tensorflow
pip install -U scikit-learn

判断是否安装成功依然可用上述方法

或者,打开Anconda, 选择3.1.4版本的Spyder

运行,如果没报错说明引入成功

5.安装caffe依赖包

1
2
3
4
5
6
7
8
9
brew install -vd snappy leveldb giflags glog szip lmdb

for x in snappy leveldb gflags glog szip hdf5 lmdb homebrew/science/opencv; do brew uninstall $x; brew install --fresh -vd $x
done
brew uninstall --force protobuf; brew install --with-python --fresh -vd protobuf brew uninstall boost boost-python; brew install --fresh -vd boost boost-python

brew tap homebrew/science

brew install hdf5 opencv

6.修改opencv

1
brew edit opencv

找到下图标注的两行

替换成:

1
DPYTHON_LIBRARY=#{py_prefi x}/lib/libpython2.7.dylib
DPYTHON_INCLUDE_DIR=#{py _prefix}/include/python2.7

替换后的效果是:

7.加入依赖包

1
brew install --build-from-source --with-python -vd protobuf
brew install --build-from-source -vd boost boost-python

8.检查是否有缺失

1
2
brew doctor
brew missing

上述安装过程中可能并非一帆风顺,如有错误应按照提示修改。苹果对版本要求较为严格,安装时注意版本控制。


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

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

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

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

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

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

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

机器学习-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周报,欢迎关注或订阅

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

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

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

十月

选择在周日下午午睡实在不是明智的选择,记不清多少次一觉醒来都临近晚上了。仿佛穿越时空,片刻间不知道自己在哪、什么时间,拉上的窗帘依然能透过夕阳的影子,恍惚间会觉得有点低落。往常可能会在这个时候给久未联系的朋友打个电话,也不知道何时这个习惯莫名终止了。

忙碌的生活可能并不容易,但是颓废的生活果然是这么轻松惬意,身为并不愿意承认重度拖延症患者的我,想做点什么并不容易,这种感觉很糟糕。今年几个熟悉的人从公司离职,感觉是更糟糕。想想也是有趣,大概每天至少会有三分之一的时间是在职场度过,然而一旦离职这种体系基本会随之崩塌,仿佛从未认识过一样,然后变成社交软件上的一个ID,然后变成不远的将来后偶尔想起的曾经。越来越不喜欢建立这种随时会被打破的社交关系,费时费力,仅点头之交的关系,不要也罢。

四年前的这个时候初到上海,离开了我非常喜欢的泉州厦门,四年过去了,不仔细回想,都不知道这几年是怎么过的。以前希望一天变成12小时,而现在却希望一天是48小时。变得和以前难以置信的不一样,我经常会怀念过去无形装逼放浪不羁的我。朋友圈慢慢屏蔽了几十个人,今天突然之间想全部都解除屏蔽了,想想也挺有趣,没有这些人的每天鸡汤、软文、自拍,那朋友圈还有什么意思,如果生活不用来装逼,那还有什么意义?

都是需要诗和远方的人,当然可能需要的还有money。从沉迷于空虚之中,彷徨于温饱之际,到房产两三套,资产过千万的城市小资产阶级,他们理解这个世界在发生什么,然而却并不关心身边的人,他们自私而苦闷,幸福而纠结,安然而焦虑,在单位有一官半职,在社会上有一定地位,这是被时间和岁月吞噬的一类人,尚未发光却即将熄灭,尚未年轻却迅速老去,而我们,却都在希望变成这一类人!

很难不忧伤,尽管忧伤,是生活的一部分!


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

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

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

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

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

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

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

Xcode免证书免数据线调试

一. 免证书

Xcode7之后,开发者调试终于可以不需要证书了,之前越狱后免除证书不算在内

  • 步骤如上图所示
  • 注意,Bundle Inentifier最好使用之前没用过的,否则可能不成功
  • 上图步骤之后,钥匙串中已经自动生成了一个供本机使用的调试证书
  • 如果App ID已经是开发者账号或者属于某个已付费的账号组里,会给该账号自动生成一个证书,可登陆苹果开发者中心查看。勾选Automatically manage signing后会自动生成Provisioning Prifile描述文件,当然可能会生成失败,会提示更换Bundle Identifier。如果该账号不是开发者账号,则仅会在本机生成一个可供调试的证书
  • 如果有多个工程需要调试,调试时可修改Bundle Identifier为同一个值,否则可能会对频繁更改Bundle Identifier的App Id进行限制。
  • 运行后依然会报错,会提示需要打开手机设置->通用->描述文件与设备管理中添加信任
二.免数据线

Xcode9之后,终于可以免数据线调试了。这里说的免数据线并非完全脱离数据线,而是第一次使用数据线启动之后才可以脱离使用

  • 步骤如上图所示,注意勾选Connect via network,即通过网络连接
  • 注意,手机系统要求iOS11及以上
  • 第一次启动需要连接数据线,并且手机和电脑需处于同一无线网环境下。第一次启动后,拔出数据线,这时候会发现设备依然连接着,选中运行即可
  • 可以同时支持多台设备

以上,即可实现免证书免数据线,平时方便自己调试,还随时可以给测试人员安装开发包临时测试


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

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

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

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

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

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

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

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