エッジ検出

エッジの検出は、Canny アルゴリズム、ラプラシアン、および Sobel アルゴリズムによって行うことができる。ここでは、次の写真を使って、植物領域のエッジを検出する例を示す。植物領域のエッジを検出したいので、ここでは BGR 写真をそのままグレースケース化せずに、緑色を検出するのに適している L*a*b* 色空間の a* 値を取り出して、エッジ検出に用いる。

タネツケバナの写真 タネツケバナの写真(a* 値)

Canny アルゴリズム

Canny アルゴリズムでは、画像の輝度に対して微分を行い、その微分値が与えられた閾値の範囲に入っていれば、それをエッジとしている。そのため、Canny アルゴリズムを利用する使い場合は、画像の輝度に対する微分値の最小値と最大値の範囲を与える必要がある。次の例では、最小値を 30、最大値を 35 としている。

import numpy as np
import cv2

img_BGR = cv2.imread("chirsuta.jpg")

img_Lab = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2Lab)
img_Lab_L, img_Lab_a, img_Lab_b = cv2.split(img_Lab)
# cv2.imwrite('chirsuta.a.jpg', img_Lab_L)

img_canny = cv2.Canny(img_Lab_a, 30, 35)
cv2.imwrite('chirsuta.canny.jpg', img_canny)
タネツケバナの写真(Cannyによるエッジ検出結果)

エッジを検出するとき、グレースケール化された画像を利用するよりも、2 値化した後の画像を使った方がエッジがきれいに検出できる。2 値化後に面積の小さいゴミ領域も除去すると、エッジがよりきれいになる。

import numpy as np
import cv2

img_BGR = cv2.imread("chirsuta.jpg")

# L*a*b*
img_Lab = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2Lab)
img_Lab_L, img_Lab_a, img_Lab_b = cv2.split(img_Lab)

# detect green area
_thres, img_green = cv2.threshold(img_Lab_a, 110, 255, cv2.THRESH_BINARY_INV)

# remove small area
nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(img_green, connectivity=8)
sizes = stats[1:, -1]; nb_components = nb_components - 1
img_plant = np.zeros((img_green.shape))
for i in range(0, nb_components):
    if sizes[i] >= 3000:
        img_plant[output == i + 1] = 255
img_plant = np.uint8(img_plant)

img_plant_canny = cv2.Canny(img_plant, 0, 255)
cv2.imwrite('chirsuta.canny.jpg', img_plant_canny)
タネツケバナの写真(2値化後のCannyによるエッジ検出結果)

ラプラシアン

import numpy as np
import cv2

img_BGR = cv2.imread("chirsuta.jpg")

# L*a*b*
img_Lab = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2Lab)
img_Lab_L, img_Lab_a, img_Lab_b = cv2.split(img_Lab)

# use a* channel to get edge (Laplacian)
img_laplacian = cv2.Laplacian(img_Lab_a, cv2.CV_32F, 8)
#img_laplacian = cv2.convertScaleAbs(img_laplacian)
cv2.imwrite('chirsuta.laplacian.jpg', img_laplacian)
タネツケバナの写真(ラプラシアンによるエッジ検出結果)

Sobel アルゴリズム

import numpy as np
import cv2

img_BGR = cv2.imread("chirsuta.jpg")

# L*a*b*
img_Lab = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2Lab)
img_Lab_L, img_Lab_a, img_Lab_b = cv2.split(img_Lab)

# use a* channel to get edge (Sobel)
img_sobel_x = cv2.Sobel(img_Lab_a, cv2.CV_8U, 1, 0, ksize=5)
img_sobel_y = cv2.Sobel(img_Lab_a, cv2.CV_8U, 0, 1, ksize=5)
img_sobel = cv2.addWeighted(img_sobel_x, 0.5, img_sobel_y, 0.5, 1)
cv2.imwrite('chirsuta.sobel.jpg', img_sobel)
タネツケバナの写真(Sobelによるエッジ検出結果)