Canny Edge Detection

ChangSeong Yooยท2023๋…„ 7์›” 24์ผ
0

Vision

๋ชฉ๋ก ๋ณด๊ธฐ
5/5
post-thumbnail

๐Ÿ“์ด ํฌ์ŠคํŠธ๋Š” canny edge detection์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.




์ •์˜

์ด๋ฏธ์ง€์—์„œ edge๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๋ฐ์— ๋งค์šฐ ํšจ๊ณผ์ ์ธ ๊ฒฝ๊ณ„ ๊ฒ€์ถœ ๊ธฐ๋ฒ•์ด๋ฉฐ, ์ •ํ™•์„ฑ์„ ๋ณด์žฅํ•˜๊ณ  ์–‡์€ edge ๊ฒ€์ถœํ•˜๋Š”๋ฐ์— ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ์„ ๋ณด์ด๋Š” ๊ฒฝ๊ณ„ ๊ฒ€์ถœ ๊ธฐ๋ฒ•์ด๋‹ค.

์žฅ์ 

  1. gaussian filter๋ฅผ ์ด์šฉํ•˜์—ฌ ์„ ๋ช…ํ•˜๊ณ  ์ •ํ™•ํ•œ edge ๊ฒ€์ถœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  2. non-maximum suppression์„ ์‚ฌ์šฉํ•˜์—ฌ ์–‡์€ edge๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

๋‹จ์ 

  1. ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๋Š” ๊ฒฝ๊ณ„ ๊ฒ€์ถœ ๊ธฐ๋ฒ•์œผ๋กœ, ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๋Š” ๋งŒํผ ์—ฐ์‚ฐ๋Ÿ‰์ด ๋งŽ์•„์ ธ ์ž์› ํšจ์œจ์„ฑ์ด ๋‚ฎ๋‹ค.
  2. threshold ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ํŠœ๋‹ํ•ด์•ผํ•œ๋‹ค.




๋ชฉ์ 

๊ธฐ์กด sobel edge detection์˜ ๋‘๊บผ์šด ํ˜•ํƒœ๋กœ edge๋กœ ๊ฒ€์ถœํ•˜๋Š” ๋‹จ์ ์œผ๋กœ ์ •ํ™•ํ•˜๊ฒŒ ๊ฒ€์ถœํ•˜๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.
๊ทธ๋ž˜์„œ sobel edge detection์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•˜์—ฌ ์–‡๊ณ  ์ •ํ™•ํ•œ edge๋ฅผ ๊ฒ€์ถœํ•˜๋ฉฐ ์žก์Œ์„ ์—†์• ๊ธฐ ์œ„ํ•ด canny edge detection์„ ์‚ฌ์šฉํ•œ๋‹ค.




