アニメ画像の昼/夜認識システムの作成：(3 / 3) それをもとに時間帯に合わせてmacOSの壁紙を変更する

## 本シリーズの記事一覧:

1.[「Core ML」モデルを「Create ML」で既存のラベル付けされたアニメ画像を入力として用いてトレーニングする。](https://qiita.com/MaShunzhe/items/9933eab603781154232f)
2. [そのモデルと「Vision」フレームワークを用いて新規画像からラベルを取得する。](https://qiita.com/MaShunzhe/items/c829b3219b1afe335391)
3. （本記事）それをもとに時間帯に合わせてmacOSの壁紙を変更する

## 意図：

Mac OSの壁紙として、時刻に合わせてさまざまなアニメ画像を設定するアプリの開発。

機械学習を使用して、アニメ画像に自動的に昼または夜としてのマーク付けを行う。

アニメ画像から昼夜の状態を認識する必要があるため、機械学習を取り入れます。
このアプリは、例えば日中には昼の場面のさまざまなアニメ画像を壁紙として設定します。そして夜間には、夜の場面のさまざまなアニメ画像を壁紙に設定します。

## 本記事

本稿では、壁紙を時間帯に合うアニメ画像に自動的に変えてくれるmacOS用のアプリケーションを開発する方法を説明します。

本記事の前項で、アニメ画像を入力すると「昼間」または「夜間」のラベルを出力できる機械学習モデルをすでに作成しました。また、入力された画像に対するラベルを取得するSwiftコードの書き方も学習しました。

## フロー
1. ユーザーが多くのアニメ画像が保存されたフォルダーを選択します。
2. プログラムが機械学習を用いて各画像に対してラベル（昼間または夜間）を割り当てます。
3. プログラムが、ランダムな画像を壁紙として設定するために毎時間繰り返し呼び出されるタイマーを開始します。システム時間を確認し、昼間であれば昼間の画像をランダムに選択し、夜間であれば夜間の画像をランダムに選択します。

## では始めましょう

### フォルダーの選択とファイルの読み込み

前記事のデモアプリケーションで示した通り、ユーザーがファイルを選択できるようにするには`NSOpenPanel` を使います。前回は画像を一枚だけ選択しましたが、今回は、多くの画像が保存されているフォルダーを選択できるように変更します。

```swift
@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` を呼び出します。

```swift
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つの変数を設定しましょう。

```swift
var dayImages = [String]()
var nightImages = [String]()
var imageCount = 0
```

これで、本記事の第2部で行ったように、機械学習による認識コードを書く準備が整いました。

```swift
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)
        }
    }
}
```

### 毎時間の壁紙変更

まず、タイマー変数を作成します:

```swift
var wallpaperTimer: Timer!
```

タイマーのスケジュールを設定します

```swift
wallpaperTimer = Timer.scheduledTimer(withTimeInterval: 3600, repeats: true) { (timer) in
    self.changeWallPaper()
}
```

そして壁紙を3600秒（60秒*60分）ごとに変更します。

```swift
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)
        }
    }
}
```

```swift

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)
        }
    }
}

```

これで完成です！時間帯に応じて壁紙を変えるアプリが出来上がりました！

---

:relaxed: [Twitter @MszPro](https://twitter.com/MszPro)

:sunny: [私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。](http://mszpro.com/ioskiji/)
<img width="150" src="https://cdn.mszmagic.com/static-web-content/AppClipImage_small.png">