Python, Pillowで画像を一括リサイズ(拡大・縮小)

Modified: | Tags: Python, Pillow, 画像処理, 自動化

画像処理ライブラリPillow(PIL)のImageモジュールに、画像をリサイズ(拡大・縮小)するメソッドresize()が用意されている。

Image.resize(size, resample=0)
Returns a resized copy of this image.
Image.resize() - Pillow (PIL Fork) 10.2.0 documentation

ここでは、以下の内容について説明する。

  • Image.resize()の使い方
  • 一括で処理するコード例
    • 特定の拡張子のファイルのみを処理
    • Pillowが対応するすべての画像ファイルを処理

Pillow(PIL)のインストール、基本的な使い方などは以下の記事参照。

拡大・縮小ではなく、画像の一部を切り出してサイズを小さくする場合は、crop()を使う。

Image.resize()の使い方

引数sizeには、リサイズ後のサイズを(width, height)のようにタプルで指定する。

引数resampleには、リサンプリングする際に使われるフィルターを指定する。以下の6種類がある。省略した場合はデフォルトでNEARESTが使われる。

Filters
- NEAREST
- BOX
- BILINEAR
- HAMMING
- BICUBIC
- LANCZOS
Concepts - Filters - Pillow (PIL Fork) 10.2.0 documentation

下のもの(BICUBICとかLANCZOS)ほど処理に時間はかかるが、品質は高い。

from PIL import Image

img = Image.open('data/src/lena_square.png')

img_resize = img.resize((256, 256))
img_resize.save('data/dst/lena_pillow_resize_nearest.jpg')

img_resize_lanczos = img.resize((256, 256), Image.LANCZOS)
img_resize_lanczos.save('data/dst/lena_pillow_resize_lanczos.jpg')

引数のresampleを省略しNEARESTフィルターで縮小した画像(左)と、LANCZOSフィルターを使った画像(右)。

Pillow resize Nearest Pillow resize Lanczos

上の例では、リサイズ後の画像サイズを(256, 256)というように決め打ちしているが、元画像のサイズをもとに指定したい場合は、例えば以下のようにする。

img_resize = img.resize((img.width // 2, img.height // 2))
img_resize_lanczos.save('data/dst/lena_pillow_resize_half.jpg')

サイズは整数で指定する必要があるため、//を使っている。

一括で処理するコード例

画像の一括処理もファイル名の一括変換と同じ要領でできる。

glob()でファイルのパス文字列を取得し、それぞれをresize()でリサイズ、save()で新たなファイル名を指定して保存する。保存先のディレクトリはmakedirs()で生成する。

Joblibを用いた並列処理の例は以下の記事を参照。

特定の拡張子のファイルのみを処理

拡張子がjpgのファイルのみを抽出する例は以下の通り。

import os
import glob
from PIL import Image

dst_dir = 'data/temp/images_half'
os.makedirs(dst_dir, exist_ok=True)

files = glob.glob('./data/temp/images/*.jpg')

for f in files:
    img = Image.open(f)
    img_resize = img.resize((img.width // 2, img.height // 2))
    root, ext = os.path.splitext(f)
    basename = os.path.basename(root)
    img_resize.save(os.path.join(dst_dir, basename + '_half' + ext))

複数の拡張子のファイルを処理したい場合、例えば以下のようにすべてのファイルのパスをglob()で抽出したあとで選択する方法がある。

files = glob.glob('./data/temp/images/*')

for f in files:
    root, ext = os.path.splitext(f)
    if ext in ['.jpg', '.png']:
        img = Image.open(f)
        img_resize = img.resize((img.width // 2, img.height // 2))
        basename = os.path.basename(root)
        img_resize.save(os.path.join(dst_dir, basename + '_half' + ext))

Pillowが対応するすべての画像ファイルを処理

拡張子で抽出するのではなく、Pillowが対応する(= Image.open()で開ける)すべての画像ファイルを処理したい場合は、try ... except ...による例外処理を行う。

files = glob.glob('./data/temp/images/*')

for f in files:
    try:
        img = Image.open(f)
        img_resize = img.resize((img.width // 2, img.height // 2))
        root, ext = os.path.splitext(f)
        basename = os.path.basename(root)
        img_resize.save(os.path.join(dst_dir, basename + '_half' + ext))
    except OSError as e:
        pass

画像ファイルをすべて処理したい場合は複数の拡張子を明示的に指定するよりも楽。

関連カテゴリー

関連記事