์›๋ฆฌ

  1. ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ๋ง : ๋…ธ์ด์ฆˆ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด gaussian filter๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    gaussian filter์˜ ๊ณต์‹์€
    G(x,y)=12ฯ€ฯƒ2eโˆ’x2+y22ฯƒ2G(x,y) = \frac{1}{2\pi\sigma^2}e^{-\frac{x^2+y^2}{2\sigma^2}}
    ์™€ ๊ฐ™๋‹ค.
  2. gradient ๊ณ„์‚ฐ (ํฌ๊ธฐ & ๋ฐฉํ–ฅ)
    sobel filter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜์ง ๋ฐฉํ–ฅ(xx)๊ณผ ์ˆ˜ํ‰ ๋ฐฉํ–ฅ(yy)์˜ ๋ฏธ๋ถ„๊ฐ’์„ ๊ตฌํ•˜์—ฌ gradient๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
    ์ด ๊ฐ’์„ ํ†ตํ•ด gradient์˜ ํฌ๊ธฐ์™€ ๋ฐฉํ–ฅ์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    magnitude:โˆฅfโˆฅ=fx2+fy2magnitude : \lVert f \rVert = \sqrt{f^2_x + f^2_y}
    phase:ฮธ=tanโˆ’1(fyfx)phase : \theta = tan^{-1}(\frac{f_y}{f_x})
  3. ํ•˜๋‚˜์˜ edge๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ”ฝ์…€๋กœ ํ‘œํ˜„๋˜๋Š” ํ˜„์ƒ์„ ์—†์• ๊ธฐ ์œ„ํ•ด gradient๊ฐ€ ์ตœ๋Œ“๊ฐ’(local maximum)์ธ ํ”ฝ์…€๋งŒ์„ ์—ฃ์ง€๋กœ ์„ค์ •ํ•˜๋Š” Non-Maximum Suppression์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    gradient ๋ฐฉํ–ฅ(์ˆ˜์ง, ์ˆ˜ํ‰)์„ ๊ธฐ์ค€์œผ๋กœ NMS๋ฅผ ์ ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–‡์€ edge๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    https://velog.io/@mykirk98/Non-Maximum-SuppressionNMS
    NMS์— ๋Œ€ํ•œ ์ œ ํฌ์ŠคํŠธ์ด๋‹ˆ ๋ชจ๋ฅด์‹œ๋Š” ๋ถ„๋“ค์€ ์ฐธ๊ณ ํ•˜์—ฌ ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค๐Ÿ‘๐Ÿฝ.
  4. Hysteresis Threshold
    Hysteresis๋ž€ ThresholdlowThreshold_{low}, ThresholdhighThreshold_{high} ๋‘ ๊ฐœ์˜ ์ž„๊ณ„๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€์˜ ํ”ฝ์…€์„ ๋‘ ๊ฐ€์ง€ edge ๊ทธ๋ฃน์œผ๋กœ ๋ถ„๋ฅ˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

    • ์œ„์˜ ์ผ€์ด์Šค์™€ ๊ฐ™์€ ThresholdhighThreshold_{high} ์ด์ƒ์˜ gradient๋ฅผ ๊ฐ–๋Š” edge๋ฅผ "Strong edge" ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
      ThresholdhighThreshold_{high} ๊ณผ ThresholdlowThreshold_{low} ์‚ฌ์ด์˜ ๊ตฌ๊ฐ„์„ "Hysteresis" ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
      ๊ณ ๋กœ gradient๊ฐ€ ๊ฐ์†Œํ•˜์—ฌ ThresholdhighThreshold_{high} ์•„๋ž˜๋กœ Hysteresis ๊ตฌ๊ฐ„ ์ดํ•˜๋กœ ๊ฐ์†Œํ•˜์ง€ ์•Š๊ณ  ThresholdhighThreshold_{high} ์œ„๋กœ ์œ ์ง€ํ•˜๋Š” gradient ๋ฅผ "Strong edge" ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

    • ์ด๋ฒˆ ์ผ€์ด์Šค๋Š” ThresholdlowThreshold_{low} ์•„๋ž˜๋กœ gradient๊ฐ€ ์ฆ๊ฐ€ํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๋Š” edge๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ํŒ๋ณ„ํ•ฉ๋‹ˆ๋‹ค.โŒ
      ํ”ฝ์…€ ๊ฐ’์ด ๊ธฐ์ค€์— ๋ฏธ์น˜์ง€ ๋ชปํ•˜๊ณ  ํ˜„์ €ํžˆ ๋‚ฎ์•„ edge๊ฐ€ ๋  ์ˆ˜๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

    • ์œ„์˜ ์ผ€์ด์Šค๊ฐ™์€ ๊ฒฝ์šฐ๋Š” gradient๊ฐ€ ๊ฐ์†Œํ•˜์—ฌ ThresholdhighThreshold_{high} ์•„๋ž˜๊นŒ์ง€ ๊ฐ์†Œํ•˜์—ฌ Hysteresis ๊ตฌ๊ฐ„์— ๋“ค์–ด์™”๋‹ค. ํ•˜์ง€๋งŒ continuousํ•œ ๊ณก์„ ์„ ์œ ์ง€ํ•˜๋ฉฐ ThresholdhighThreshold_{high} ์ด์ƒ์˜ gradient ๊ฐ’์ด ์œ ์ง€๋˜๋Š” ์ด ๊ตฌ๊ฐ„ gradient ๊ฐ’์„ "weak edge" ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

    • ํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ์—๋Š” "weak edge" ๊ฐ€ ์„ฑ๋ฆฝ๋˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹คโŒ.
      ์™œ๋ƒํ•˜๋ฉด ThresholdlowThreshold_{low} ์•„๋ž˜๋กœ gradient๊ฐ€ ๊ฐ์†Œํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. Hysteresis ๊ตฌ๊ฐ„ ์•„๋ž˜๋กœ gradient ๊ฐ’์ด ๊ฐ์†Œํ•˜๋ฉด edge๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ํŒ๋ณ„ํ•ฉ๋‹ˆ๋‹คโŒ.

    • ๊ทธ๋Ÿฌ๋ฉด ์œ„ ๊ทธ๋ฆผ์„ ํ•œ๋ฒˆ ์ ์šฉํ•ด๋ณด์ฃ .
      ์ด ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ํ•˜์ด๋ผ์ดํŠธ ์นœ ๋ถ€๋ถ„์€ edge๋ฅผ ๊ณ ๋ คํ•  ๋งŒํ•œ gradient ๊ฐ’์ด ์•„๋‹™๋‹ˆ๋‹ค.
      ๊ฒฐ๊ตญ "weak edge" ๋Š” ์•„๋‹ˆ์ง€๋งŒ ThresholdhighThreshold_{high} ์ด์ƒ์˜ ๊ฐ’์„ ์œ ์ง€ํ•˜๋Š” ์ € ์ข์€ ๊ตฌ๊ฐ„๋งŒ "strong edge" ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.




