web-dev-qa-db-ja.com

画像ダウンサンプリングアルゴリズム

画像を元のサイズの半分に分割するために使用できる最良のリサンプリングアルゴリズムは何ですか。速度が最も重要ですが、品質をそれほど悪くすることはありません。私は基本的に画像ピラミッドを生成しようとしています。

私はもともとピクセルをスキップすることを計画していました。これが最善の方法ですか?私が読んだところによると、ピクセルスキップによって生成された画像は鮮明すぎます。このコメントを試した人はいますか?私の画像には、 this。 のようなマップデータが含まれています

19
sleeping.ninja

ピクセルをスキップするとエイリアシングが発生し、高周波数の変化(明るい/暗いバンドの交互など)が低周波数(一定の明るいまたは暗いなど)に変換されます。

エイリアシングなしで半分に縮小する最も簡単な方法は、2x2ピクセルを平均して1つのピクセルにすることです。より洗練されたリダクションカーネルを使用すると、より良い結果を得ることができますが、速度が犠牲になります。

編集:これまでに説明した手法の例をいくつか示します。

1ピクセルおきにスキップします。左側の凡例を見ると、結果があまり良くないことがわかります。それはほとんど読めません:

Skipping every other pixel

2x2グリッドごとの平均化-テキストがシャープで読みやすくなりました。

Average 2x2

R。 -によって示唆されるように、ガウスぼかしは少しぼやけていますが、ある程度までは読みやすくなっています。ぼかしの量を調整して、さまざまな結果を得ることができます。

enter image description here

R。 は、結果に影響を与えるガンマ曲線についても正しいですが、これは最も要求の厳しいアプリケーションでのみ表示されるはずです。私の例はガンマ補正なしで行われました。

28
Mark Ransom

ダウンスケーリングの場合、面積平均(マークの回答を参照)は、得られる最良のものに近いものです。

他の主な候補はガウス分布で、半径がわずかに大きくなっています。これにより、ブラーが少し増加します。これは不利な点と見なされる可能性がありますが、ピクセルmod 2の配置に依存するのではなく、ブラーをより均一にします。

意味がすぐにわからない場合は、ピクセルパターン0,0,2,2,0,0と0,0,0,2,2,0を検討してください。エリア平均を使用すると、それぞれ0,2,0と0,1,1にダウンスケールされます。つまり、一方はシャープで明るく、もう一方はぼやけて暗くなります。より長いフィルターを使用すると、両方がぼやけますが、より類似しているように見えます。これはおそらく人間の観察者にとって重要です。

考慮すべきもう1つの問題はガンマです。ガンマが線形でない限り、強度kの2つのピクセルは、強度2*kの1つのピクセルよりも合計強度がはるかに低くなります。フィルタが十分なぼかしを実行する場合、それはそれほど重要ではないかもしれませんが、単純な面積平均フィルタでは、それは大きな問題になる可能性があります。私が知っている唯一の回避策は、スケーリングの前後にガンマ曲線を適用して反転させることです...

6
R..

前述のように、速度が問題になる場合は、2x2ブロックを取得し、結果のピクセルとして平均を計算することをお勧めします。品質は達成できる最高のものではありませんが、それに近いものです。このアルゴリズムを誘発してその弱点を示すことはできますが、ほとんどの画像では、何倍も高い計算時間を正当化するような違いは見られません。また、メモリのオーバーヘッドもありません。色解像度をチャネルあたり6ビットに下げることができる場合は、ARGBチャネル(ここでは32ビットARGBを想定)を分解しないようにする非常に高速な方法があります。

destPixel[x,y] = ((sourcePixel[2*x  ,2*y  ]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x+1,2*y  ]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x  ,2*y+1]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x+1,2*y+1]>>2)&0x3f3f3f3f);

このアルゴリズムの副作用は、PNGとして保存すると、ファイルサイズが小さくなることです。これはどのように見えるかです: Test image downscaled with the above algorithm

4
Thilo Köhler

私はThiloKöhlerのソリューションを一般化しようとしました(ただしPythonで):

STRIDE = 2
MASK = 0x3F3F3F3F
color = 0
for Δx, Δy in itertools.product(range(STRIDE), repeat=2):
    color += (get_pixel(x + Δx, y + Δy) // STRIDE) & MASK

これは、2(1/4サイズの結果)によるスケーリングでは正常に機能しますが、3または4またはその他のint値によるスケーリングでは機能しません。これを一般化することは可能ですか?

ところで、Pythonista以外の場合、上記のforループはこれと同等です(ただし、最初のバージョンはSTRIDEを変更することでスケーラブルです)。

for Δx, Δy in [(0, 0), (0, 1), (1, 0), (1, 1)]:
    color += (get_pixel(x + Δx, y + Δy) // STRIDE) & MASK

32ビットのARGB値を使用しています。

2

NetPBMスイート には pamscale というユーティリティが含まれており、ダウンサンプリングのオプションがいくつか用意されています。これはオープンソースであるため、さまざまなオプションを試してから、最も気に入ったアルゴリズムをコピーできます(またはlibnetpbmを使用するだけです)。

1
Nemo
0
Seth Robertson