ImageMagick は画像の拡大や縮小、いわゆるリサイズ処理のできるオプションが幾つがあります。

-resize, -thumbnail, -scale, -sample, -resample, -geometry。
これらのオプションと、リサイズのちょっとだけ細かい話をします。

リサイズとは?

ここではビットマップ画像の拡大や縮小処理の事とします。
画像処理的にはビットマップのグリッドの仕切り直しと捉える事ができます。

  • 拡大
src resample dst
3x3colors-dot32.png 3x3-3x3-dot16.png 3x3-3x3-dot32.png

画像の拡大を行うと、元のピクセルの位置から広げて配置し直します。
この図の空白の部分をどう埋めるのかが、補間(Interpolation)アルゴリズムです。

補間アルゴリズム

この補間アルゴリズムを ImageMagick はオプションで細かく指定出来ます。
縮小を行う際にも、どのようにピクセルを削除するか、又は混ぜるかで同様の補間処理があります。

サンプル画像

比較用サンプルとして、ドット単位のテスト画像と、実際のイラスト画を用います。

% echo  P3  3 3  9 \
 9 2 3  9 7 1  9 9 0 \
 7 4 7  7 7 4  7 9 0 \
 0 6 9  0 8 6  0 9 0 | convert - 3x3colors.png
3x3colors.png (+ ドット拡大x16)
3x3colors.png 3x3colors-dot32.png

また、水緑様のイラストから髪飾りの画像を使わせて頂きます。

ornament.png

-sample (最速)

Nearest Neighbor と呼ばれる、単純で速いアルゴリズムで処理します。
引き延ばす時には隣のピクセルをコピーし、縮小する時には単にピクセルを削除するだけです。新しい色を作らなくて済むのも大きな特徴です。
あえてドット絵のような画像を作りたい場合や、GIF や PNG8 のように色数が増えると面倒な時に便利です。

  • 拡大
% concert 3x3colors.png -sample 200% 3x3colors-sample200.png
% convert ornament.png  -sample 200% ornament-sample200.png
original -sample 200%
3x3colors.png 3x3colors-dot32.png 3x3colors-sample200.png 3x3colors-sample200-dot32.png
ornament.png ornament-sample200.png

斜めの線にドット絵のようなカクカクが付き易いです。よく、ジャギーという表現を使います。
また、元の画像にない人工的な歪みが出るのを、アーチファクトと呼びます。医療画像だと誤診を誘発する致命的なやつです。

  • 縮小
% concert 3x3colors.png -sample 50% 3x3colors-sample50.png
% convert ornament.png  -sample 50% ornament-sample50.png
original -sample 50%
3x3colors.png 3x3colors-dot32.png 3x3colors-sample50.png 3x3colors-sample50-dot32.png
ornament.png ornament-sample50.png

こちらも斜めの線がジャギーになり易いです。

-scale (次に速い)

  • 拡大
% concert 3x3colors.png -scale 200% 3x3colors-scale200.png
% convert ornament.png  -scale 200% ornament-scale200.png

拡大は -sample と同じです。

  • 縮小
% concert 3x3colors.png -sample 50% 3x3colors-scale50.png
% convert ornament.png  -sample 50% ornament-scale50.png

Pixel Mixing アルゴリズムを使います。Pixel Averaging, Area map とも呼ばれます。

縮小前のピクセルは数が多いので、それらの色の平均を使います。中途半端に重なるピクセルはカバー率で重み付けします。

original -sample 50%
3x3colors.png 3x3colors-dot32.png 3x3colors-scale50.png 3x3colors-scale50-dot32.png
ornament.png ornament-scale50.png

曲線が -sample の縮小よりも少し滑らかですが、少しボヤけます。
ジャギーさも少し残ります。

-resize (お勧め)

深く考えずに画像のサイズを変えたいときは、-resize を使うと良いでしょう。

  • 拡大
% convert 3x3colors.png -resize 200% 3x3colors-resize200.png
% convert ornament.png  -resize 200% ornament-resize200.png

Bi-Cubic Family の中でバランスの良いと言われる Mitchell フィルタを用います。

original -resize 200%
3x3colors.png 3x3colors-dot32.png 3x3colors-resize200.png 3x3colors-resize200-dot32.png
ornament.png ornament-resize200.png

滑らかに拡大出来ます。ただし結構ボヤけます。

  • 縮小
% convert 3x3colors.png -resize 50% 3x3colors-resize50.png
% convert ornament.png  -resize 50% ornament-resize50.png

