機械学習をCore MLを使うとiOSアプリで試すことができます。人工知能、AIや機械学習のそれ自体は難しいのですが、アプリに簡単に展開できるようにAppleも考えているのでしょう
Xcode 11.4
Core ML
Appleの解説にありますがCore MLは学習させたモデルをアプリで使えるようにするフレームワークで、あくまで学習モデルを利用するだけです。(学習をさせるものとしてはCreate MLがあります)
学習モデルはAppleのページに載っているものをそのまま使えます。また他のTensorflow等からCore MLに使えるように変換するとか、Create MLで学習させたモデルを使うことができます。
以前にUIImagePickerControllerを使ったカメラアプリを簡単に作ってみましたが、これにCore MLを使えるように設定していきます。
Core ML Model
学習モデルは以下のページにあります。
Core ML Models – Apple Developer
この中の「Resnet50」を使ってみます。この他のモデルもありますが、それぞれ学習方法が異なります。試しに使ってみるのも良いかと思います。
Core ML の実装
取得した学習モデル Resnet50.mlmodel をプロジェクト内にAddしておきます。
実装手順としては以下のようになります。
学習モデルのからVNCoreMLModelのインスタンスを生成します。
1 |
let model = try? VNCoreMLModel(for: Resnet50().model) |
このインスタンスから画像をクラス分けした結果を取得するリクエストを出します。
1 |
let request = VNCoreMLRequest(model: model) |
ハンドラを実行して予測結果を取得する
1 |
let handler = VNImageRequestHandler( ciImage: ciImage, orientation: orientation) |
このようになります。
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
import Vision import CoreML ... // カメラで撮影した後の画像を予測に送る photoPredict(pickedImage) ... func photoPredict(_ targetPhoto: UIImage){ // 学習モデルのインスタンス生成 guard let model = try? VNCoreMLModel(for: Resnet50().model) else{ print("error model") return } // リクエスト let request = VNCoreMLRequest(model: model){ request, error in guard let results = request.results as? [VNClassificationObservation] else { return } // 確率を整数にする let conf = Int(results[0].confidence * 100) // 候補の1番目 let name = results[0].identifier if conf >= 50{ self.label.text = "\(name) です。確率は\(conf)% \n" } else{ self.label.text = "もしかしたら、\(name) かも。確率は\(conf)% \n" } } // 画像のリサイズ request.imageCropAndScaleOption = .centerCrop // CIImageに変換 guard let ciImage = CIImage(image: targetPhoto) else { return } // 画像の向き let orientation = CGImagePropertyOrientation( rawValue: UInt32(targetPhoto.imageOrientation.rawValue))! // ハンドラを実行 let handler = VNImageRequestHandler( ciImage: ciImage, orientation: orientation) do{ try handler.perform([request]) }catch { print("error handler") } } |
サンプルコード
カメラで写真を撮ってその画像を予測させる簡単なアプリです。
Resnet50.mlmodel をAdd File to “xxx…”でプロジェクト内に追加します。
ViewController.swft
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
import UIKit import CoreML import Vision class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{ @IBOutlet var cameraView : UIImageView! @IBOutlet var label : UILabel! override func viewDidLoad() { super.viewDidLoad() } // カメラの撮影開始 @IBAction func startCamera(_ sender : Any) { let sourceType:UIImagePickerController.SourceType = UIImagePickerController.SourceType.camera // カメラが利用可能かチェック if UIImagePickerController.isSourceTypeAvailable( UIImagePickerController.SourceType.camera){ // インスタンスの作成 let cameraPicker = UIImagePickerController() cameraPicker.sourceType = sourceType cameraPicker.delegate = self self.present(cameraPicker, animated: true, completion: nil) } else{ label.text = "error" } } // 撮影が完了時した時に呼ばれる func imagePickerController(_ imagePicker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){ // dismiss imagePicker.dismiss(animated: true, completion: nil) if let pickedImage = info[.originalImage] as? UIImage { cameraView.contentMode = .scaleAspectFit cameraView.image = pickedImage photoPredict(pickedImage) } } func photoPredict(_ targetPhoto: UIImage){ // 学習モデルのインスタンス生成 guard let model = try? VNCoreMLModel(for: Resnet50().model) else{ print("error model") return } // リクエスト let request = VNCoreMLRequest(model: model){ request, error in guard let results = request.results as? [VNClassificationObservation] else { return } // 確率を整数にする let conf = Int(results[0].confidence * 100) // 候補の1番目 let name = results[0].identifier if conf >= 50{ self.label.text = "\(name) です。確率は\(conf)% \n" } else{ self.label.text = "もしかしたら、\(name) かも。確率は\(conf)% \n" } } // 画像のリサイズ request.imageCropAndScaleOption = .centerCrop // CIImageに変換 guard let ciImage = CIImage(image: targetPhoto) else { return } // 画像の向き let orientation = CGImagePropertyOrientation( rawValue: UInt32(targetPhoto.imageOrientation.rawValue))! // ハンドラを実行 let handler = VNImageRequestHandler( ciImage: ciImage, orientation: orientation) do{ try handler.perform([request]) }catch { print("error handler") } } // 撮影がキャンセルされた時に呼ばれる func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true, completion: nil) } // 写真を保存 @IBAction func savePicture(_ sender : Any) { let image:UIImage! = cameraView.image if image != nil { UIImageWriteToSavedPhotosAlbum( image, self, #selector(ViewController.image(_:didFinishSavingWithError:contextInfo:)), nil) } else{ print("image Failed !") } } // 書き込み完了結果の受け取り @objc func image(_ image: UIImage, didFinishSavingWithError error: NSError!, contextInfo: UnsafeMutableRawPointer) { if error != nil { print(error.code) } else{ } } // アルバムを表示 @IBAction func showAlbum(_ sender : Any) { let sourceType:UIImagePickerController.SourceType = UIImagePickerController.SourceType.photoLibrary if UIImagePickerController.isSourceTypeAvailable( UIImagePickerController.SourceType.photoLibrary){ // インスタンスの作成 let cameraPicker = UIImagePickerController() cameraPicker.sourceType = sourceType cameraPicker.delegate = self self.present(cameraPicker, animated: true, completion: nil) } else{ label.text = "error" } } } |
info.plistにカメラと写真の使用許可を取る設定をします
NSCameraUsageDescription
Privacy – Camera Usage Description
NSPhotoLibraryAddUsageDescription
Privacy – Photo Library Additions Usage Description
storyboardにUIImageView, Label, Buttonを配置します。Labelは複数行表示にしておきます。
それぞれを紐付けすると出来上がり
またAlbumを開いてアルバム内の写真を選択すると、同様に画像の予測をします。
着物が99%と出ましたが…
このモデルは物や動物のクラス分けがメインなのでしょうか
References:
機械学習 – Apple Developer
Core ML – Apple Developer