画像判定プログラムで使用する画像で、JPEG形式以外の画像を削除したい

Python

はじめに

顔や物体の画像を判別するプログラムを作成しているとき、学習用に様々な画像データを利用します。
COCO2014、COCO2017などから学習用の画像データをダウンロードして、機械学習を実行すると、「画像データを読み込めない」のようなエラーメッセージが表示されることがあります。

エラーメッセージの例1

tensorflow.python.framework.errors_impl.InvalidArgumentError: Expected image (JPEG, PNG, or GIF), got empty file
[[{{node DecodeJpeg}}]]

エラーメッセージの例2

tensorflow.python.framework.errors_impl.InvalidArgumentError: Invalid JPEG data or crop window, data size 32768
[[{{node DecodeJpeg}}]] [Op:IteratorGetNext]

「画像データを読み込めない」が原因として考えられるのが、下記の2点です。

  1. ダウンロードの過程で画像データが破損した
  2. 元々の画像データが破損している

機械学習を行う環境によっては、実行に数時間掛かる場合があります。
私の環境では、1回の機械学習に数時間掛かるので、数時間経過したあとにエラーが発生すると、やる気が削がれます。

事前に学習用の画像データが適切な画像データなのかを確認するプログラムを作成しました。

プログラムの概要

下記URLを基にプログラムを作成しました。
python – Tensorflow: Error when trying transfer learning: Invalid JPEG data or crop window – Stack Overflow

画像データがJPEG形式となっているかを確認し、JPEG形式と確認できない画像データを削除します。

<JPEG形式として認識する方法>
JPEGファイルの構造は、大まかに表現すると下記の4つのデータ領域に分割できます。

 

  1. Start of Image(SOI)
  2. 4つのデータ領域の情報(セグメント)
  3. 画像データ
  4. End of Image(EOI)

それぞれの領域には、マーカーが設けられています。
1.と3.と4.のマーカーの有無を確認することで、JPEG形式となっているかを確認します。

プログラム

7行目に確認する画像フォルダを指定します。

from struct import unpack
from tqdm import tqdm
import os
import glob

# 画像フォルダのパスを指定する
images = glob.glob(r'C:\tmp\train2014\*')

class JPEG:
    def __init__(self, image_file):
        with open(image_file, 'rb') as f:
            self.img_data = f.read()

    def decode(self):
        '''
        JPEGファイルの構造は、大まかに表現すると4つのデータ領域に分割できる。
        1.Start of Image(SOI)
        2.4つのデータ領域の情報(セグメント)
        3.画像データ
        4.End of Image(EOI)
        decode関数では、1.と3.と4.のマーカーの有無を確認する
        :return:
        '''
        data = self.img_data
        while (True):
            marker, = unpack(">H", data[0:2])
            # Start of Image(SOI)を確認する
            if marker == 0xffd8:
                data = data[2:]
            # End of Image(EOI)を確認する
            elif marker == 0xffd9:
                return
            # Start of Scan(このマーカ以降が画像データ)を確認する
            elif marker == 0xffda:
                data = data[-2:]
            else:
                lenchunk, = unpack(">H", data[2:4])
                data = data[2 + lenchunk:]
            if len(data) == 0:
                break


bads = []

for img in tqdm(images):
    # 画像を読み込む
    image = JPEG(img)
    try:
        # 画像がJPEG形式となっているかを確認する
        image.decode()
    except:
        # 画像データを確認して、JPEG形式となっていない画像をbadsに代入する
        bads.append(img)

print('削除する画像', bads)

for name in bads:
    # JPEG形式となっていない画像データを削除する
    os.remove(name)

実行結果

プログラムを実行する前に、動作に必要なライブラリをインストールしておきます。

pip install tqdm

COCO2014のtrain2014.zip内の画像データには、破損している画像データが含まれていました。COCO2014を確認した結果は下記の通りです。

> python.exe check-jpeg.py
100%|██████████| 82783/82783 [06:30<00:00, 212.10it/s]
削除する画像 ['C:\\tmp\\train2014\\COCO_train2014_000000167126.jpg']

削除した画像データをフォトアプリで表示しようとしても、正常に表示することができませんでした。

 

 

コメント

タイトルとURLをコピーしました