본문 바로가기

컴퓨터 비전/실습

prewitt, sobel, canny 구현(python)

학습한 prewitt, sobel, canny에 대해 python으로 구현을 해봅시다.

 

Code

import cv2
import time
import numpy as np
import math
from matplotlib import pyplot as plt


def padding(img, n):

    x, y = img.shape # original image size

    padding_img = np.zeros((x+2*n, y+2*n)) # consider up,down,left,right

    padding_img[n:x+n, n:y+n] = img # zero padding

    return padding_img


def edge_detection(img, mask1, mask2, threshold):
    
    img = padding(img,1)
    
    result1 = np.zeros(np.array(img.shape))
    result2 = np.zeros(np.array(img.shape))
    
    for h in range(1, img.shape[0] - 1):
        for w in range(1, img.shape[1] - 1):
            tmp = img[h-1:h+2, w-1:w+2]
            result1[h,w] = np.abs(np.sum(tmp*mask1)) # axis of x
            result2[h,w] = np.abs(np.sum(tmp*mask2)) # axis of y

    result = result1 + result2 # sum of x and y
    thr_result = np.zeros(img.shape)
    thr_result[result > threshold] = 1 # edge
    
    return thr_result[1:img.shape[0] - 1, 1:img.shape[1] - 1] # return original size
    
    
gray_img = cv2.imread('../lena.bmp', cv2.IMREAD_GRAYSCALE)


threshold1 = 100
threshold2 = 200
edge_img = cv2.Canny(gray_img, threshold1, threshold2) 


prewitt_y = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]])
prewitt_x = np.array([[1, 0, -1], [1, 0, -1], [1, 0, -1]])

sobel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
sobel_x = np.array([[1, 0, -1], [2, 0, -2], [1, 0, -1]])

p = edge_detection(gray_img, prewitt_x, prewitt_y, 100)
s = edge_detection(gray_img, sobel_x, sobel_y, 140)

plt.subplot(1,3,1)
plt.imshow(p, cmap='gray')
plt.title('prewit')

plt.subplot(1,3,2)
plt.imshow(s, cmap='gray')
plt.title('sobel')

plt.subplot(1,3,3)
plt.imshow(edge_img, cmap='gray')
plt.title('canny')

print(p.shape)
print(s.shape)
print(edge_img.shape)

plt.show()

 

prewitt과 sobel은 행렬을 만든뒤 인풋영상에 각각 x축과 y축에 대해서 edge_detection 함수를 적용한뒤 합한 영상이 아웃풋이 됩니다. canny는 라이브러리를 사용했고 threshold를 지정했습니다. edge_detection 함수에서 컨볼루션 연산을 하기전에 먼저 패딩을해야 영상이 밀리지 않고 원래 자리를 고정할수 있습니다. 그리고 반환할때 원래 영상크기로 패딩을 다시 복원해주면 됩니다.

 

Result

 

prewitt과 sobel은 x축 edge와 y축 edge를 겹치면서 중복된 부분으로 인해 edge가 굵게 나타난 반면 canny는 더 얇게 edge를 검출한 모습입니다. canny는 두가지로 threshold를 지정할수 있어 더 정밀한 edge 검출에서 용이하겠습니다.

감사합니다.