38

私の質問はこの質問に非常に近いです:組み込みのガウス関数を使用せずに画像をガウスぼかしするにはどうすればよいですか?

この質問に対する答えは非常に良いですが、実際のガウス フィルター カーネルを実際に計算する例は示されていません。答えは任意のカーネルを与え、そのカーネルを使用してフィルターを適用する方法を示しますが、実際のカーネル自体を計算する方法は示しません。C++ または Matlab でゼロからガウスぼかしを実装しようとしているため、カーネルをゼロから計算する方法を知る必要があります。

誰かが小さなサンプル画像マトリックスを使用して実際のガウス フィルター カーネルを計算できれば幸いです。

4

7 に答える 7

36

の MATLAB ドキュメントに記載されているように、Gaussian カーネルを最初から作成できますfspecial。そのページのアルゴリズムの部分にある Gaussian カーネルの作成式を読み、以下のコードに従ってください。コードは、sigma = 1 で m 行 n 列の行列を作成することです。

m = 5; n = 5;
sigma = 1;
[h1, h2] = meshgrid(-(m-1)/2:(m-1)/2, -(n-1)/2:(n-1)/2);
hg = exp(- (h1.^2+h2.^2) / (2*sigma^2));
h = hg ./ sum(hg(:));

h =

    0.0030    0.0133    0.0219    0.0133    0.0030
    0.0133    0.0596    0.0983    0.0596    0.0133
    0.0219    0.0983    0.1621    0.0983    0.0219
    0.0133    0.0596    0.0983    0.0596    0.0133
    0.0030    0.0133    0.0219    0.0133    0.0030

fspecialこれは、次のようにビルトインで実行できることに注意してください。

fspecial('gaussian', [m n], sigma)
ans =

    0.0030    0.0133    0.0219    0.0133    0.0030
    0.0133    0.0596    0.0983    0.0596    0.0133
    0.0219    0.0983    0.1621    0.0983    0.0219
    0.0133    0.0596    0.0983    0.0596    0.0133
    0.0030    0.0133    0.0219    0.0133    0.0030

好きな言語でこれを実装するのは簡単だと思います。

編集: C ++でコーディングする場合は慣れていない可能性があるため、特定のケースのh1との値も追加させてください。h2meshgrid

h1 =

    -2    -1     0     1     2
    -2    -1     0     1     2
    -2    -1     0     1     2
    -2    -1     0     1     2
    -2    -1     0     1     2

h2 =

    -2    -2    -2    -2    -2
    -1    -1    -1    -1    -1
     0     0     0     0     0
     1     1     1     1     1
     2     2     2     2     2
于 2011-11-20T21:29:04.033 に答える
32

それは聞こえるほど簡単です:

double sigma = 1;
int W = 5;
double kernel[W][W];
double mean = W/2;
double sum = 0.0; // For accumulating the kernel values
for (int x = 0; x < W; ++x) 
    for (int y = 0; y < W; ++y) {
        kernel[x][y] = exp( -0.5 * (pow((x-mean)/sigma, 2.0) + pow((y-mean)/sigma,2.0)) )
                         / (2 * M_PI * sigma * sigma);

        // Accumulate the kernel values
        sum += kernel[x][y];
    }

// Normalize the kernel
for (int x = 0; x < W; ++x) 
    for (int y = 0; y < W; ++y)
        kernel[x][y] /= sum;
于 2011-11-20T21:27:17.890 に答える
23

ガウス ブラーを実装するには、ガウス関数を使用して、カーネル内の要素ごとに 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']
于 2011-11-20T21:29:26.653 に答える
0
 function kernel = gauss_kernel(m, n, sigma)
 % Generating Gauss Kernel

 x = -(m-1)/2 : (m-1)/2;
 y = -(n-1)/2 : (n-1)/2;

 for i = 1:m
     for j = 1:n
         xx(i,j) = x(i);
         yy(i,j) = y(j);
     end
 end

 kernel = exp(-(xx.*xx + yy.*yy)/(2*sigma*sigma));

 % Normalize the kernel
 kernel  = kernel/sum(kernel(:));

 % Corresponding function in MATLAB
 % fspecial('gaussian', [m n], sigma)
于 2016-11-03T00:43:22.590 に答える