script day.log

大学生がなんとなく始めた、趣味やら生活のことを記録していく。

フィルタリング(Sobelフィルタ,ラプラシアンフィルタ)

さて、今回は空間フィルタについてです。

フィルタリングとは

画像のフィルタリングとは,画素値を用いて演算することによって,画像中のエッジの強調やノイズの除去,
特定の周波数成分のカットや強調などを行う処理である.画像のフィルタリングは,画像空間において
フィルタリングを行う空間領域でのフィルタリングと,画像にフーリエ変換を施して周波数領域に変換した後に
フィルタリングを行う周波数領域でのフィルタリングに大別出来る.

今回お話するのは空間領域でのフィルタリングです.

画像のフィルタリングとは,画素値を用いて演算することによって,画像中のエッジの強調やノイズの除去,
特定の周波数成分のカットや強調などを行う処理である.画像のフィルタリングは,画像空間において
フィルタリングを行う空間領域でのフィルタリングと,画像にフーリエ変換を施して周波数領域に変換した後に
フィルタリングを行う周波数領域でのフィルタリングに大別出来る.

空間領域でのフィルタリング

空間領域でのフィルタリングとは原画像の注目画素(m,n)の濃度値f(m,n)と注目画素の近傍画素の濃度値に対する
数値演算処理によって,新たな濃度値g(m,n)を求める操作である.ただし,近傍画素は画像全体に対して十分小さく,
具体的には3\times3画素,5\times5画素などである.変換後の濃度値g(m,n)

\begin{align}
\label{math-1}
 g(m,n) = \sum^{1}_{k=-1}\sum^{1}_{l = -1}C_{k,l}f(m + k, n + l)
\end{align}

で与えられるフィルタは線形フィルタと呼ばれ,C_{k,l}の値を変えることにより様々なフィルタを実現することが
できる.ただし,近傍画素は3\times3画素としC_{k.l}(-1\leq k,l \leq 1)は近傍の各画素に掛ける係数とする.


  • 差分フィルタ

領域の境界では濃度値の急激な変化が見られる.従って,その境界すなわち,エッジを抽出するには
画像に対して微分操作を行えばよい.いま,ディジタル画像を考えていることから,水平および垂直方向の
微分操作はそれぞれ次のように表され,差分操作によって求められる.

\begin{align}
 \Delta_{x}f(m,n) &= \frac{f(m,n+1)-f(m,n)}{n+1-n} = f(m,n+1) - f(m,n) \nonumber \\
 \Delta_{y}f(m,n) &= \frac{f(m+1,n)-f(m,n)}{m+1-m} = f(m+1,n) - f(m,n) \nonumber
\end{align}

Sobel(ソーベル)フィルタとは

微分操作を用いると雑音に弱いという欠点がある.そこで,近傍画素の濃度値も利用して安定した
1次微分が計算できるように拡張したSobelフィルタがある.
以下にSobelフィルタの加重マトリックスを示す.

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

水平方向のエッジを強調

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

垂直方向のエッジを強調

Sobelフィルタの実装(C言語

以下にSobelフィルタの適用部分を示す.
内容としては,各画素の濃度値を関数に渡して,returnしてるだけ.
ただ,水平方向と垂直方向の両方のエッジを強調するため,
出力画素で工夫(垂直方向と水平方向の2乗を足し、√をとって,絶対値を出力)してます.

unsigned char sobel_filtering(unsigned char px0, unsigned char px1,unsigned char px2,unsigned char px3,unsigned char px4,unsigned char px5,unsigned char px6,unsigned char px7,unsigned char px8){
    int sobel_x[9] = {-1,0,1,
                    -2,0,2,
                    -1,0,1};
    int sobel_y[9] = {-1,-2,-1,
                      0,0,0,
                      1,2,1};

    double px_x, px_y, px_out;
    px_x = px_y = px_out = 0;

    px_x = sobel_x[0] * px0 + sobel_x[1] * px1 + sobel_x[2] * px2 + sobel_x[3] * px3 + sobel_x[4] * px4 + sobel_x[5] * px5 + sobel_x[6] * px6 + sobel_x[7] * px7 + sobel_x[8] * px8;
    px_y = sobel_y[0] * px0 + sobel_y[1] * px1 + sobel_y[2] * px2 + sobel_y[3] * px3 + sobel_y[4] * px4 + sobel_y[5] * px5 + sobel_y[6] * px6 + sobel_y[7] * px7 + sobel_y[8] * px8;

    px_out = abs(sqrt(pow(px_x,2.0) + pow(px_y,2.0)));

    if(px_out > 255){
        return 255;
    }
    else{
        return (unsigned char)px_out;
    }
}

ラプラシアンフィルタとは

Sobelフィルタでは1次微分が計算されたわけだが,
ラプラシアンフィルタでは2次微分を計算する.
すると緩やかな濃度変化でも優れたエッジの検出を実行することが出来る.以下にラプラシアンフィルタの加重マトリックスを示す.

0 1 0
1 −4 1
0 1 0

4近傍

1 1 1
1 -8 1
1 1 1

8近傍

ラプラシアンフィルタの実装(C言語

以下にラプラシアンフィルタの適用部分を示す.
内容としては,各画素の濃度値を関数に渡して,returnしてるだけ.
真ん中の画素値(i=4)だけ−8倍してます.関数に渡すときや配列に格納するときに-8倍してもいいと思います.

unsigned char laplacian(unsigned char px0, unsigned char px1,unsigned char px2,unsigned char px3,unsigned char px4,unsigned char px5,unsigned char px6,unsigned char px7,unsigned char px8){
    int laplacian[9] = {px0,px1,px2, px3,px4,px5,px6,px7,px8};

    int px_out = 0;
    for (int i = 0; i < 9; i++) {
        if(i == 4){
            laplacian[i] *= -8;
        }
         px_out += laplacian[i];   
    }

    px_out = abs(px_out);
    if(px_out > 255){
        return 255;
    }
    else{
        return (unsigned char)px_out;
    }
}

次は平滑化について書きます.