本シリーズの記事一覧:
1.「Core ML」モデルを「Create ML」で既存のラベル付けされたアニメ画像を入力として用いてトレーニングする。
2. そのモデルと「Vision」フレームワークを用いて新規画像からラベルを取得する。
3. (本記事)それをもとに時間帯に合わせてmacOSの壁紙を変更する
意図:
Mac OSの壁紙として、時刻に合わせてさまざまなアニメ画像を設定するアプリの開発。
機械学習を使用して、アニメ画像に自動的に昼または夜としてのマーク付けを行う。
アニメ画像から昼夜の状態を認識する必要があるため、機械学習を取り入れます。
このアプリは、例えば日中には昼の場面のさまざまなアニメ画像を壁紙として設定します。そして夜間には、夜の場面のさまざまなアニメ画像を壁紙に設定します。
本記事
本稿では、壁紙を時間帯に合うアニメ画像に自動的に変えてくれるmacOS用のアプリケーションを開発する方法を説明します。
本記事の前項で、アニメ画像を入力すると「昼間」または「夜間」のラベルを出力できる機械学習モデルをすでに作成しました。また、入力された画像に対するラベルを取得するSwiftコードの書き方も学習しました。
フロー
- ユーザーが多くのアニメ画像が保存されたフォルダーを選択します。
- プログラムが機械学習を用いて各画像に対してラベル(昼間または夜間)を割り当てます。
- プログラムが、ランダムな画像を壁紙として設定するために毎時間繰り返し呼び出されるタイマーを開始します。システム時間を確認し、昼間であれば昼間の画像をランダムに選択し、夜間であれば夜間の画像をランダムに選択します。
では始めましょう
フォルダーの選択とファイルの読み込み
前記事のデモアプリケーションで示した通り、ユーザーがファイルを選択できるようにするにはNSOpenPanel
を使います。前回は画像を一枚だけ選択しましたが、今回は、多くの画像が保存されているフォルダーを選択できるように変更します。
@IBAction func browseFile(sender: AnyObject) {
let openPanel = NSOpenPanel();
openPanel.title = "Select a file"
openPanel.canChooseDirectories = true //フォルダ
openPanel.canChooseFiles = false //ファイル
openPanel.allowsMultipleSelection = false
openPanel.allowedFileTypes = ["jpg", "png", "jpeg"]
openPanel.begin { (result) -> Void in
if(result == NSApplication.ModalResponse.OK){
let path = openPanel.url!.path
self.processFiles(path: path)
}
}
}
関数processFiles
において、まず当該フォルダーに含まれる全てのファイルを取得し、その後各ファイルに対して機械学習関数 detectScene
を呼び出します。
func processFiles(path: String){
let fm = FileManager.default
do {
let items = try fm.contentsOfDirectory(atPath: path)
for item in items {
let completePath = path + "/" + item
if let image = CIImage(contentsOf: URL(fileURLWithPath: completePath)) {
//これは画像ファイルです
imageCount += 1
detectScene(image: image, path: completePath)
}
}
} catch {
// ディレクトリの読み取りに失敗しました
}
}
機械学習 (Vision Framework)
まず、昼間の画像群へのパスと夜間の画像群へのパスを示す2つの変数を設定しましょう。
var dayImages = [String]()
var nightImages = [String]()
var imageCount = 0
これで、本記事の第2部で行ったように、機械学習による認識コードを書く準備が整いました。
func detectScene(image: CIImage, path: String) {
// MLモデルを読み込む
guard let model = try? VNCoreMLModel(for: モデルファイルの名前().model) else {
fatalError()
}
// Visionリクエストを作成する
let request = VNCoreMLRequest(model: model) { [weak self] request, error in
guard let results = request.results as? [VNClassificationObservation],
let topResult = results.first else {
fatalError("予期しない結果")
}
let detectedResult = topResult.identifier
if detectedResult == "昼間"{
self!.dayImages.append(path)
} else if detectedResult == "夜"{
self!.nightImages.append(path)
}
//Check if the progress finished
if (processedCount == self!.imageCount){
self!.finishedML()
}
}
let handler = VNImageRequestHandler(ciImage: image)
DispatchQueue.global(qos: .userInteractive).async {
do {
try handler.perform([request])
} catch {
print(error)
}
}
}
毎時間の壁紙変更
まず、タイマー変数を作成します:
var wallpaperTimer: Timer!
タイマーのスケジュールを設定します
wallpaperTimer = Timer.scheduledTimer(withTimeInterval: 3600, repeats: true) { (timer) in
self.changeWallPaper()
}
そして壁紙を3600秒(60秒*60分)ごとに変更します。
func changeWallPaper(){
let now = Date()
let calender = Calendar.current
let hour = calender.component(Calendar.Component.hour, from: now)
//Day
if 8 <= hour && hour <= 18{
if let random = self.dayImgAry.randomElement() {
self.setWallpaper(wallpaperPath: random)
}
} else {
if let random = self.nightImgAry.randomElement() {
self.setWallpaper(wallpaperPath: random)
}
}
}
func setWallpaper(wallpaperPath: String){
let sharedWorkspace = NSWorkspace.shared
let screens = NSScreen.screens
let wallpaperUrl = URL(fileURLWithPath: wallpaperPath)
var options = [NSWorkspace.DesktopImageOptionKey: Any]()
options[.imageScaling] = NSImageScaling.scaleProportionallyUpOrDown.rawValue
options[.allowClipping] = true
for screen in screens{
do {
try sharedWorkspace.setDesktopImageURL(wallpaperUrl, for: screen, options: options)
} catch {
print(error)
}
}
}
これで完成です!時間帯に応じて壁紙を変えるアプリが出来上がりました!