23
- 1月
2019
No Comments
機械学習用に画像を前処理する
Advertisements
1. 機械学習用の画像データの前処理
画像そのものにも前処理は時としてもちろん必要です。 が、ここで扱いたいのは、前処理の前の前処理 です。
スクレイピングで収集してきたからこその、データの前処理が必要です。
2. 機械学習の教師データとしての画像データ
前回、Google画像検索で大量の画像を収集してきました。 スクレイピングで収集してきたからこその、データの前処理が必要です。
話題としては、以下の2点です。
- 機械学習用の画像データを、前処理でRGBA形式に変換する
- 問題はそれだけじゃない:教師データが重複する可能性
それでは、個別に見ていきましょう。
2.1 機械学習用の画像データを、前処理でRGBA形式に変換する
png画像などだと、こんなエラーが出ることがあります。
UserWarning: Palette images with Transparency expressed in bytes should be converted to RGBA images to RGBA images
そのように書いてあるので、いわれたとおり、前処理で事前にRGBAに変換しておく必要があります。
Advertisements
2.2 問題はそれだけじゃない:教師データが重複する可能性
スクレイピングで画像を収集したわけですが、検索キーが近しいこともあり、同じ画像が収集されてしまうことがあります。つまり、
本命チョコ画像と義理チョコ画像が、重複する
ことです。
教師データとして与える画像のうち、本命チョコ画像にも義理チョコ画像にも、同じ画像が含まれていたら、意味のある学習が出来るはずがありません。一方で、画像一枚一枚、目で見て重複を確認するなんてありえない・・・・・
これを事前に解決しておく必要があります。
3. source code
以下に、source codeを示します。 主な処理内容は2つです。
- 本命チョコ画像と義理チョコの重複ファイルの削除
- 同じファイル名かつ、同じサイズ、同じチャンネル数の画像は、同じ画像であると判断して削除
- 画像をRGBA形式に変換
- 画像ファイルを開き、RGBAではないと思われる画像を、RGBA形式で保存し、元ファイルを削除
- 変換に削除したら、どうせ使えないのだろうと仮定して、そのファイルを削除
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 15 14:00:06 2019
@author: boomin
"""
import pandas as pd
import numpy as np
import os
import glob
from PIL import Image
honImgDir = "images" + os.sep + "honmei" + os.sep
girImgDir = "images" + os.sep + "giri" + os.sep
# 本命チョコ写真リスト
hmImg = glob.glob(honImgDir + "*.*")
hmImg = pd.DataFrame({
"filename":[os.path.basename(f) for f in hmImg],
"fullpath":[f for f in hmImg]
})
# 義理チョコ写真リスト
grImg = glob.glob(girImgDir + "*.*")
grImg = pd.DataFrame({
"filename":[os.path.basename(f) for f in grImg],
"fullpath":[f for f in grImg]
})
# 本命チョコと義理チョコのファイル一覧
ifiles = pd.concat([hmImg,grImg], axis=0).reset_index(drop=True)
def getImageSize(im):
try:
rimf = Image.open(im)
return np.asarray(rimf).shape
except:
os.remove(im)
# 画像のサイズとチャンネル数を取得してDataFrameに追加
ifiles["shape"] = [ getImageSize(x) for x in ifiles["fullpath"]]
# ファイル名と画像サイズ、チャンネル数を元に、重複していないファイルを抽出
dupfiles = ifiles[ifiles.duplicated(subset=['filename', 'shape'], keep=False)]
# 義理と本命で重複していると思われる画像を削除
_ = [ os.remove(fpath) for fpath in dupfiles["fullpath"] ]
print(f"delete {len(dupfiles)} duplicated files")
# 重複していない、処理対象ファイル一覧
ifiles = ifiles[~ifiles.duplicated(subset=["filename", "shape"])]
def convertImage(fpath,shape):
root, ext = os.path.splitext(fpath)
try:
if len(shape)<3 or shape[2]!=3:
print(f"converted from {shape} : {os.path.basename(fpath)}")
rimf = Image.open(fpath)
rgb_im = rimf.convert('RGB')
rgb_im.save(f"{root}.jpg")
# 変換元画像を削除
os.remove(fpath)
except:
try:
os.remove(fpath)
print(f"removing {fpath} by error")
except:
print(f"cannot remove {fpath}")
# 画像の変換を行う
done = [ convertImage(fpath,shape) for fpath,shape in zip(ifiles['fullpath'], ifiles['shape']) ]
print(f"{len(ifiles)-len(done)} files are removed.")
4. 最終的には、残った教師データを実際に目で見て確認する
最後はやはり、やらざるを得ません。 が、面倒といえば面倒。。。。。
この件については、また次回書くことにします。
Advertisements