Lanzcos フィルタを用います。(ただし、パレット画像 or 透明度がついてる場合には縮小でも Mitchell を適用)
エイリアシング対策のされたフィルタです。アーチファクトノイズが乗りにくいのが特徴です。

original -sample 50%
3x3colors.png 3x3colors-dot32.png 3x3colors-resize50.png 3x3colors-resize50-dot32.png
ornament.png ornament-resize50.png

滑らかに縮小しますが、こちらも画像がボヤけます。

-resize & -unsharp

-resize のボケ対策に、unsharp を併せて使うと良いです。

% convert ornament.png  -resize 200% -unsharp 10x5+0.7+0  ornament-resize200-unsharp.png
% convert ornament.png  -resize 50% -unsharp 10x5+0.7+0  ornament-resize50-unsharp.png

(unsharp のパラメータは自分の好みもありますが、分かりやすいように少し強めにしてます。2015年当時の GIMP は 12x6+0.5+0 だそうです > http://freeparticle.hatenablog.com/entry/2015/01/16/230956)

  • 拡大
original -resize 200% -unsharp 10x5+0.5+0
ornament.png ornament-resize200.png ornament-resize200-unsharp.png
  • 縮小
original -sample 50% -unsharp 10x5+0.5+0
ornament.png ornament-resize50.png ornament-resize50-unsharp.png

なお、シャープ(sharpness)にするのに unsharp という単語を使うのは、アナログ写真の時代に行われた unsharp-masking (USM) に由来します。わざとボケたネガ画像のマスクを作り、それを合成する事でボケを相殺するそうです。

-thumbnail (メタデータ削除)

画像の変換アルゴリズムは -resize と同じですが、Exif 等のメタデータを削除します。
Exif には撮影位置や(画像上書き前の)サムネール画像が入る事もあるので、不特定多数に公開する、又は漏れる可能性のある写真では削った方が身の為です。

-resample (dpi合わせ)

指定した dpi 値でメタデータの dpi を上書きすると同時に、その変化に合わせて画像サイズをリサイズします。

dpi って?

dpi は物理的な解像度で、1 inch に何ドット詰めるかの単位です。
例えば、画像をプリンタで印刷するときに、dpi に応じて大きさが決まりますし、
WYSIWYG(ウィジウィグ) 環境ではモニタ表示にも影響します。

具体例

例えば、Retina ディスプレイでスクリーンショットをとると、解像度が既存の倍の 144 dpi で記録されます。

% identify ss.png
ss.png PNG 1064x560 1064x560+0+0 8-bit sRGB 120732B 0.000u 0:00.000
% identify -verbose  ss.png | grep -A 2 Resol
  Resolution: 56.69x56.69
  Print size: 18.7687x9.87829
  Units: PixelsPerCentimeter

Resolution が cm 単位なので inch に変換すると、56.69[px/cm] * 2.54 [cm/inch] = 144 [px/inch]

これを既存モニタ向けの 72dpi 相当に簡単に変換できます。inch 指定、デフォルトの cm指定、 どちらでも良いです。

% convert ss.png -resample 28.35  ss2.png
% convert ss.png -units PixelsPerInch -resample 72  ss3.png
% identify ss2.png ss3.png
ss2.png PNG 532x280 532x280+0+0 8-bit sRGB 43726B 0.000u 0:00.000
ss3.png PNG 532x280 532x280+0+0 8-bit sRGB 43726B 0.000u 0:00.000

-geometry

このオプションでもリサイズ出来ますが、利用はおすすめ出来ません。

ImageMagick は convert 以外にも色んなコマンドがあって、各々で -geometry が違う意味を持たされている多義的なオプションです。よくない。

Geometry is a very special option.
The operator behaves slightly differently in every IM command, and often in special and magical ways.
The reasons for this is mostly due to legacy use and should be avoided if at all possible.

歴史的な都合でコマンド毎に違う動作をするので、出来る限り使うのは避けてね。と公式にもあります。

-filter 付きで -resize

-filter で任意の補間フィルタを適用できます。

-point, -scale, -resize と -filter 〜 の関係

option -filter (enlarge/reduce)
-sample point
-scale point / triangle(と似てる pixel mixing)
-resize mitchell / lanczoc

補間フィルタ一覧

-list filter でフィルタの一覧が出るので、全種類を簡単に試せます。

for f in `convert -list filter` ; do convert koishi.png -filter $f -resize 10%  filter/$f.png ; done

スクリーンショット 2018-02-06 0.39.15.png

これを見るだけでも、縮小には Lanczos が良さそうな感じがします。

filter:verbose=1

-define filter:verbose=1 をつけると、実際に適用されるアルゴリズム名や詳細なパラメータ、実際に補間する時の重み付け数列を確認出来ます。

% convert in.png -define filter:verbose=1 -filter box -resize 100x100 out.png
# Resampling Filter (for graphing)
#
# filter = Box
# window = Box
# support = 0.5
# window-support = 0.5
# scale-blur = 1
# practical-support = 0.5

 0.00   1
 0.01   1
 0.02   1
<略>
 0.49   1
 0.50   1
 0.50   0

グラフ

出力された数列は補間する際の重み付けで使う値です。
アルゴリズム別にグラフにしてみます。

% # Nearest Neighbor
% convert logo: -define filter:verbose=1 -filter box      -resize 100% null:
% # Bi-Linear
% convert logo: -define filter:verbose=1 -filter triangle -resize 100% null:
% # Bi-Cubic (B:1/3,C:1/3 - Mitchell)
% convert logo: -define filter:verbose=1 -filter mitchell -resize 100% null:
% # Lanczos (Lobe:3)
% convert logo: -define filter:verbose=1 -filter lanczos -resize 100% null:

Interpolation-Functions.png

  • box は 0 か 1 か。ピクセルを混ぜない。
  • triangle は線形でピクセルを混ぜる。0 と 1 で傾きが急に変化するのが欠点。
  • mitchell は更に一個外のピクセルまで考慮して triangle の欠点を補う。
  • lanczos は mitchell の更に。と言いたいけど、そこは本質でなく sinc で LPF をかけてる。

詳しくはこちらの解説が図付きで分かりやすいです。

-filter cubic

cubic フィルタを指定すると Bi-Cubic として知られるアルゴリズムで補間します。
box(Nearest-Neighbor) や triangle(Bi-Linear) は2点の輝度値から計算しますが、Bi-Cubic は更にもう一つ外を含め4点を使う事で滑らかに補間できます。

Bi-Cubic.png
転載元) https://en.wikipedia.org/wiki/Bicubic_interpolation

