はじめに
Pillowで画像の拡大縮小や回転を行う際、resampleという引数を指定することができる。例えば、以下のようなコードである。
image = Image.open("hogehoge")
rotated_image = image.rotate(angle=45, resample=Image.BICUBIC)
resampleは、画像の補間方法を指定することができる引数である。今回は画像の補間とは何なのか、補間の方法にはどんなものがあるのかをまとめたいと思う。
画像の補間とは
画像の補間とは、既存の画像を基にして新しい画像を生成するプロセスである。例えば、画像の拡大は元の画像を基にしてサイズの大きい新しい画像を生成している。画像を拡大する際、元の画像になかった画素が生成される。そのため新たに生成された画素にどのような画素値を入れるか考える必要がある。(添付画像のA, Bは拡大することで新たに生まれた画素)
画像を縮小する場合は、画素が減少するが既存の画素からどのような画素値を入れるか検討する必要がある。
このように既存の画像から新しい画像を生成するプロセスが補間であり、補間にはいくつかの方法が存在する。以降は補間の方法について説明する。
補間のアルゴリズム詳細
本記事では補間方法の中でも、最近傍補間、バイリニア補間について解説する。
最近傍補間
画像を拡大、縮小、回転した時に元画像の最近傍にある画素値をそのまま使用する方法である。単純なアルゴリズムなので処理が早いが画質が劣化しやすいという特徴がある。
拡大、縮小する場合
元画像のある座標における画素値を $I$ ,補間後の画像の画素値を$I'$、拡大率を$α$とすると補間は下式で実施される。
$$
I'(x', y') = I([\frac{x}{α}], [\frac{y}{α}])
$$
[]は四捨五入を意味する。
拡大の具体例を示す。例えば、ある画像を1.5倍に拡大する場合、補間された画像の(2, 3)の座標に当たる画素値は、元の画像の$([\frac{2}{1.5}], [\frac{3}{1.5}])=(1,2)$の座標の画素値を使用することになる。
回転する場合
$(x', y')$が回転後の座標とすると、回転元の座標$(x, y)$から下式で参照される。
$$
\begin{equation}
\begin{bmatrix}
x' \\ y'
\end{bmatrix}
= \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix}
\end{equation}
$$
$\begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix}$は回転行列であり、任意の点を$\theta$だけ回転した位置に移動させる。回転行列がなぜこのような形になるのかについては、こちらの動画がわかりやすかったので、詳しく知りたい方はこちらの動画をご覧ください。
バイリニア補間
バイリニア補間は、4つの画素値を用いて補間する画素の画素値を求める方法である。手順は下記の通り。
拡大縮小の場合
- 変換後の座標$(x', y')$を拡大率$α$で割り、$(\frac{x'}{α}, \frac{y'}{α})$を求める
- $(\frac{x'}{α}, \frac{y'}{α})$の小数部を切り捨てることで、$(x,y)$を得る
- $(x,y), (x+1,y), (x,y+1), (x+1,y+1)$とすることで、周囲4画素を得る
- $(\frac{x'}{α}, \frac{y'}{α})$との距離が大きくなるほど値が小さくなるように加重平均を算出し、変換後の画素値とする(下式)
\begin{align}
\displaylines{
I(x',y') =& (1-dx)(1-dy)I(x,y) + dx(1-dy)I(x+1, y) \\
&+ (1-dx)dyI(x,y+1) + dxdyI(x+1,y+1)
}
\end{align}
回転の場合
回転の場合も、拡大縮小の場合とほぼ同じ手順である。拡大縮小の場合は、拡大率$α$を用いて、周囲4点の画素を求めたが、回転の場合は回転行列を用いる点が異なる。
終わりに
代表的な画像の補間方法について解説した。画像の補間方法によって変換のスピードや画質に影響が出るため、それぞれの補間方法の特性を把握しておきたいと思った。本記事が皆さんの理解の一助になると嬉しく思う。
参考