ネイティブのガウスぼかし式を使用して画像をぼかしたいです。ウィキペディアの記事を読みましたが、これを実装する方法がわかりません。
数式を使用して重みを決定するにはどうすればよいですか?
MATLAB のような組み込み関数を使用したくない
ネイティブのガウスぼかし式を使用して画像をぼかしたいです。ウィキペディアの記事を読みましたが、これを実装する方法がわかりません。
数式を使用して重みを決定するにはどうすればよいですか?
MATLAB のような組み込み関数を使用したくない
素朴なガウスぼかしを書くのは実際にはかなり簡単です。これは、他の畳み込みフィルターとまったく同じ方法で実行されます。ボックスとガウスフィルターの唯一の違いは、使用する行列です。
次のように定義された画像があるとします。
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です。
それがあなたに十分な説明を与えることを願っています。
カーネルを計算するために 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;
}
お役に立てれば。
ウィキペディアの記事で説明されているフィルター カーネルを使用するには、(離散)畳み込みを実装する必要があります。アイデアは、値の小さなマトリックス (カーネル) があり、このカーネルを画像内のピクセルからピクセルに移動し (つまり、マトリックスの中心がピクセル上になるように)、マトリックス要素にオーバーラップした画像を掛けることです。結果のすべての値を合計し、古いピクセル値をこの合計で置き換えます。
ガウスぼかしは、2D 畳み込みの代わりに 2 つの 1D 畳み込み (垂直方向と水平方向に 1 つ) に分離できるため、処理が少し高速になります。
これを特定のテクノロジーに制限するかどうかはわかりませんが、制限しない場合は、 SVG(ScalableVectorGraphics)にガウスぼかしが実装されています。ピクセルを含むすべてのプリミティブに適用されると思います。SVGには、オープンスタンダードであり、広く実装されているという利点があります。