リンク
・
画像の変換(目次ページ)
『拡大・縮小』関連
・
画像の縮小
・
画像の拡大「Nearest Neighbor法」
・
画像の拡大「Bilinear法」
・
画像の拡大「Bicubic法」
・
画像の拡大「Lanczos法」
・画像の拡大-距離計算に関する考察
・
超解像
ここまで、Bilinear法、Bicubic法、Lanczos法、すべて
「X方向の距離とY方向の距離を求め、それぞれのウェイト計算をし、
X方向のウェイトとY方向のウェイトを掛ける。」
という手法をとってきました。
しかし、距離と言えば、X方向やY方向ではなく直線距離のはず。
つまり、デジカメであれば、カメラを傾ける事でX軸Y軸は傾くし、
スキャナーだって対象の角度を変えれば傾く。
X軸やY軸の方向は、人間が処理の都合で後から付けたもの。
画像の拡大にとって、
「そのような後付けの軸方向に左右されるべきものなのだろうか。」
「直線距離で計算するのが正しいのでは?」
そんな素朴な疑問がわいてきました。
では、実際に試して確認してみましょう。
用いたのは3つのテストデータ。
テストデータ1 (弱エッジ) |
緩やかに変化するグラデーションデータ |
テストデータ2 (強エッジ) |
白黒パターン |
テストデータ3 (ワイングラス) |
実写データ |
|
テストデータ1 (弱エッジ) |
128x128 → 240x320
まず最初に用いたのはこの同心円状のデータ。
何かのテストチャート、という訳ではなく、
私が適当に作ったデータです。
左下を中心にして、白黒レベルが波のようになっています。
右上部の波が密になった場所で灰色の楕円が幾つか見えますが、
これは、各ピクセルの形が四角形なため、副二次的に発生したモアレです。
左上隅と右下隅にも同様の傾向が見られます。
|
Nearest Neighbor |
『Nearest Neighbor法』は「ウェイト」という考え方はありません。
ここでは、比較のために載せています。
|
|
Bilinear
weight = weight_x * weight_y
weight_x = bilinear_weight( dx )
weight_y = bilinear_weight( dy ) |
Bilinear
weight = bilinear_weight( d )
d = √( dx2 + dy2 ) |
左側(←)は、X方向、Y方向それぞれのウェイトを掛ける従来の方法。
右側(→)は、直線距離でウェイトを求める方法です。
「Bilinear法」は参照ピクセルが 2x2 ピクセルなので、
その程度では、ほとんど差が出ません。
|
|
Bicubic
weight = weight_x * weight_y
weight_x = bicubic_weight( dx )
weight_y = bicubic_weight( dy ) |
Bicubic
weight = bicubic_weight( d )
d = √( dx2 + dy2 ) |
左側に比べ、右側がくっきりしている事がわかります。
「シャープネス・フィルタがより強く掛かっている」という認識で良いと思います。
しかし、右側の画像のグラデーション部分(左下4分の1の領域)を見ると
四角いブロック状のノイズ(モザイク・ノイズ)が出ている事が分かります。
その点に注意して左側の同じ位置を(じっくり)見ると、
うっすらとですが、ブロック状のノイズが出ている事が分かります。
|
|
Lanczos2
weight = weight_x * weight_y
weight_x = lanczos_weight( dx, 2 )
weight_y = lanczos_weight( dy, 2 ) |
Lanczos2
weight = lanczos_weight( d, 2 )
d = √( dx2 + dy2 ) |
右側の画像の中央部分のシマシマを見ると、左側よりもくっきりしているようです。
Lanczos2 に関しては、直線距離で行った方がシャープネス・フィルタが掛かる
と言ってよいでしょう。
|
|
Lanczos3
weight = weight_x * weight_y
weight_x = lanczos_weight( dx, 3 )
weight_y = lanczos_weight( dy, 3 ) |
Lanczos3
weight = lanczos_weight( d, 3 )
d = √( dx2 + dy2 ) |
中央部分のシマシマを見ると、左側よりも右側の方がくっきりしています。
同じく中央部分の、同心円のカーブの滑らか具合を Lanczos2、Lanczos3 で比較
すると、Lanczos3 の方が優れているようです。
次に、別のパターンで拡大方法の違いを見てみましょう。
|
テストデータ2 (強エッジ) |
64x32 → 180x120
このパターンはエッジが強い画像(輝度が白→黒とレベル差が大きい画像)です。
|
Nearest Neighbor |
「Nearest Neighbor 法」はエッジのレベル差は維持されているものの、
中央部分の細いシマシマを見ると、線の幅が不正確である事がわかります。
|
|
Bilinear
weight = weight_x * weight_y
weight_x = bilinear_weight( dx )
weight_y = bilinear_weight( dy ) |
Bilinear
weight = bilinear_weight( d )
d = √( dx2 + dy2 ) |
「Bilinear 法」は左側、右側、あまり差が無く、
どちらもボケている事が分かります。
(よくよく見ると、右側にノイズが出ています。)
|
|
Bicubic
weight = weight_x * weight_y
weight_x = bicubic_weight( dx )
weight_y = bicubic_weight( dy ) |
Bicubic
weight = bicubic_weight( d )
d = √( dx2 + dy2 ) |
「Bicubic 法」は左側よりも右側の方がくっきりしています。
しかし、白の四隅、黒の四隅で形が崩れている事がわかります。
|
|
Lanczos2
weight = weight_x * weight_y
weight_x = lanczos_weight( dx, 2 )
weight_y = lanczos_weight( dy, 2 ) |
Lanczos2
weight = lanczos_weight( d, 2 )
d = √( dx2 + dy2 ) |
「Lanczos2」は左側より右側がくっきりしています。
|
|
Lanczos3
weight = weight_x * weight_y
weight_x = lanczos_weight( dx, 3 )
weight_y = lanczos_weight( dy, 3 ) |
Lanczos3
weight = lanczos_weight( d, 3 )
d = √( dx2 + dy2 ) |
「Lanczos3」の右側はエッジの反射(折り返し)がノイズとなって出ています。
それを踏まえて左側を見ると、同じ位置にうっすらとノイズが分かります。
次に実写で違いを見てみましょう。
|
テストデータ3 (ワイングラス) |
160x120 → 384x256 (下記の拡大結果は一部を切り出し)

