Help us understand the problem. What is going on with this article?

Swift初心者がCoreMLで機械学習に足を踏み入れてみた

はじめに

Swift初心者ではありますが、以前から興味があったCoreMLで機械学習にチャレンジしてみました。
機械学習と聞くと、なんとなく難しそうでハードルが高いイメージがあったのですが、実際に触れてみると想像よりも簡単に実装できましたのでまとめてみました。

そもそもCore MLとは?については、まとめられている記事がありましたので紹介させていだきます。
Appleの機械学習がヤバい

成果物

今回は、機械学習モデルを活用してiPhoneで撮影した画像の中の主要なオブジェクトを分類して、その中で1番割合を占めているオブジェクト名を表示する機能を作成していきます。
coremltest.gif

Navigation barにSiamese catと表示されました。
Siamese cat = シャム猫のようです。(正解はラグドールなのでOKですかね?笑)
猫の種類まで検出するのすごい。。
一応猫を判別することに成功しました!

作成の流れ

作成にあたり以下のような流れで進めていきます。
image.png

1. Core MLを使用するための前準備

Core MLを使用するためには、モデルのダウンロードとインポートが必要になります。
ここでは、こちらの工程を説明していきます。

1-1. Core MLモデルのダウンロード

今回は、画像識別を行うためのCore MLモデルの1つであるMobileNetV2を使用します。
そのために、以下Apple developerサイトのモデル一覧からダウンロードする必要があります。
https://developer.apple.com/jp/machine-learning/models/

image.png
「モデルを見る」をクリックすると以下の画像が表示されます。

image.png
赤枠内のファイルをダウンロードすることで、今回使用するCore MLモデルを入手することができます。

1-2. Core MLモデルをインポート

実際に使用するためにXcodeにCore MLモデルをインポートしていきます。
とは言っても、実際にはドラッグ&ドロップするだけの作業になります。。

image.png

MobileNetV2.mlmodelが追加されていれば準備作業は完了です。
続いて、実装作業に進んでいきます。

2. 実装

ここでは、
2-1. iPhoneで撮影した画像を表示する処理
2-2. 画像データを機械学習モデルで分類する処理
を順に実装していきます。

2-1. iPhoneで撮影した画像を表示する処理

2-1-1. StoryBoadに設置

image.png
今回は個人的に楽に実装しやすそうなNavigationBarCameraを配置していきます。
撮影した写真を表示させるためにUIImageViewを配置します。

2-1-2. 機能を実装

先ほど設置したオブジェクトにアクションを追加していきます。

  • Cameraをタップするとカメラを起動させる
  • UIImageViewに撮影した画像を表示させる
ViewController.swift
class ViewController: UIViewController, UINavigationControllerDelegate {
    // 撮影した画像を表示するImageView
    @IBOutlet weak var imageView: UIImageView!

    let imagePicker = UIImagePickerController()

    override func viewDidLoad() {
        super.viewDidLoad()

        imagePicker.delegate = self
        // .photoLibraryにするとフォト内の写真を開くことができます。
        imagePicker.sourceType = .camera
        imagePicker.allowsEditing = false

    }
    /// NavigationbarItemのカメラをタップした時のアクション
    @IBAction func didSelectCamera(_ sender: Any) {
        present(imagePicker, animated: true, completion: nil)
    }
}

/// UIImagePickerの処理
extension ViewController: UIImagePickerControllerDelegate {

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        if let userSelectedImage = info[.originalImage] as? UIImage {
            imageView.image = userSelectedImage
        }
        imagePicker.dismiss(animated: true, completion: nil)
    }
}

UIImagePickerController:
https://developer.apple.com/documentation/uikit/uiimagepickercontroller

2-1-3. info.plistでカメラ使用許可などを設定

カメラ使用などにユーザーの許可が必要になるためinfo.plistに設定を追加します。
image.png

コードではこちらになります。

info.plist
<key>NSPhotoLibraryUsageDescription</key>
<string>こちらの機能にはフォトを使用します</string>
<key>NSCameraUsageDescription</key>
<string>こちらの機能にはカメラを使用します</string>

2-2. 機械学習の処理を実装

image.png
今回は、Core MLで画像の分類を行うためVisionフレームワークを使用して実装していきます。

2-2-1. 使用するフレームワークなどをimportする

ViewController.swift
import CoreML
import Vision

Core ML:
https://developer.apple.com/jp/documentation/coreml
Visionフレームワーク:
https://developer.apple.com/documentation/vision

