PythonのPillowのImage.filterの使い方: 画像にフィルター(エフェクト)を適用する
目次
- PillowのImage.filterの使い方
- Image.filter()の構造
- ImageFilter
- 使用する画像
- 画像にブラー(BLUR)をかける
- 画像にエンボス(EMBOSS)をかける
- 画像を収縮(MinFilter)させる
- ソースコードの解析
- 問題
PillowのImage.filterの使い方
Pythonの画像処理ライブラリであるPillowには画像を管理するImage
モジュールがあります。
Image
モジュールは画像に指定のフィルター(エフェクト)をかける関数Image.filter()
を持っています。
また、ImageFilter
というフィルターを管理するモジュールもあり、このモジュールのフィルターをImage.filter()
に指定することで多種多様なエフェクトを画像に適用することが出来るようになります。
- Image Module — filter — Pillow (PIL Fork) 7.2.0 documentation
- ImageFilter Module — Pillow (PIL Fork) 7.2.0 documentation
Pillowには沢山のフィルターが備わっているため、このフィルターを使えば大抵のエフェクトには対応できます。
フィルターにはガウシアンブラーやメディアンフィルタ、エンボスなどがあります。
これらのフィルターはC言語で記述され、動作も早く、またPythonがバインディングしているので使い勝手もいいです。
まさにPillowのフィルターはC言語の早さとPythonの便利さを兼ね備えているわけですが、フィルターにかぎらずPillowのモジュールはたいていこの形式が取られています。
Pythonの速度の遅さをC言語でカバーしているわけですね。
Image.filter()の構造
Image.filter()
は↓のような構造になっています。
Image.filter()
は引数を1つ取り、返り値を1つ返す関数です。
引数のfilter
にImageFilter
のフィルターオブジェクトを渡すことで機能します。
Image.filter(filter)
filter(第1引数)
フィルターのカーネルです。
これはImageFilter
に列挙されているオブジェクトです。
ImageFilter()
はフィルター実行時にこのオブジェクトをインスタンス化してフィルターを実行します。
返り値
返り値はフィルター適用後の画像(Image
オブジェクト)です。
ImageFilter
ImageFilter
は画像へ適用するフィルターが列挙されているモジュールです。
開発者はこのImageFilter
から使いたいフィルターを選び、そのフィルターをImage.filter()
に渡して、フィルターを実行するというのが一般的な流れになります。
使用できるフィルター
ImageFilter
から選択できるフィルターは以下の通りです。
以下の定数的フィルタークラス(組み込みフィルター)があります。
BLUR
CONTOUR
DETAIL
EDGE_ENHANCE
EDGE_ENHANCE_MORE
EMBOSS
FIND_EDGES
SHARPEN
SMOOTH
SMOOTH_MORE
こちらのフィルターはインスタンス化の必要もなく定数のようにImage.filter()
に指定すれば使えます。
それから以下のフィルタークラス(ランクフィルター、マルチバンドフィルターなど)があります。
Kernel
RankFilter
MedianFilter
MinFilter
MaxFilter
ModeFilter
GaussianBlur
BoxBlur
UnsharpMask
Color3DLUT
こちらのフィルターはインスタンス化してパラメーターを指定して使います。
使用する画像
今回のImage.filter()
の検証には↓の画像を使います。
この画像はRGBA
で横幅500px
, 高さ500px
のPNG
画像です。
画像にブラー(BLUR)をかける
画像にブラーをかけます。ブラーとは輪郭をぼやけさせるフィルターです。
まずImage.open()
に画像のパスを指定して画像をImage
オブジェクトとして開きます。
それからそのオブジェクトのメソッドImage.filter()
を、ImageFilter.BLUE
を指定して実行します。
すると返り値としてフィルター適用後のオブジェクトが返ってきますので、Image.save()
に保存先の画像のパスを指定してこのオブジェクトを画像として保存します。
from PIL import Image, ImageFilter im = Image.open('img/a.png') # 画像を開く filter_im = im.filter(filter=ImageFilter.BLUR) # ブラーを適用 filter_im.save('dst/out1.png') # フィルターを適用した画像を保存
保存したdst/out1.png
を開くと↓のように表示されます。
画像にエンボス(EMBOSS)をかける
画像にエンボスをかける場合はImage.EMBOSS
を指定します。
from PIL import Image, ImageFilter im = Image.open('img/a.png') # 画像を開く filter_im = im.filter(filter=ImageFilter.EMBOSS) # エンボスを適用 filter_im.save('dst/out2.png') # フィルターを適用した画像を保存
出力結果。
画像を収縮(MinFilter)させる
ImageFilter.MinFilter
の使用例です。
これはインスタンス化してそのオブジェクトをImage.filter()
に渡して使用します。
from PIL import Image, ImageFilter im = Image.open('img/a.png') # 画像を開く filter_im = im.filter(filter=ImageFilter.MinFilter()) # ミンフィルターを適用 filter_im.save('dst/out3.png') # フィルターを適用した画像を保存
出力結果。
ソースコードの解析
Image.filter()
の実装は↓のようになっています。
内部的には引数のfilter
がインスタンス化できる場合はインスタンス化しています。
また、画像のバンドが1つ、またはフィルターがマルチバンドフィルターの場合と、それ以外とで処理を分けています。
どちらの場合もインスタンス化したfilter
のメソッドfilter
を呼び出しています。
つまり、フィルターのインターフェースとしてはこのfilter
メソッドを定義する必要があるわけですね。
filter
メソッドの実装はフィルターによってまちまちです。
たとえばGussianBlur
のfilter
メソッドの実装は↓のようになっています。
def filter(self, image): return image.gaussian_blur(self.radius)
Image
オブジェクトのgaussian_blur()
を呼び出しているだけです。
このgaussian_blur()
は最終的にC言語で書かれたモジュールに辿り着きます。
↑の関数から
↑の関数が呼ばれます。
ImagingGaussianBlur()
の実装を見ると内部ではImagingBoxBlur()
にパラメーターを指定して処理を委譲しています。
ImagingBoxBlur()
は以下のモード以外ではエラーを生成するのがわかります。
if (!(strcmp(imIn->mode, "RGB") == 0 || strcmp(imIn->mode, "RGBA") == 0 || strcmp(imIn->mode, "RGBa") == 0 || strcmp(imIn->mode, "RGBX") == 0 || strcmp(imIn->mode, "CMYK") == 0 || strcmp(imIn->mode, "L") == 0 || strcmp(imIn->mode, "LA") == 0 || strcmp(imIn->mode, "La") == 0)) { return ImagingError_ModeError(); }
よって↓のコードのようにモード1
の画像にImageFilter.GaussianBlur
を適用するとValueError
が生成されます。
from PIL import Image, ImageFilter im = Image.new('1', (500, 500), 0) # モード1の画像を生成 im.filter(filter=ImageFilter.GaussianBlur()) # ガウシアンブラーを適用
出力結果。
Traceback (most recent call last): File "sample.py", line 4, in <module> im.filter(filter=ImageFilter.GaussianBlur()) # ガウシアンブラーを適用 File "C:\venv_win\lib\site-packages\PIL\Image.py", line 1208, in filter return self._new(filter.filter(self.im)) File "C:\venv_win\lib\site-packages\PIL\ImageFilter.py", line 168, in filter return image.gaussian_blur(self.radius) ValueError: image has wrong mode
問題
Q1: 画像にブラーをかけたい場合に適当なフィルターを答えよ
ImageFilter.BLUR
ImageFilter.MinFilter
ImageFilter.EMBOSS
Q2: Image.filter()
の引数として適当なオブジェクトを答えよ
convertメソッドが定義されたオブジェクト
filterメソッドが定義されたオブジェクト
cropメソッドが定義されたオブジェクト
Q3: Image.filter()
の戻り値として適当なものを答えよ
int
list
Image
問題の正解はこちら↓
Q1: 1
Q2: 2
Q3: 3