サムネがコーヒーの記事は書きかけです。

一次微分カーネルを使用してエッジ検出(を試みる)

画像に対する一次微分とは、簡単に言うとピクセル間の勾配(輝度差)を検出することです。

輝度差が大きく傾いている場所がエッジであると言う考え方を用いているのが特徴です。

一次微分カーネル

画像に一次微分をする際、縦横それぞれに関して微分をする必要が出てきます。

水平方向の一次微分カーネルを

$$K_l = \begin{bmatrix}0&1&0\\0&-1&0\\0&0&0 \\ \end{bmatrix}$$

垂直方向の一次微分カーネルを

$$K_s = \begin{bmatrix}0&0&0\\0&-1&1\\0&0&0 \\ \end{bmatrix}$$

と定義します。

微分処理の実装

上記の2つのカーネルに従い、解析対象の一枚の画像から二種類の画像を得ることになります。

今回はwikipediaからSaccharomyces cerevisiaeの画像を借りて解析していきます。

https://en.wikipedia.org/wiki/Saccharomyces_cerevisiae

Saccharomyces cerevisiae(Wikipedia)
import cv2 
import numpy as np 
img = cv2.imread('sample_1.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

kernel_l = np.array([[0, 1, 0],
                   [0, -1, 0],
                   [0, 0, 0]])
kernel_s = np.array([[0, 0, 0],
                   [0, -1, 1],
                   [0, 0, 0]])
dst_ld = cv2.filter2D(img_gray, -1, kernel_l)
dst_sd = cv2.filter2D(img_gray, -1, kernel_s)
cv2.imwrite('img_ld.png',dst_ld)
cv2.imwrite('img_sd.png',dst_sd)

上記の処理によって、縦横それぞれの方向で一次微分した画像データを取得することができました。

上記の画像ですが、ほとんど見えていないためコントラストを上げて結果を確認してみます。

def adjust(img, a, b):
    dst = a * img + b
    return np.clip(dst, 0, 255).astype(np.uint8)
dst = adjust(cv2.imread('img_.jpg'), a=3, b=10)
cv2.imwrite('img.jpg',dst)

一応ピクセルの勾配が検出できていそうですね。

画像の統合

上記で得た縦横二種類の一次微分フィルタ処理後の画像を一枚に統合します。

dst = cv2.addWeighted(dst_ld,0.5,dst_sd,0.5,25)
dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)
cv2.imwrite('result.jpg',dst)

少し暗めなので、ガンマ値を高めに設定しておきました。

畳み込み演算で実行

畳み込み演算を使用して、一次微分カーネルをかけて行ってみます。

import cv2 
import numpy as np 
img = cv2.imread('sample_1.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
kernel_l = np.array([[0, 1, 0],
                   [0, -1, 0],
                   [0, 0, 0]])
kernel_s = np.array([[0, 0, 0],
                   [0, -1, 1],
                   [0, 0, 0]])

def filter2D(src, kernel):
    m, n = kernel.shape
    h = src.shape[0]
    w = src.shape[1]
    dst = np.zeros((h, w))
    for y in range(int((m-1)/2), h - int((m-1)/2)):
        for x in range(int((m-1)/2), w - int((m-1)/2)):
            dst[y][x] = np.sum(src[y-int((m-1)/2):y+int((m-1)/2)+1, x-int((m-1)/2):x+int((m-1)/2)+1]*kernel)
    return dst
dst_ld = filter2D(img_gray,kernel_l)
dst_sd = filter2D(img_gray,kernel_s)
dst = np.sqrt(dst_ld ** 2 + dst_sd ** 2)

filer2Dメソッドを手動で実装したのと同じですが、返り値が行列となっているため、画像として出力してしまう前に2つの画像を統合することができます。

これにより、画像の重みを1にしたまま両方の画像を統合することが可能になります。

なんとなく明るくなったような気がします。

ガウシアンブラーの併用

以下の記事で紹介したように、二次元ガウス分布による重み付けを利用した平滑化を行うことで、エッジがより際立つことがあります。

実行するまでどうなるかはわかりませんが、せっかくなので試してみたいと思います。

強めのガウシアンブラーをかけます。

import cv2
import numpy as np
img_raw = cv2.imread('sample_1.jpg')
img_gray = cv2.cvtColor(img_raw,cv2.COLOR_RGB2GRAY)
dst = cv2.GaussianBlur(img_gray, ksize=(25, 25), sigmaX=2)
cv2.imwrite('result_gaussian.jpg',dst)

以下が出力結果です。

次に畳み込み演算を用いて、それぞれの画像に一次微分フィルター処理を行った結果を見てみます。

どうやら、ガウシアンブラーしなかった方がエッジの検出はうまくできているようです。

そもそも、ガウシアンブラーは高周波数領域のノイズを取り除くものなので、当たり前かもしれませんね。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です