ガウス ブラーを実装するには、ガウス関数を使用して、カーネル内の要素ごとに 1 つの値を計算するだけです。
通常、カーネルの中央の要素に最大の重みを割り当て、カーネルの境界にある要素にはゼロに近い値を割り当てます。これは、実際に中央の要素が存在することを保証するために、カーネルが奇数の高さ (それぞれの幅) を持つ必要があることを意味します。
実際のカーネル要素を計算するには、ガウス ベルをカーネル グリッドにスケーリングし (任意の egsigma = 1
と任意の範囲 eg を選択-2*sigma ... 2*sigma
)、要素の合計を 1 に正規化します。これを実現するために、任意のカーネル サイズをサポートしたい場合は、シグマを必要なカーネル サイズに適合させることができます。
C++ の例を次に示します。
#include <cmath>
#include <vector>
#include <iostream>
#include <iomanip>
double gaussian( double x, double mu, double sigma ) {
const double a = ( x - mu ) / sigma;
return std::exp( -0.5 * a * a );
}
typedef std::vector<double> kernel_row;
typedef std::vector<kernel_row> kernel_type;
kernel_type produce2dGaussianKernel (int kernelRadius) {
double sigma = kernelRadius/2.;
kernel_type kernel2d(2*kernelRadius+1, kernel_row(2*kernelRadius+1));
double sum = 0;
// compute values
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++) {
double x = gaussian(row, kernelRadius, sigma)
* gaussian(col, kernelRadius, sigma);
kernel2d[row][col] = x;
sum += x;
}
// normalize
for (int row = 0; row < kernel2d.size(); row++)
for (int col = 0; col < kernel2d[row].size(); col++)
kernel2d[row][col] /= sum;
return kernel2d;
}
int main() {
kernel_type kernel2d = produce2dGaussianKernel(3);
std::cout << std::setprecision(5) << std::fixed;
for (int row = 0; row < kernel2d.size(); row++) {
for (int col = 0; col < kernel2d[row].size(); col++)
std::cout << kernel2d[row][col] << ' ';
std::cout << '\n';
}
}
出力は次のとおりです。
$ g++ test.cc && ./a.out
0.00134 0.00408 0.00794 0.00992 0.00794 0.00408 0.00134
0.00408 0.01238 0.02412 0.03012 0.02412 0.01238 0.00408
0.00794 0.02412 0.04698 0.05867 0.04698 0.02412 0.00794
0.00992 0.03012 0.05867 0.07327 0.05867 0.03012 0.00992
0.00794 0.02412 0.04698 0.05867 0.04698 0.02412 0.00794
0.00408 0.01238 0.02412 0.03012 0.02412 0.01238 0.00408
0.00134 0.00408 0.00794 0.00992 0.00794 0.00408 0.00134
簡単にするために、2d-kernel を使用する必要はありません。2 つの直交する 1D カーネルを使用すると、実装が簡単になり、計算も効率的になります。これは、このタイプの線形畳み込みの結合性 (線形分離可能性) によって可能になります。対応するウィキペディアの記事のこのセクションも参照してください。
これはPythonでも同じです(誰かが役に立つと思うかもしれません):
from math import exp
def gaussian(x, mu, sigma):
return exp( -(((x-mu)/(sigma))**2)/2.0 )
#kernel_height, kernel_width = 7, 7
kernel_radius = 3 # for an 7x7 filter
sigma = kernel_radius/2. # for [-2*sigma, 2*sigma]
# compute the actual kernel elements
hkernel = [gaussian(x, kernel_radius, sigma) for x in range(2*kernel_radius+1)]
vkernel = [x for x in hkernel]
kernel2d = [[xh*xv for xh in hkernel] for xv in vkernel]
# normalize the kernel elements
kernelsum = sum([sum(row) for row in kernel2d])
kernel2d = [[x/kernelsum for x in row] for row in kernel2d]
for line in kernel2d:
print ["%.3f" % x for x in line]
カーネルを生成します。
['0.001', '0.004', '0.008', '0.010', '0.008', '0.004', '0.001']
['0.004', '0.012', '0.024', '0.030', '0.024', '0.012', '0.004']
['0.008', '0.024', '0.047', '0.059', '0.047', '0.024', '0.008']
['0.010', '0.030', '0.059', '0.073', '0.059', '0.030', '0.010']
['0.008', '0.024', '0.047', '0.059', '0.047', '0.024', '0.008']
['0.004', '0.012', '0.024', '0.030', '0.024', '0.012', '0.004']
['0.001', '0.004', '0.008', '0.010', '0.008', '0.004', '0.001']