娘とVertex AIで作る「おりがみ折り筋分類モデル」 データ作成編
きっかけ編からの続きです。
データをどう作る?
おりがみは娘がどんどん作ってくれて、折り筋という2次元に変えて撮影するというアイデアがあったとしても、実際にどうデータ化するかは一筋縄では行きませんでした。
Vertex AI では一つのラベル(おりがみ名)について1000枚の画像データを推奨しています。って1000枚無理だよ!最小限の10枚をクリアすることを考えます。
最終的に以下の方法にたどり着きました。
おりがみより一回り大きい正方形のダンボール(台紙)に折り筋をぴーんと貼り付ける(仮どめコアラ使用)。
台紙を壁などに立てかけて、折り筋に影がなるべく入らないようにスマホで撮影。
台紙を90度回転させて再度撮影。
3をあと2回繰り返して、最終的に0,90,180,270度回転の画像を撮る。
折り筋を一旦剥がして裏返しにして貼り直す。
2,3,4を再度行う。
撮影した8枚の画像に対して90,180,270度回転の画像を生成
この方法で、1枚の折り筋に対して片面4枚、両面で8枚の画像を撮影し、画像処理で3倍の24枚に増やします。これでノルマの10枚をクリアします。
以下に撮影データを置いておきます。
おりがみは以下の11種類。飛行機、やっこさん、ピアノは僕が折りました。これぐらいしか折れないです。ピアノは唯一、娘に教えたおりがみです。工程が少ない割にしっかりピアノの造形になります。
キャンディーボックス
星
箱
ツル
飛行機
バラ
やっこさん
椅子
ピアノ
リボン
ハス
ここで僕は大失態を犯します。撮影データを見て気づくことないですか?なぜか片面につき3枚しか撮らなかったんです。ショック。結局、一つの折り筋に対して画像処理分を含めて18枚ということになりました。
これでうまくいくならそれはそれで成果ということで気を取り直します。(画像処理は3回だからそれに引っ張られて勘違いしたんだと思います)
撮影方法の試行錯誤
10枚弱程度の撮影画像が必要で折り筋の両面撮るという前提で考えていきました。回転や裏返しを簡単にやりたい。
(このセクションは読まなくてもその後に関係ないですが一番苦労した部分なので読んでほしい)
最初は、ただ机の上に折り筋を置いて撮ることを考えました。これだと折り筋がぐちゃぐちゃで撮りづらい、照明の反射も気になる。ある程度の圧力を加えて伸ばしたいところ。
次に、手近にあったスキャナで撮ろうと思いました。でもスキャナにいちいちセットするのがめんどくさい、スキャナを持っていないと撮れない(将来性を考えてなるべく誰でもデータを作れる状況にしたい)、スキャナだとカバーの圧力が強すぎて折り筋が消えちゃうかもしれないと思ってやめました。
次に、20センチ角の透明なアクリル板がなぜかたくさんあったので、それに挟み込んで適度な圧縮をくわえて撮影することを考えました。挟んでクリップで留めるとバッチリでした。
これは折り筋の美しさ、回転・裏返しの容易さという点では完璧だったのですが、壁に立てても透明ゆえ反射が酷くてだめでした。まさか偏光フィルタ使うわけいかないし、照明組むわけにもいかないし。
次に、その辺にあった四角いダンボールに貼り付けて撮りました。貼り付けは古典的にセロハンテープを小さな輪にしました。この方法は回転は簡単だし、反射もなくて良いのですが、折り筋の貼付けが面倒、貼り直しは丁寧にやらないと折り筋が破れる。
"貼って剥がせてキズ残さず"みたいなのなんかなかったっけ?
ここで救世主あらわる「仮どめコアラ」!
こんな感じでダンボールに折り筋を固定します。適度な強度で理想的。厚さが1mmと2mmの2種類あるのですが1mmのほう使いました。
これで安定して撮影ができるようになりました。最終的には1つの折り筋に対して2分ぐらいで撮れるようになったと思います。
ファイル名にラベルを含める
撮影データができたのであとは回転の画像処理をしてハイおしまいといきたいところなのですが、画像にラベル(おりがみ名)をつけないといけません。それぞれの折り筋が何のおりがみなのかは教えないといけないんですね。
今回は撮影画像のファイル名にラベルを含めてみます。ピアノを例に取ると以下のようにしました。
piano_0.jpg #おりがみ完成画像 AIモデル作成には使わない
piano_1.jpg #ここから折り筋撮影画像
piano_2.jpg
piano_3.jpg
...
piano_6.jpg
Vertex AI のコンソールからアップロードした画像を見ながらラベルをつけることもできるのですが、折り筋見ても素人には何の折り紙かわかりませんから、やっぱり撮影するやいなやファイル名に付けるのが確実簡単な気がしています。
回転画像の生成
今回はColab上のPythonで画像生成を行います。Colab からグーグルドライブ上のファイルの読み書きが簡単にできてしまって便利すぎます。
コードは以下の通り。flipや拡大縮小もできるようになっています。flipはデータ水増しの試行錯誤です(結局使わなかった)。拡大縮小は学習用データと予測用データの上限がそれぞれ30MB、1.5MB(1ファイルあたり)なので場合によって必要になります。
import os
from PIL import Image
def process_image(image_path, save_folder, resize_percent=None):
img = Image.open(image_path)
if resize_percent is not None:
# 縮小割合を計算
width, height = img.size
new_width = int(width * resize_percent / 100)
new_height = int(height * resize_percent / 100)
new_size = (new_width, new_height)
else:
new_size = img.size # サイズ変更なし
# 回転と反転の組み合わせを処理
operations = [
(0, '', "000"),
(90, '', "090"),
(180, '', "180"),
(270, '', "270"),
#(0, 'flip', "000_f"),
#(90, 'flip', "090_f"),
#(180, 'flip', "180_f"),
#(270, 'flip', "270_f")
]
for degree, flip, operation_name in operations:
save_path = os.path.join(save_folder, f"{operation_name}_{os.path.basename(image_path)}")
if os.path.exists(save_path):
print('exists ' + save_path)
else:
if flip == "flip":
processed_img = img.transpose(Image.FLIP_LEFT_RIGHT)
else:
processed_img = img
processed_img = processed_img.rotate(degree, expand=True)
if resize_percent is not None:
# 画像を指定した割合で縮小
processed_img = processed_img.resize(new_size, Image.LANCZOS)
processed_img.save(save_path)
print('save ' + save_path)
if __name__ == "__main__":
input_folder = "/content/drive/MyDrive/origamiDB/input" # 処理する画像ファイルが入っているフォルダ
output_folder = "/content/drive/MyDrive/origamiDB/output" # 処理した画像ファイルを保存するフォルダ
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for filename in os.listdir(input_folder):
if filename.endswith(".jpg") or filename.endswith(".jpeg"):
parts = filename.split("_") # ファイル名を "_" で分割
# ファイル名が3つのパーツからなり、最後のパーツが0から始まる場合
if len(parts) >= 2 and parts[-1].startswith("0"):
continue # ループから外す
input_image_path = os.path.join(input_folder, filename)
process_image(input_image_path, output_folder)
次はいよいよモデル作成に入ります。
この記事が気に入ったらサポートをしてみませんか?