画像の拡大・縮小(resize)
pythonで画像をリサイズ(拡大・縮小)する方法を紹介します。
今回は
- cv2.resize()によるリサイズ
- アフィン変換によるリサイズ
- PILのresizeによるリサイズ
開発環境はjupyter notebook、言語はpythonです。
今回使用した画像・コード一式はgoogle driveにも保存しておりますので、必要に応じてお使いください。
作成したコード
#モジュールのインポート import cv2 import glob import numpy as np import matplotlib.pyplot as plt import os from PIL import Image %matplotlib inline #affine変換によるリサイズ用def文 def resize_affine(path,ratio): img = cv2.imread(path) h, w = img.shape[:2] src = np.array([[0.0, 0.0],[0.0, 1.0],[1.0, 0.0]], np.float32) dest = src * ratio affine = cv2.getAffineTransform(src, dest) img3 = cv2.warpAffine(img, affine, (int(float(w)*ratio), int(float(h)*ratio)), cv2.INTER_LANCZOS4) cv2.imwrite(os.path.split(path)[1][:-4]+"_resize_affine_"+str(ratio)+".bmp",img3) return #PILによるリサイズ用def文 def resize_PIL(path,ratio): img = Image.open(path) w,h = img.size img_resize = img.resize((int(float(w)*ratio),int(float(h)*ratio)),Image.LANCZOS) img_resize.save(os.path.split(path)[1][:-4]+"_PIL_"+str(ratio)+".bmp") return #画像の読み込み filename = glob.glob("*.jpg") img = cv2.imread(filename[0]) plt.imshow(img) #拡大倍率の指定 ratio = 0.5 for n in range(len(filename)): img = cv2.imread(filename[n]) #パターン1:cv2.resize()によるリサイズ img_cv2resize = cv2.resize(img, dsize=None, fx=ratio, fy=ratio,interpolation=cv2.INTER_LANCZOS4) cv2.imwrite(os.path.split(filename[n])[1][:-4]+"_cv2resize_"+str(ratio)+".bmp",img_cv2resize) #パターン2:アフィン変換によるリサイズ resize_affine(filename[n],ratio) #パターン3:PILによるリサイズ resize_PIL(filename[n],ratio)一応、プログラムと同ディレクトリに入れたjpgファイルに対して、3種類の処理が一気に実行されるよう記述しております。
また、今回は元の画像の大きさを縦横ともに0.5倍になるよう設定していますが、アス比も自由に設定できるのでカスタマイズしてみてください。
処理の解説
1. cv2.resize()によるリサイズ
用いたプログラムはこちらです。ratio = 0.5 cv2.resize(img, dsize=None, fx=ratio, fy=ratio,interpolation=cv2.INTER_LANCZOS4)
今回はfxとfyに拡大率(ratio)である0.5を入力することで、画像の大きさを半分にしています。
さらに、interpolationによってデータの不足部分を補完する方法を指定しています。
使用できる補間法は以下の表にまとめています。
具体的な解説は省略しますが、表の下の補間法ほど、補間精度が高くなる(画質が悪くなりにくい)と考えてください。
また、下記のようdsizeを書き換えて、指定の高さhと幅wを持つ画像にリサイズすることができます。
さらに、interpolationによってデータの不足部分を補完する方法を指定しています。
使用できる補間法は以下の表にまとめています。
具体的な解説は省略しますが、表の下の補間法ほど、補間精度が高くなる(画質が悪くなりにくい)と考えてください。
また、下記のようdsizeを書き換えて、指定の高さhと幅wを持つ画像にリサイズすることができます。
w,h = img.shape[:2] cv2.resize(img, dsize=(w,h))この方法は紹介した3つの手法の中では最も使用しやすいコマンドかなと思います。
2. affine変換によるリサイズ
使用したプログラムは下記の通りです。def resize_affine(path,ratio): img = cv2.imread(path) h, w = img.shape[:2] src = np.array([[0.0, 0.0],[0.0, 1.0],[1.0, 0.0]], np.float32) dest = src * ratio affine = cv2.getAffineTransform(src, dest) img3 = cv2.warpAffine(img, affine, (int(float(w)*ratio), int(float(h)*ratio)), cv2.INTER_LANCZOS4) cv2.imwrite(os.path.split(path)[1][:-4]+"_resize_affine_"+str(ratio)+".bmp",img3) return本プログラムは変数srcから変数destへと、cv2.getAffine()とcv2.warpAffine()を使って変換する処理になります。
下図を見ていただけると処理のイメージが湧きやすいと思います。
画像上の3点の座標を、変換前(src)と変換後(dest)でどのように移動させるか指定するという感じですね。
affine変換によるリサイズの模式図
ここの設定を誤ると黒い余白(黒いのに余白というのも変な感じですが・・・)ができたり、画像が切り出されてしまうので注意です。
見た感じ、3手法の中で最も画質が悪かったのですが、affine変換だとリサイズ以外にも並進なども同時にできるので、利用する頻度は多いかもしれません。
3. PILによるリサイズ
使用したプログラムは以下の通りです。
上2つの手法と流れは大して変わらないので説明はいらないと思います。#PILによるリサイズ用def文 def resize_PIL(path,ratio): img = Image.open(path) w,h = img.size img_resize = img.resize((int(float(w)*ratio),int(float(h)*ratio)),Image.LANCZOS) img_resize.save(os.path.split(path)[1][:-4]+"_PIL_"+str(ratio)+".bmp") return
ただ、interpolationの指定方法が少し違いますね。
PILでは下記の6つ手法がinterpolationとして使用できるそうです。
- NEAREST
- BOX
- BILINEAR
- HAMMING
- BICUBIC
- LANCZOS
3手法全てにおいて、ランツォシュでリサイズしてみましたが、なぜかこのPILによるリサイズが最も画質が良かったです。あまりPILは便利だと思わないですが、使ってみる価値はありそうです。
今回使用した画像:鴨らぁめん/らーめん 鴨 to 葱
基本パワポで図を作っているので、リサイズの処理に説得力を出せず、今回はトップ画のみの登場となりました。
鴨と葱の旨味が詰まった最高のラーメンでした。ここはリピートしたいと思っています。
コメント
コメントを投稿