2-2-2. Core MLモデルのインスタンス生成と処理

ViewController.swift
// 使用するCore MLモデルのインスタンスを生成
let model = VNCoreMLModel(for: MobileNetV2().model)
// これでVisionからリクエストを送りmodelを元に解析することができる
let request = VNCoreMLRequest(model: model) { (request, error) in
     // 解析結果を分類情報として保存
     guard let results = request.results as? [VNClassificationObservation] else {
         return
     }
}

VNCoreMLModel:
https://developer.apple.com/documentation/vision/vncoremlmodel
VNClassificationObservation:
https://developer.apple.com/documentation/vision/vnclassificationobservation

2-2-3. 画像の解析リクエストをする

2-2-2で作成したCore MLモデルの解析をリクエストする処理を書いていきます。

ViewController.swift
// Visionへリクエストを送るためにUIImage→CIImageへ変換する
let ciImage = CIImage(image: image)

// 画像解析をリクエスト
let handler = VNImageRequestHandler(ciImage: ciImage)

// リクエストを実行
do {
    try handler.perform([request])
}
catch {
    print(error)
}

CIImage:
https://developer.apple.com/documentation/coreimage/ciimage
VNImageRequestHandler:
https://developer.apple.com/documentation/vision/vnimagerequesthandler

3. 完成形

ViewController.swift
import UIKit
import CoreML
import Vision

class ViewController: UIViewController {
    // 撮影した画像を表示するImageView
    @IBOutlet weak var imageView: UIImageView!

    let imagePicker = UIImagePickerController()

    override func viewDidLoad() {
        super.viewDidLoad()

        imagePicker.delegate = self
        imagePicker.sourceType = .camera
        imagePicker.allowsEditing = false

    }

    @IBAction func didSelectCamera(_ sender: Any) {
        present(imagePicker, animated: true, completion: nil)
    }

}

/// UIImagePickerの処理
extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        if let userSelectedImage = info[.originalImage] as? UIImage {
            imageView.image = userSelectedImage

            // 画像からオブジェクトを検出し、出力する
            detectImageObject(image: userSelectedImage)
        }

        imagePicker.dismiss(animated: true, completion: nil)
    }

    /// 画像からオブジェクトを検出・結果を出力
    func detectImageObject(image: UIImage) {
        // VNCoreMLModel(for: xx.modle): xxは使用するCore MLモデルによって変わります
        guard let ciImage = CIImage(image: image), let model = try? VNCoreMLModel(for: MobileNetV2().model) else {
            return
        }
        // Core MLモデルを使用して画像を処理する画像解析リクエスト
        let request = VNCoreMLRequest(model: model) { (request, error) in
            // 解析結果を分類情報として保存
            guard let results = request.results as? [VNClassificationObservation] else {
                return
            }

            // 画像内の一番割合が大きいオブジェクトを出力する
            if let firstResult = results.first {
                let objectArray = firstResult.identifier.components(separatedBy: ",")
                if objectArray.count == 1 {
                    self.navigationItem.title = firstResult.identifier
                } else {
                    self.navigationItem.title = objectArray.first
                }
            }
        }

        // 画像解析をリクエスト
        let handler = VNImageRequestHandler(ciImage: ciImage)

        // リクエストを実行
        do {
            try handler.perform([request])
        }
        catch {
            print(error)
        }
    }
}

VisionおよびCore MLを使用した画像の分類
https://developer.apple.com/documentation/vision/classifying_images_with_vision_and_core_ml

まとめ

Core MLの情報はdeveloper.appleにサンプルコードなどがあり、手が出しやすい部類かなと思いました。また、用意されているCore MLモデル以外に他社製の機械学習モデルも変換してアプリで使用することができるようなので、かなりの可能性が秘めているなと感じました。ただ、まだ理解できてないところが多いので、実際にコードを書きながら理解を深めて記事でも書ければと思います。

また、本記事に間違い等ございましたら、
大変恐縮でありますがご指摘いただければと存じます。
よろしくお願いいたします。

takashico
独学でRuby on Rails を勉強を始めて1年未満の初学者です。 今後は、自分でWebサービスの開発をしていきたいと考えています。 現在は、会社でiOS開発-swiftを勉強中です。
spacemarket
「世界中のあらゆるスペースをシェアできるプラットフォームを創る」のミッションのもと、スペースを1時間単位で簡単に予約できる「スペースマーケット」等を運営しています。
https://spacemarket.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした