こしあん
2021-02-07

ごちうさで始める線画の自動着色(1)~データセットのEDA~


2k{icon} {views}


KaggleにあったGochiUsa_Facesデータセットを使って、ごちうさキャラの線画の自動着色で遊んでみました。この投稿では下準備として、データセットのEDAをします。

GochiUsa_Facesデータセット

これなに?:ごちうさのキャラの顔画像を集めたもの。

https://www.kaggle.com/rignak/gochiusa-faces

全部で4万枚、サイズは16.12GB。Kaggleの画像データセットにしては比較的お手軽サイズ。

このデータセットのいいところは、もちろんキャラが可愛くて癒やしなこともあるのですが、画像解像度が高めの画像を多く集めているところ小さい解像度のアニメ画像を集めたデータセットはあるが、そこそこ大きいサイズは見当たらない。ごちうさで完結しているのでキャラ数が限定的で、かつどのキャラの顔かアノテーションがついているところ。

今回から何個かの記事に分けて「GochiUsa Facesデータセット」で遊んでみます。

データセットの構造

ダウンロードすると3つのフォルダーと1つのPDFが出てきます。

  • additional_dataset
  • main_dataset
  • test_dataset
  • GochiUsa_Dataset.pdf

PDFではいろいろ面白い分析しています。

「main_dataset」と「test_dataset」が主要キャラ(9人)で、「additional_dataset」がサンプル数の少ないサブキャラクターの画像です。

今回は主要キャラのみ扱います。主要キャラのみ考えると「main_dataset」が訓練データ、「test_dataset」がテストデータとなります。

ただし、main_datasetとtest_datasetでデータソースが異なるようです。main_datasetはアニメのキャプチャ中心、test_datasetは(おそらく)ファンアートが中心です。ただし、PDFによると、主要キャラを画像分類すると、9割以上の精度が出たとのことです(後述)。今回はこのデータソースの差は無視しますが、ソースの差が問題になるケースで有効かもしれません。実践的ですね。

(a)がmain_dataset、(b)がtest_dataset、(c)がadditional_datasetです(画像はPDFより)。(a), (b)のキャラクターは、左から

  1. ブルーマウンテン
  2. チノ
  3. 千夜
  4. ココア
  5. マヤ
  6. メグ
  7. モカ
  8. リゼ
  9. シャロ

(c)のキャラクターは左から、

  1. あんこ(甘兎庵のオスうさぎ)
  2. 千夜の祖母
  3. ココアの母
  4. 凛(青山ブルーマウンテンの編集者)
  5. リゼの父
  6. サキ(チノの母親)
  7. タカヒロ(チノの父)
  8. ティッピー
  9. ユラ

データ数と解像度の関係

PDFより。画像の幅の分布です。

中央値が362ピクセル付近で、高解像度のサンプルが多め。

キャラごと、データセットごとに特定サイズ以上のサンプルが何枚あるか数えてみましょう。ここでの特定サイズとは「画像の幅の高さのうち小さい方の値が一定値以上か」で判定します。

from PIL import Image
import glob
import pandas as pd

def count_images(root_dir):
    dirs = sorted(glob.glob(root_dir + "/*"))
    characters = [d.replace("\\", "/").split("/")[-1] for d in dirs]
    min_sizes = [0, 64, 128, 256, 320, 512]
    df = pd.DataFrame(0, columns=min_sizes, index=characters)

    for i, d in enumerate(dirs):
        files = sorted(glob.glob(d + "/*"))

        for f in files:
            with Image.open(f) as img:
                for j, min_image_size in enumerate(min_sizes):
                    if min(img.size) >= min_image_size:
                        df.iloc[i, j] += 1
    return df

print(count_images("archive/main_dataset/main_dataset"))

main_dataset

キャラ/サイズ 0 64 128 256 320 512
Blue Mountain 1607 1553 1399 1133 939 623
Chino 12941 12707 11836 8900 7601 4098
Chiya 7283 7150 6793 5304 4500 2340
Cocoa 12223 12023 11334 8839 7479 3888
Maya 4747 4695 4440 3144 2574 1090
Megumi 4040 4005 3825 2732 2189 832
Mocha 1241 1220 1154 980 835 493
Rize 9052 8884 8307 6428 5425 2623
Sharo 6445 6344 5933 4509 3792 1888
小計 59579 58581 55021 41969 35334 17875

