59

ネイティブのガウスぼかし式を使用して画像をぼかしたいです。ウィキペディアの記事を読みましたが、これを実装する方法がわかりません。

数式を使用して重みを決定するにはどうすればよいですか?

MATLAB のような組み込み関数を使用したくない

4

5 に答える 5

137

素朴なガウスぼかしを書くのは実際にはかなり簡単です。これは、他の畳み込みフィルターとまったく同じ方法で実行されます。ボックスとガウスフィルターの唯一の違いは、使用する行列です。

次のように定義された画像があるとします。

 0  1  2  3  4  5  6  7  8  9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

3x3ボックスフィルター行列は次のように定義されます。

0.111 0.111 0.111
0.111 0.111 0.111
0.111 0.111 0.111

ガウスぼかしを適用するには、次のようにします。

ピクセル11の場合、ピクセル0、1、2、10、11、12、20、21、22をロードする必要があります。

次に、ピクセル0に3x3ブラーフィルターの左上部分を掛けます。ピクセル1は上部中央、ピクセル2、ピクセル3は右上、ピクセル10は中央左などです。

次に、それらをすべて追加し、結果をピクセル11に書き込みます。ご覧のとおり、ピクセル11はそれ自体と周囲のピクセルの平均になります。

エッジケースはもう少し複雑になります。テクスチャのエッジの値にはどのような値を使用しますか?1つの方法は、反対側に折り返すことです。これは、後で並べて表示される画像に適しています。もう1つの方法は、ピクセルを周囲の場所に押し込むことです。

したがって、左上のサンプルは次のように配置できます。

 0  0  1
 0  0  1
10 10 11

これを大規模なフィルターカーネル(つまり、5x5または9x9など)に簡単に拡張できる方法を理解していただければ幸いです。

ガウスフィルターとボックスフィルターの違いは、行列に含まれる数値です。ガウスフィルターは、行と列にわたるガウス分布を使用します。

たとえば、任意に定義されたフィルターの場合(つまり、これはガウス分布ではありませんが、おそらくそれほど遠くはありません)

0.1 0.8 0.1

最初の列は同じですが、上の行の最初の項目に乗算されます。

0.01 0.8 0.1
0.08 
0.01 

2番目の列は同じですが、値は上の行の0.8で乗算されます(以下同様)。

0.01 0.08 0.01
0.08 0.64 0.08
0.01 0.08 0.01

上記のすべてを合計した結果は1に等しくなります。上記のフィルターと元のボックスフィルターの違いは、書き込まれた終了ピクセルの重みが中央のピクセル(つまり、その位置にあるピクセル)に向かってはるかに大きくなることです。すでに)。ぼけは、周囲のピクセルがそのピクセルにぼかすために発生しますが、それほどではありません。この種のフィルターを使用すると、ぼやけが生じますが、高周波(つまり、ピクセルからピクセルへの色の急速な変化)情報の多くを破壊することはありません。

これらの種類のフィルターは、多くの興味深いことを行うことができます。現在のピクセルから周囲のピクセルを差し引くことにより、この種のフィルターを使用してエッジ検出を行うことができます。これにより、色の非常に大きな変化(高周波)のみが残ります。

編集:5x5フィルターカーネルは上記とまったく同じように定義されています。

たとえば、行が0.1 0.2 0.4 0.2 0.1の場合、各値に最初の項目を掛けて列を形成し、次にそれぞれに2番目の項目を掛けて2番目の列を形成すると、フィルターが作成されます。の

0.01 0.02 0.04 0.02 0.01
0.02 0.04 0.08 0.04 0.02
0.04 0.08 0.16 0.08 0.04
0.02 0.04 0.08 0.04 0.02
0.01 0.02 0.04 0.02 0.01

任意の位置を取ると、位置0、0は単純な0.1*0.1であることがわかります。位置0、2は0.1 * 0.4、位置2、2は0.4 * 0.4、位置1、2は0.2*0.4です。

それがあなたに十分な説明を与えることを願っています。

于 2009-11-08T12:09:05.977 に答える
11

カーネルを計算するために C# で使用したコードの擬似コードを次に示します。ただし、終了条件を正しく扱っているとは言いません。

double[] kernel = new double[radius * 2 + 1];
double twoRadiusSquaredRecip = 1.0 / (2.0 * radius * radius);
double sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * Math.PI) * radius);
double radiusModifier = 1.0;

int r = -radius;
for (int i = 0; i < kernel.Length; i++)
{
    double x = r * radiusModifier;
    x *= x;
    kernel[i] = sqrtTwoPiTimesRadiusRecip * Exp(-x * twoRadiusSquaredRecip);
    r++;
}

double div = Sum(kernel);
for (int i = 0; i < kernel.Length; i++)
{
    kernel[i] /= div;
}

お役に立てれば。

于 2009-11-08T12:33:43.813 に答える
9

ウィキペディアの記事で説明されているフィルター カーネルを使用するには、(離散)畳み込みを実装する必要があります。アイデアは、値の小さなマトリックス (カーネル) があり、このカーネルを画像内のピクセルからピクセルに移動し (つまり、マトリックスの中心がピクセル上になるように)、マトリックス要素にオーバーラップした画像を掛けることです。結果のすべての値を合計し、古いピクセル値をこの合計で置き換えます。

ガウスぼかしは、2D 畳み込みの代わりに 2 つの 1D 畳み込み (垂直方向と水平方向に 1 つ) に分離できるため、処理が少し高速になります。

于 2009-11-08T12:00:41.947 に答える
3

これを特定のテクノロジーに制限するかどうかはわかりませんが、制限しない場合は、 SVG(ScalableVectorGraphics)にガウスぼかしが実装されています。ピクセルを含むすべてのプリミティブに適用されると思います。SVGには、オープンスタンダードであり、広く実装されているという利点があります。

于 2009-11-08T11:48:28.487 に答える