์ฝ”๋“œ ์ดํ•ด

์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋„ ๋˜์ง€๋งŒ, ๋…ธ๋™๋ ฅ๊ณผ ์‹œ๊ฐ„ํšจ์œจ์„ฑ์„ ๊ณ ๋ คํ–ˆ์„ ๋•Œ OpenCV ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๊ตฌํ˜„ํ•œ canny edge detection ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋‹จ์ˆœํ•œ ๊ตฌํ˜„

import cv2

canny = cv2.Canny(image, threshold_1, threshold_2)

์ด cv2.Canny() ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ํ•œ์ค„์— canny edge detection์„ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Before Canny

After Canny

์ œ๊ฐ€ '์›๋ฆฌ' ๋ถ€๋ถ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๋“ค์ด ์ด๋Ÿฌํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋„์ถœํ•ฉ๋‹ˆ๋‹ค.
์ด๋ฏธ์ง€๋กœ ์ดํ•ด๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ์œผ๋ฉด ์ข‹๊ฒ ๋„ค์š”๐Ÿ˜…

  • ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„

    ๊ฐ€์šฐ์‹œ์•ˆ ํ•„ํ„ฐ๋ง
# 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๋ฅผ ์ ์šฉํ•˜์—ฌ

๊ฐ€ ๋„์ถœ๋œ๋‹ค.
ํ•˜์ดํผ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํŠœ๋‹ํ•˜์—ฌ ๊ฐ์ž ์›ํ•˜๋Š” ๊ฐ’์„ ๋‹ฌ๋ฆฌ ํ•˜์—ฌ ์ ์žฌ์ ์†Œ์— ํ•„์š”ํ•œ ์ด๋ฏธ์ง€๋ฅผ ๋„์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

profile
๐’ฅ๐“Š๐“ƒ๐’พโ„ด๐“‡ ๐’Ÿ๐’ถ๐“‰๐’ถ ๐’ฎ๐’ธ๐’พโ„ฏ๐“ƒ๐“‰๐’พ๐“ˆ๐“‰

0๊ฐœ์˜ ๋Œ“๊ธ€