test_dataset

キャラ/サイズ 0 64 128 256 320 512
Blue Mountain 47 47 47 38 28 8
Chino 1525 1525 1522 1289 1026 401
Chiya 513 513 512 453 374 132
Cocoa 489 489 488 414 315 119
Maya 131 131 130 118 85 30
Megumi 93 93 92 83 73 26
Mocha 57 57 57 55 42 14
Rize 507 507 506 421 336 117
Sharo 534 534 534 419 299 111
小計 3896 3896 3888 3290 2578 958

mainとtestでそこまで大きくは解像度の分布は変わらないようです。

additional_dataset

キャラ/サイズ 0 64 128 256 320 512
Anko 13 11 10 9 8 2
Anzu 140 140 138 46 20 13
Chiya’s Grandmother 41 41 41 25 10 1
Cocoa’s Mother 266 266 263 200 180 103
Kano 170 170 165 88 64 10
Karin 84 84 82 38 15 0
Mai 196 196 191 116 108 60
Miki 78 78 75 21 15 10
Nacchan 133 133 122 67 29 17
Rei 147 146 139 66 42 17
Rin 439 433 422 323 271 123
Rize’s Father 88 85 84 41 33 22
Saki 156 146 113 77 66 32
Takahiro 682 679 629 274 110 28
Tippy 78 75 56 36 16 2
Yura 83 83 81 74 74 42
小計 2794 2766 2611 1501 1061 482

additionalが9人以上いました。小数サンプルなのでここは無視してもいいでしょう。Few-shot Learningをやりたいときには使えそうですね。

アスペクト比の分布

主要キャラクターについてアスペクト比の分布を見てみます。

指標として「縦÷横を、底が2のlogを取ったもの」と比較します。この値が0なら正方形、1なら縦が横の2倍、-1なら横が縦の2倍を表します。

import matplotlib.pyplot as plt
import numpy as np

def plot_aspect_ratios(root_dir):
    dirs = sorted(glob.glob(root_dir + "/*"))
    characters = [d.replace("\\", "/").split("/")[-1] for d in dirs]
    root_dir_base = root_dir.replace("\\", "/").split("/")[-1]

    fig = plt.figure(figsize=(10, 10))
    for i, d in enumerate(dirs):
        files = sorted(glob.glob(d + "/*"))
        ar = []
        for f in files:
            with Image.open(f) as img:
                width, height = img.size
                ar.append(np.log2(height/width))

        n = int(np.ceil(np.sqrt(len(dirs))))
        ax = fig.add_subplot(n, n, i+1)
        ax.hist(ar, bins=50)
        ax.set_yscale('log')
        ax.set_title(characters[i])


    fig.suptitle(root_dir_base)
    fig.savefig(f"{root_dir_base}.png")

ほとんどヒストグラムが一本線になったので、縦軸を対数にしてみました。それでも一本線なので、データセットはほぼ正方形ということがわかります。綺麗なデータセットで扱いやすいでしょう。

単純に画像分類してみると

今回画像分類が趣旨ではないのですが、「画像分類したときにどのぐらいの精度が出るの?」というのは疑問としてあります。

データセット付属のPDFでは、128×128の解像度でInception V3で訓練したときの混同行列がありました。これはtest_datasetに対する精度です。

大半のキャラは概ね9割以上出ています。チノちゃんは母数が多いだけあって99%の精度があります。混同しやすいのがモカとココアで、これは両者が姉妹なので仕方がないでしょう。

青山ブルーマウンテンも精度が若干低いですが、データセットに不均衡があるのでこれは仕方ないでしょう。不均衡データとしては結構実践的かもしれませんね。

予告

次の投稿では、線画の自動着色のための下準備、TFRecordの作成していきます。

次回はこちら:https:blog.shikoan.com/gochiusa-02



Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


One Comment

Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です