機械学習用に画像を前処理する
23
- 1月
2019
Posted By : boomin
機械学習用に画像を前処理する
Advertisements

1. 機械学習用の画像データの前処理

画像そのものにも前処理は時としてもちろん必要です。 が、ここで扱いたいのは、前処理の前の前処理 です。

スクレイピングで収集してきたからこその、データの前処理が必要です。

2. 機械学習の教師データとしての画像データ

前回、Google画像検索で大量の画像を収集してきました。 スクレイピングで収集してきたからこその、データの前処理が必要です。

話題としては、以下の2点です。

  1. 機械学習用の画像データを、前処理でRGBA形式に変換する
  2. 問題はそれだけじゃない:教師データが重複する可能性

それでは、個別に見ていきましょう。

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つです。

  1. 本命チョコ画像と義理チョコの重複ファイルの削除
    • 同じファイル名かつ、同じサイズ、同じチャンネル数の画像は、同じ画像であると判断して削除
  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

コメントを残す