๐์ด ํฌ์คํธ๋ canny edge detection์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
์ด๋ฏธ์ง์์ edge๋ฅผ ์ฐพ์๋ด๋ ๋ฐ์ ๋งค์ฐ ํจ๊ณผ์ ์ธ ๊ฒฝ๊ณ ๊ฒ์ถ ๊ธฐ๋ฒ์ด๋ฉฐ, ์ ํ์ฑ์ ๋ณด์ฅํ๊ณ ์์ edge ๊ฒ์ถํ๋๋ฐ์ ์ฐ์ํ ์ฑ๋ฅ์ ๋ณด์ด๋ ๊ฒฝ๊ณ ๊ฒ์ถ ๊ธฐ๋ฒ์ด๋ค.
์ฅ์
๋จ์
๊ธฐ์กด sobel edge detection์ ๋๊บผ์ด ํํ๋ก edge๋ก ๊ฒ์ถํ๋ ๋จ์ ์ผ๋ก ์ ํํ๊ฒ ๊ฒ์ถํ๋๋ฐ ๋ฌธ์ ๊ฐ ์์๋ค.
๊ทธ๋์ sobel edge detection์ ๋จ์ ์ ๋ณด์ํ์ฌ ์๊ณ ์ ํํ edge๋ฅผ ๊ฒ์ถํ๋ฉฐ ์ก์์ ์์ ๊ธฐ ์ํด canny edge detection์ ์ฌ์ฉํ๋ค.
์ฐ๋ฆฌ๊ฐ ์ง์ ์์ค์ฝ๋๋ฅผ ๋ง๋ค์ด๋ ๋์ง๋ง, ๋ ธ๋๋ ฅ๊ณผ ์๊ฐํจ์จ์ฑ์ ๊ณ ๋ คํ์ ๋ OpenCV ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ตฌํํ canny edge detection ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
import cv2
canny = cv2.Canny(image, threshold_1, threshold_2)
์ด cv2.Canny() ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ํ์ค์ canny edge detection์ ์์ฑํ ์ ์์ต๋๋ค.
์ ๊ฐ '์๋ฆฌ' ๋ถ๋ถ์์ ์ค๋ช
ํ ๊ฒ๋ค์ด ์ด๋ฌํ ๊ฒฐ๊ณผ๋ฅผ ๋์ถํฉ๋๋ค.
์ด๋ฏธ์ง๋ก ์ดํด๋ฅผ ๋์ธ ์ ์์ผ๋ฉด ์ข๊ฒ ๋ค์๐
# size : ์ปค๋ ํฌ๊ธฐ sigma : ํ์คํธ์ฐจ (sigma^2 : ๋ถ์ฐ)
def Gaussian(size, sigma):
#์ค์ฌ์์๋ถํฐ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ
array = np.arange((size//2)*(-1), (size//2)+1)
#x^2+y^2 ๋ฐฐ์ด ์ด๊ธฐํ
xx_yy_array = np.zeros((size, size))
for x in range(size):
for y in range(size):
#์ค์ฌ์์๋ถํฐ์ ๊ฑฐ๋ฆฌ๋ฅผ ์ ๊ณฑํฉ์ผ๋ก ๊ณ์ฐ
xx_yy_array[x,y] = array[x]**2+array[y]**2
# ํํฐ ์ด๊ธฐํ
filter = np.zeros((size, size))
for x in range(size):
for y in range(size):
# ์ํ์ ์์ ๊ตฌํ๋ถ
filter[x,y] = 1 / (2 * np.pi * sigma**2) * np.exp(-xx_yy_array[x,y]/(2 * sigma**2))
# Scaling
filter /= filter.sum()
return filter
๊ฐ์ฐ์์ ํํฐ๋ฅผ ์ด๋ ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
๊ฐ์ฐ์์ ์ ์ฉ ์ด๋ฏธ์ง๊ทธ ๋ค์ gradient๋ฅผ ๊ตฌํ๋ค.
gradient๋ ์๋ฒจ ํํฐ๋ก๋ถํฐ ๊ตฌํ ์ ์๋ค.
# gradient๋ฅผ ๊ตฌํ๋ ๋ฐฉ๋ฒ
# ์๋ฒจ ํํฐ
def sobel(image):
#x,y ํํฐ
sobel_vertical = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
sobel_horizontal = np.array([[-1,-2,-1],
[ 0, 0, 0],
[ 1, 2, 1]])
# x์ถ, y์ถ์ ๋ํด ์ฝ๋ณผ๋ฃจ์
gradient_x = cv2.filter2D(image, -1, sobel_vertical)
gradient_y = cv2.filter2D(image, -1, sobel_horizontal)
# ์ ํด๋ฆฌ๋์ ๊ฑฐ๋ฆฌ ๊ตฌํ๊ธฐ
# == np.sqrt(gradient_x **2 + gradient_y ** 2)
gradient = np.hypot(gradient_x, gradient_y)
# Normalization
gradient = gradient / gradient.max() * 255
theta = np.arctan2(gradient_y, gradient_x)
return (gradient, theta)
gradient๋ฅผ ๊ตฌํ ์ด๋ฏธ์ง
์ด์ Non-Maximum Suppression์ ํตํด
45๋ ๊ฐ๊ฒฉ์ผ๋ก ๋ผ์ด๋ฉํ์ฌ edge ๊ฐ๊ณผ ํ์ฌ ํฝ์
์ edge ๊ฐ์ ๋น๊ตํ๋ค.
def non_max_suppression(gradient, theta):
#Height, Width
height, width = gradient.shape
#
result = np.zeros((height, width), dtype=np.int32)
#๊ฐ ๋ฐฉํฅ์ ๋๋ฉด์ ๊ณ์ฐ
angle = theta * 180. / np.pi
angle[angle < 0] += 180
#(0,45,90,135) ๋ฐฉํฅ์ ๋๋ฉด์ ์ฐ์ฐ
for i in range(1, height-1):
for j in range(1, width-1):
# 0 degrees ( & 180 degree)
if (0 <= angle[i, j] < 22.5) or (157.5 <= angle[i, j] <= 180):
left = gradient[i, j - 1]
right = gradient[i, j + 1]
# 45 degrees ( & 225 degree)
elif 22.5 <= angle[i, j] < 67.5:
left = gradient[i - 1, j + 1]
right = gradient[i + 1, j - 1]
# 90 degrees ( & 270 degree)
elif 67.5 <= angle[i, j] < 112.5:
left = gradient[i - 1, j]
right = gradient[i + 1, j]
# 135 degrees ( & 315 degree)
elif 112.5 <= angle[i, j] < 157.5:
left = gradient[i - 1, j - 1]
right = gradient[i + 1, j + 1]
if (gradient[i, j] > left) and (gradient[i, j] > right):
result[i, j] = gradient[i, j]
else:
result[i, j] = result[i, j]
return result
NMS ์ ์ฉ ์ด๋ฏธ์ง
๊ทธ๋ฆฌ๊ณ ๊ทธ ์ดํ์ hysteresis threshold๋ฅผ ์ ์ฉํ์ฌ
๊ฐ ๋์ถ๋๋ค.
ํ์ดํผ ํ๋ผ๋ฏธํฐ๋ฅผ ํ๋ํ์ฌ ๊ฐ์ ์ํ๋ ๊ฐ์ ๋ฌ๋ฆฌ ํ์ฌ ์ ์ฌ์ ์์ ํ์ํ ์ด๋ฏธ์ง๋ฅผ ๋์ถํ ์ ์๋ค.