Bi-Cubic は B(blur, basis?) と C(cardinal) のパラメータを 0〜1 の間で調整して色々なフィルタを作り出せます。
Cubic ファミリーといった呼び方もされ、B,C に応じて以下のようなフィルタが存在します。

name B C
Hermite 0 0
General 1 0
Catmull-Rom 0 1/2
Mitchell 1/3 1/3

対応するソースコードは、MagickCore/resize.c にあります。

スクリーンショット 2018-03-20 17.17.20.png

B,C の 0,1 を組み合わせた、重み付け数列のグラフです。
図1.png

Bi-Cubic は B:0, C:0 だと Nearest-Neighbor と Bi-Liner の合いの子位の性能で、あまりジャギーを隠せません。そこで B や C の値を上げて調整します。

B (blue)

B:1 のグラフです。
図2.png
青い線が B:1, C:0 に対応します。

convert ornament.png  -filter cubic \
        -define filter:b=1 \
        -define filter:c=0 \
        -resize 200% ornament-cubic-1-0-200.png

ornament-cubic-1-0-200.png

単純にぼやけてますね。

C (cardinal)

C:1 のグラフです。
図3.png
緑の線が B:0, C:1 に対応します。

convert ornament.png  -filter cubic \
        -define filter:b=0 \
        -define filter:c=1 \
        -resize 200% ornament-cubic-0-1-200.png

ornament-cubic-0-1-200.png

こちらは絵がくっきりしますが、本物の輪郭と平行してニセの輪郭が現れています。

ornament-cubic-0-1-200のコピー.png

太くて黒い線の隣に元には無かった白い線が追加されてますね。

このように、B と C は単に大きくすれば良い訳ではありません。

Mitchell

拡大する時にフィルタ窓の関係で発生するブロックノイズ(Blocking)をとりたいのですが、B を増やすとブラー(Blur)がかかり、C を増やすとリンギング(Ringing)が発生し、B,C 両方でエイリアシング(Aliasing)が目立ってくるので、それらのバランスをとって B:1/3, C:1/3 の値を採用したのが Mitchell-Netravali フィルタです。

当てずっぽうに決めたのでなく、実際に主観的テストであらわれた傾向を元に決めています。
image.png
- 転載元) http://www.imagemagick.org/Usage/filter/#mitchell
- 論文) https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf

いい感じに変換出来たパラメータを点線で示していて、そのうち Mitchell と矢印で示されたポイントが B:1/3, C:1/3 です。

最後に

フィルタについて語りたい事が山ほどありますが、エントリが更に倍以上に膨らむのでもし需要があれば別エントリで書きます。window や offset に言及してないのも中途半端な気がしますし。

参考