Slide 1

Slide 1 text

外観検査用画像前処理の コツをコード解説付きで。 2022.8 合格者の会2022/CDLE LT Akihiro ITO

Slide 2

Slide 2 text

モチベーション ● 高性能な異常検知モデル「PaDiM」を簡単に使えるようにしたい。 ○ PaDiM:https://arxiv.org/pdf/2011.08785.pdf ● 動作環境として、connectome.design社開発のmetabase®を利用する。 データを放り込むだけで、どの程度検知できるか試せるように。 ● 撮像したデータをPaDiMの入力に合わせるための前処理が意外と面倒。 → 汎用的な前処理を作ろう!

Slide 3

Slide 3 text

FYI:Overview of PaDiM ● 2020年11月に発表された、不良品検知を行 う機械学習モデル。 ● 正常品のみの画像から再学習不要で不良 品検知が実装可能。 ● 不良品検知のデータセットである MVTec AD でSOTAを達成。 出展:https://arxiv.org/pdf/2011.08785.pdf

Slide 4

Slide 4 text

FYI:Overview of MVTec AD ● 2019年6月に公開されたデータセット。 ● 15のカテゴリーに分類され、工業製品や農 作物の画像。 ● 欠陥領域のセグメンテーションデータも含ま れる。 出展:https://www.mvtec.com/company/research/datasets/mvtec-ad

Slide 5

Slide 5 text

今回のターゲット画像。 ● コンソメキューブの包み方の外観検査。 ● Good / Bad の2値分類。 ● 入力画像は、ベルトコンベア上を流れてくる 対象を撮像するため、画像ファイル内での位 置が不定。 → PaDiMで使える画像にする。

Slide 6

Slide 6 text

前処理でやること。 1. 物体が画像の中心に配置された、 224 x 224 pxのカラーpngファイルを作る。 2. 精度確認用の、224 x 224 pxのモノクロ2値pngファイルを作る。 3. 各ディレクトリ(=フォルダと同義)への振り分け ※今回は、時間の関係で ”1”のみ紹介。

Slide 7

Slide 7 text

どう処理するか? 1. 物体を検出して切り出す。 → 最新のDETRを使用 DETR:DEtection Transformer 2020年に発表されたTransformerを使った物体検出手法。 ※FasterRCNNも試したが、DETRの方が精度がよかった。 2. PaDiMで使えるように、画像のサイズを揃え、画像の中心に 物体を配置する。

Slide 8

Slide 8 text

全体の処理構造 result = step1_DetectAndCrop.prePadim_step1(searchpath, indir, outdir_step1) if result == 0: print("Error! Step1. No File Saved to: ", outdir_step1) return False result = step2_Align.prePadim_step2(searchpath2, outdir_step1, outdir_step2, args.bgcolor) if result == 0: [エラー処理] ● 途中結果を確認しやすい&再利用しや すい単位でステップを分割する。 ○ Step1:DETRを使って画像の中から物 体を検出し、画像を切り出す。 ○ Step2:正しく検出と切り出しができない 画像は捨てて、すべて同じサイズに揃 える。 ● ステップごとに必ず処理結果を判定し、 エラー処理を入れること。

Slide 9

Slide 9 text

ディレクトリ構造の処理のコツ parser = argparse.ArgumentParser() parser.add_argument('-d', '--data_path', type=str) parser.add_argument('-s', '--save_path', type=str) cwd = os.getcwd() targetdir_in = os.path.join(args.data_path, args.target) targetdir_out = os.path.join(args.save_path, args.target) ● 入出力ディレクトリ名は、引数として受け 取れるようにした方が良い。 ● 上位の構造に依存しないよう、 Current Working Directory を最上位として処理する。 → フルパス入れちゃダメ。 ● パスを組み立てる時は、文字列結合で はなく、 os.path.join() を使う。 → “/”入力の有無を問わないように。

Slide 10

Slide 10 text

ディレクトリ構造全体から対象ファイルを探すコツ # 各種定義 filetype = “.png” wildcard = “/**/*” searchpath = os.path.join(indir, wildcard + filetype) if len(glob.glob(searchpath, recursive=True)) == 0: print("Error! Step1. File Not Found in: ", searchpath) return False else: [実際の処理] ● 特定の数字や文字列( マジックナンバー) をソースコードの途中に埋め込まず、まと めて定義する。 ● パスに、“ /**/* ”を含めると、配下のディ レクトリ階層すべてから、対象ファイルを 検出できる。 ● 「対象ファルが一つも見つからない場合」 のエラー処理を必ず入れること。

Slide 11

Slide 11 text

簡易化のため、うまく検出できなかった画像は諦める! [画像を開いてサイズを配列に入れるループ処理 ]: size_mean = np.mean(image_size_array, axis=0) size_std = np.std(image_size_array, axis=0) size_limit_low = size_mean - size_std size_limit_high = size_mean + size_std if limit_low_w <= img.width and img.width <= limit_high_w and limit_low_h <= img.height and img.height < limit_high_h: [実際の処理] ● 検出と切り出しに失敗した画像は、画 像サイズが異なる。 ● 平均と分散から、作成すべき基本画像 サイズを求める。 ● 画像サイズから平均と標準偏差を計算 し、外れ値となる画像を除く。

Slide 12

Slide 12 text

同じ背景色・サイズの画像に揃える。 background_color=(0,0,0) if bgcolor == 'white': background_color=(255,255,255) [画像を開くループ処理 ]: img_new = Image.new(img.mode, box_size, background_color) left = int((box_wh - img.width) // 2) top = int((box_wh - img.height) // 2) img_new.paste(img, (left, top)) img_new.save(os.path.join(outdirname, os.path.basename(file))) ● 基本画像の背景色を引数から受け取 る。(背景は、黒か白でよいはず) ● 基本画像を生成し、元の画像をその中 心に貼り付ける。

Slide 13

Slide 13 text

これで、入力画像から学習用画像が生成される。

Slide 14

Slide 14 text

まとめ ● 今回の例 ○ ファイル数:4 ○ ソースコードの行数:約250行(空行含む) ● AIのサンプルコードは、パスやファイル名なども含め特定の文字列が直接書き込まれてい たり、画像サイズや形式も限定されている場合が多い。 ● 実務利用に向けて汎用的に使えるようにするためには、課題に合わせて修正する箇所が 極力少なくなるように作り込む必要がある。 ● また例えば、 ”for i in range(10):” のようにいわゆるマジックナンバーが埋め込まれてい るとコードの解読や修正に手間がかかるので、必ず定義すること。 epoch = 10 for i in range(epoch):

Slide 15

Slide 15 text

ソースコードは、美しく。