はじめに
XcodeのCreateML
が簡単に画像認識をアプリケーションを組み込めるようなので試しにやってみました。
https://developer.apple.com/jp/machine-learning/create-ml/
上のようにやってくれるらしい。
作成したもの
作った pic.twitter.com/FuWqPuZsdH
— 清水 幸佑 (@thimi0412) December 2, 2019
環境
- Xcode Version 11.2.1
画像データの準備
何を分類するのか
りんごとかオレンジとかの分類だとなんかつまらないので、今回はアイドルマスターシンデレラガールズ カードギャラリーさんから画像をいただいて、島村卯月
、渋谷凛
、本田未央
を分類してみようと思います。
学習用のデータとテスト用のデータのフォーマットはこんな感じ。
各ディレクトリの名前がラベルになるのでtrain_data
とtest_data
の名前を間違えないように気をつけましょう。
train_data
├── mio_honda
├── rin_shibuya
└── uzuki_shimamura
test_data
├── mio_honda
├── rin_shibuya
└── uzuki_shimamura
#モデルの作成
プロジェクトの作成
Xcode > Open Developer Tool > Create ML
から起動
プロジェクトのフォルダを決定しテンプレートを選択します。今回は画像認識なのでImage Classifier
を選択。
学習開始
学習用データをTraining Data
に、テスト用データをTesting Data
にデータを追加しましょう。
追加したらTrain
ボタンを押して完了です。
学習が完了したらOutput
にある.mlmodel
ファイルをドラッグして別の場所に保存しておきましょう。
アプリケーションに組み込む’
XcodeからCreate new Xcode project
でSingle View App
でプロジェクトを作成します。私はswiftには疎いのでとりあえず書いたコードを乗っけておきます。
ViewController.swift
とカメラを使用するのでinfo.plist
をいじりました。
先ほど作成した.mlmodel
をプロジェクトに追加してください。
import UIKit
import AVKit
import CoreML
import Vision
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
@IBOutlet weak var cameraDisplay: UIImageView!
@IBOutlet weak var resultLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
setUpCamere()
}
func setUpCamere() {
guard let device = AVCaptureDevice.default(for: .video) else { return }
guard let input = try? AVCaptureDeviceInput(device: device) else { return }
let session = AVCaptureSession()
session.sessionPreset = .hd4K3840x2160
let previewLayler = AVCaptureVideoPreviewLayer(session: session)
previewLayler.frame = view.frame
cameraDisplay.layer.addSublayer(previewLayler)
let output = AVCaptureVideoDataOutput()
output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "CameraOutput"))
session.addInput(input)
session.addOutput(output)
session.startRunning()
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let sampleBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
scanImage(buffer: sampleBuffer)
}
func scanImage(buffer: CVPixelBuffer) {
// .mlmodelを読み込ませる
guard let model = try? VNCoreMLModel(for: IdolClassifier_1().model) else { return }
let request = VNCoreMLRequest(model: model) { request, _ in
guard let results = request.results as? [VNClassificationObservation] else { return }
guard let mostConfidentResult = results.first else { return }
DispatchQueue.main.async {
if mostConfidentResult.confidence >= 0.9 {
let confidenceText = "\n \(Int(mostConfidentResult.confidence * 100))% confidence"
switch mostConfidentResult.identifier {
case "uzuki_shimamura":
self.resultLabel.text = "uzuki_shimamura \(confidenceText)"
case "rin_shibuya":
self.resultLabel.text = "rin_shibuya\(confidenceText)"
case "mio_honda":
self.resultLabel.text = "mio_honda\(confidenceText)"
default:
return
}
} else {
self.resultLabel.text = "I don't know"
}
}
}
let requestHandler = VNImageRequestHandler(cvPixelBuffer: buffer, options: [:])
do {
try requestHandler.perform([request])
} catch {
print(error)
}
}
}