Python実践!複数のデータをまとめたデータ構造を作成する方法

python実装方法

機械学習では必然的に複数のデータを扱うことになります。例えばMNISTのような画像分類タスクでは、70,000枚の画像データが提供されています。
MNISTではデータを扱いやすいように、ライブラリから取得すると、まとまったデータ構造として取得されますが、独自のデータを扱う場合は自分でまとめる必要がありますので、その方法を紹介します。

本記事のテーマ

複数のデータ(例えば画像)を取得し、1つのデータ構造にする方法をソースコードとともに紹介します。

想定する処理フロー

こちらの図のフローで複数のデータを順番に読み込み、一つのデータ構造にまとめる処理を実現していきます。

それではコードとともに各処理のポイントを見ていきましょう。

実装例と解説

こちらが先ほどの処理フローを実現したコードになります。
※この例では、データとして「/Users/user/Pictures」に保存している画像10枚を対象としました。

import numpy as np
from pathlib import Path # ファイル操作の定番ライブラリ
import cv2 # 画像処理用ライブラリ

img_path = Path("[画像を保存しているPathを指定]") # 例:"/Users/user/Pictures"

# ② 取得したPathを元にデータを読み込み、データ毎の処理を実施
def read_img(img_path):
    """
    画像を保存しているPathを受け取り、
    画像毎に処理を行い、処理した画像を返す関数
    
    Args:
        img_path (PosixPath): 画像データのPath
    Return:
        img (ndarray): 処理後の画像
    """

    # img_pathで指定した画像を読み込む
    img = cv2.imread(str(img_path))
    
    # OpenCV(cv2)ではBGRの順番で読み込まれるため、RGBの順番に変換
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 

    # 画像のshapeが[H*W*Channel]となっているので、[Channel*H*W]に変更
    img = img.transpose([2,0,1]) 
    
    return img

# ① データの保存元(Path)を順番に取得
imgs = [read_img(img_path) for img_path in img_path.glob('*.png')] 

# ③ 複数の画像を一つにまとめたデータ構造を作成
# 画像サイズが異なると一つのデータ構造(ndarray)にできないため、最も小さいサイズを確認
h_min = np.min([img.shape[1] for img in imgs])
w_min = np.min([img.shape[2] for img in imgs])

# 同じサイズの画像のリストとして取得
cropped_img = [img[:, :h_min, :w_min] for img in imgs]

# 画像を一つのデータ構造(ndarray)に変換
imgs_ndarray = np.stack(cropped_img, axis=0) 


# 作成したデータ構造(ndarray)のshapeを確認
print(imgs_ndarray.shape) # 出力結果:(10, 3, 335, 368)
  1. データの保存元(Path)を順番に取得
    リスト内包表記を用いて、データの保存先(img_path)にある拡張子が'png'のファイルpathを順番に取得し、画像を読み込む自作関数(read_img)に渡しています。
  2. 取得したPathを元にデータを読み込み、データ毎の処理を実施
    OpenCV(cv2)を用いて画像を読み込んだ後、カラーの順番をBGRからRGBへと変換しています。
    そしてデータ構造が[画像枚数, チャンネル数, H, W]となるように、次元の入れ替えを行っています。これはPyTorchでデータを扱う場合、[batch_size, チャンネル数, H, W]として扱われるのでそれに対応しています。
  3. 読み込んだ画像は配列(array)として保存しているので、np.stack関数を用いて一つのndarrayに変換しています。
    [channel, H, W]というデータ構造(ndarray)をもつ、長さN(画像枚数)の配列になっているので、np.stackを使い[N, channel, H, W]というデータ構造(ndarray)にしています。

これで複数のデータを一つのデータ構造としてまとめて取得することができました。
以前の記事で紹介したMNISTデータ構造と同じような形式になっているのがわかると思います。ニューラルネットを構築して学習する場合は、教師データを用意すればMNISTと同様に学習ができます。
※実際に学習するにはデータ数も確保する必要があります。

終わりに

データの前処理の前段にあたる、まとまったデータ構造の作り方を紹介しました。
今後も継続して役に立つ情報を共有していきたいと思います。

コメント

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