|
Nearest Neighbor |
「Nearest Neighbor」はブロック状(モザイク状)になります。

|

|
Bilinear
weight = weight_x * weight_y
weight_x = bilinear_weight( dx )
weight_y = bilinear_weight( dy ) |
Bilinear
weight = bilinear_weight( d )
d = √( dx2 + dy2 ) |
「Bilinear」では、左側、右側で大した違いはありません。

|

|
Bicubic
weight = weight_x * weight_y
weight_x = bicubic_weight( dx )
weight_y = bicubic_weight( dy ) |
Bicubic
weight = bicubic_weight( d )
d = √( dx2 + dy2 ) |
「Bicubic」では右側がくっきりしています。
しかし、グラスにうつった照明の反射(水面と縁の間)を見ると、
グラデーション部分にブロックノイズが出ている事が分かります。
シャープネス・フィルタ特性が強すぎるのではないかと思います。

|

|
Lanczos2
weight = weight_x * weight_y
weight_x = lanczos_weight( dx, 2 )
weight_y = lanczos_weight( dy, 2 ) |
Lanczos2
weight = lanczos_weight( d, 2 )
d = √( dx2 + dy2 ) |
「Lanczos2」右側の方がくっきりしています。

|

|
Lanczos3
weight = weight_x * weight_y
weight_x = lanczos_weight( dx, 3 )
weight_y = lanczos_weight( dy, 3 ) |
Lanczos3
weight = lanczos_weight( d, 3 )
d = √( dx2 + dy2 ) |
「Lanczos3」右側の方がくっきりしています。
このワイングラス、グラスの側面にブドウの模様がほどこされています。
拡大後、この模様がちゃんと出ているのは Bicubic, Lanczos2, Lanczos3 の右側
でしょう。
総合的に判断すると、
画質という意味では Lanczos2 の右側(直線距離で計算)が最もバランスが
とれているように思います。
ただし、Lanczos2 を直線距離で処理すると、
出力側の各ピクセルに対して 16 ピクセルを参照するため、
1ピクセルあたり、平方根(√)の計算が 16 回発生する事になり、
計算量がとんでもない事になります。
【まとめ】
|
( X方向ウェイト)*( Y方向ウェイト) |
(直線距離ウェイト) |
Bilinear |
△ぼける |
←と大差なし △ぼける |
Bicubic |
△ぼける |
△画質は改善
×グラデーションにブロックノイズ
×処理が重い (√計算 16回 / pixel) |
Lanczos2 |
△ぼける |
○画質は改善 (バランスがとれている)
×処理が重い (√計算 16回 / pixel) |
Lanczos3 |
△ぼける |
△画質は改善 ×エッジ部分で折り返し
×処理が重い (√計算 36回 / pixel) |