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