HOWTO · NumPy

Python で NumPy の配列を画像として保存する

このチュートリアルでは、Python で numpy 配列を画像として保存する方法を示します

このページの内容

NumPy 配列は、Pillow、imageio、Matplotlib、OpenCV を使って画像ファイルに保存できます。適切な方法は、プロジェクトですでに使用しているライブラリと、配列内のピクセルデータの構成によって異なります。2 次元配列は一般にグレースケールのピクセルを表し、3 次元配列は一般に高さ × 幅 × チャンネル数で色チャンネルを表します。RGB データでは最後の次元が 3 チャンネルで、RGBA ではアルファチャンネルが加わります。

一般的な 8 ビット画像では、0 から 255 の値を持つ numpy.uint8 が実用的な出発点になります。浮動小数点配列の解釈やスケーリング方法はライブラリによって異なることがあるため、保存前に書き込み側が想定する値の範囲を確認してください。以下の例では、小さな配列と一時的な PNG の保存先を使用します。必要なパッケージがインストールされていない場合は、NumPy と各例で使うライブラリをインストールしてください(たとえば Pillow の場合は python -m pip install numpy pillow を実行します)。

画像出力用に NumPy 配列を準備する

画像データに合った配列形状を選びます。グレースケールなら (height, width)、RGB なら (height, width, 3)、RGBA なら (height, width, 4) が一般的です。ただし、これは書き込み側がチャンネルを最後に置く形式を想定している場合です。形状から分かるのはデータの配置であり、各チャンネルの意味までは分かりません。色付きピクセルをライブラリに渡す前に、元データのチャンネル順が RGB か BGR かを確認してください。

画像形式と使用する書き込み側の両方が対応するデータ型と数値範囲を使います。一般的な 8 ビット出力では、0 から 255 の値を持つ numpy.uint8 が広く使われています。元データが浮動小数点数だったり別の範囲を使っていたりする場合は、意図を明確にして変換またはスケーリングしてください。書き込み側によって、値のクリッピング、再スケーリング、拒否の扱いは異なります。

Image.fromarray() 関数で NumPy 配列を画像として保存する

Pillow の Image.fromarray() は配列から画像を作成し、Image.save() はそれをファイルに書き込みます。2 次元の uint8 配列はグレースケールデータを表します。カラー画像では、RGB 順の適切な 3 チャンネル配列を渡します。次の例では、小さなグレースケール配列を gray.png として保存します。

from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np
from PIL import Image

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
with TemporaryDirectory() as directory:
    output_path = Path(directory) / "gray.png"
    image = Image.fromarray(pixels)
    image.save(output_path)
    print("Saved gray.png")
Saved gray.png

一時ディレクトリを使うことで、例を単独で実行できる形にしています。カラー画像では、形状が (height, width, 3) で RGB 順の配列を使用できます。適切な 3 チャンネル配列であれば、Pillow は RGB と判定できます。

imageio.imwrite() 関数で NumPy 配列を画像として保存する

imageio.imwrite() は、最初の引数として渡したパスに配列を書き込みます。通常、ファイル名の拡張子によって書き込み側が選ばれるため、インストール済みの imageio プラグインが対応する拡張子を使ってください。この自己完結した例ではグレースケール配列を作成し、書き込みが終わるまで出力先を一時ディレクトリ内に保持します。提示された実行結果にはこの imageio の例は含まれていません。手元の環境で実行するには、NumPy と imageio をインストールしてください(たとえば python -m pip install numpy imageio を実行します)。

from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
try:
    import imageio.v2 as imageio
except ImportError:
    print("imageio is unavailable; install imageio to write the image.")
else:
    with TemporaryDirectory() as directory:
        output_path = Path(directory) / "gray.png"
        imageio.imwrite(output_path, pixels)
        print("Saved gray.png")

この用途には、imageio などの画像書き込みライブラリを使用します。過去の scipy.io.imsave() の例は、現在の使い方として紹介していません。この記事では、SciPy API の歴史や非推奨化に関する主張には依存していません。

matplotlib.pyplot.imsave() 関数で NumPy 配列を画像として保存する

Matplotlib では matplotlib.pyplot.imsave() を使って配列を直接保存できます。2 次元配列をグレースケール画像として出力するには、cmap="gray" を指定します。カラーマップを明示しない場合、Matplotlib はスカラー値を色に変換することがあります。3 チャンネルの入力は RGB として扱われます。次の例では、グレースケールの値を明示的なグレーカラーマップで保存します。

from pathlib import Path
from tempfile import TemporaryDirectory

import matplotlib.pyplot as plt
import numpy as np

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
with TemporaryDirectory() as directory:
    output_path = Path(directory) / "gray.png"
    plt.imsave(output_path, pixels, cmap="gray")
    print("Saved gray.png")
Saved gray.png

数値範囲に意味があるスカラー値を可視化する場合は、正規化方法とカラーマップを意図的に選んでください。これにより、可視化のための色付けと、元のピクセルチャンネルとを区別できます。

cv2.imwrite() 関数で NumPy 配列を画像として保存する

OpenCV の cv2.imwrite() はファイル名の拡張子からエンコーダーを選び、書き込みに成功したかどうかを真偽値で返します。特に、出力ディレクトリやコーデックを利用できない可能性がある場合は、その値を確認してください。OpenCV のカラー配列では慣例として BGR のチャンネル順を使います。保存後の色を元データと一致させたい場合は、書き込む前に RGB データを変換してください。2 次元のグレースケール配列にはチャンネル順の変換は不要です。この例では有効な出力先を作成し、戻り値が False の場合と OpenCV がインストールされていない場合の両方に、対処方法が分かるメッセージを表示します。提示された実行結果にはこの OpenCV の例は含まれていません。手元の環境で実行するには、NumPy と opencv-python をインストールしてください(たとえば python -m pip install numpy opencv-python を実行します)。

from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np

pixels = np.array([[0, 64, 128], [192, 224, 255]], dtype=np.uint8)
try:
    import cv2
except ImportError:
    print("OpenCV is unavailable; install opencv-python to write the image.")
else:
    with TemporaryDirectory() as directory:
        output_path = Path(directory) / "gray.png"
        written = cv2.imwrite(str(output_path), pixels)
        if written:
            print("Saved gray.png")
        else:
            print(f"Could not write {output_path}; check the directory and image encoder.")

RGB カラー入力の場合は、cv2.imwrite() を呼び出す前に cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR) で変換します。元データに合わせて、変換方法と配列の配置を整えてください。

出力形式を選び、画像を確認する

通常、ファイル名の拡張子によって出力形式が決まるか、形式が示されます。ただし、対応する形式やオプションはライブラリとインストール済みプラグインによって異なります。PNG は可逆圧縮で、JPEG は非可逆圧縮のため透明度を保持しません。選んだ拡張子に書き込み側が対応していることを確認してください。

OpenCV のように API が戻り値を返す場合は、その値を確認します。結果を確かめたいときは、保存したファイルを再度開き、寸法、モードまたはチャンネル数、ピクセル値を調べてください。色が予想と異なる場合は RGB/BGR のチャンネル順が原因かもしれません。グレースケール画像に色が付いている場合は、Matplotlib がカラーマップを適用した可能性があります。出力に問題があるときは、配列の形状、データ型、値の範囲、チャンネル順が書き込み側の想定と一致しているか確認してください。