Convolution¶
이 문서에서의 convolution은 digital image processing등에서의 convolution을 다루고 있음. signal processing의 discrete convolution에 대한 건 다음 문서를 참고할 것:
Discrete Convolution, Circular Convolution
image filtering에서 spatial domain filtering은 주로 filter 또는 kernel 또는 window 라고 하는 행렬과 입력 영상의 Convolution으로 이루어짐.
Convolution은 기호 ⊗ or ∗ 등으로 표기되지만 통일된 기호는 없음.
- 어찌보면, spatial operation의 끝판왕이라고 봐도 됨.
convolution의 수식은 다음과 같음.
where
- \(h(x,y)\) : filter or kernel
- \(f(x,y)\) : original image
- \(g(x,y)\) : output image
convolution은 cross-correlation과 달리 교환법칙이 성립 하며, impulse response(영상에선 point spread function)와 입력 신호를 이용하여 시스템의 response를 구하는 연산 임.
- cross-correlation과 달리 입력 함수 중 하나가 reflection이 이루어진다는 차이가 있음.
- cross-correlation에 대한 보다 자세한 내용은 다음 url을 참고 : Cross correlation
하지만, 이미지 처리에서는 대부분 kernel을 대칭적인 것을 사용하다 보니 cross-correlation과 차이가 없는 경우가 많고, 특히 ML(기계학습)이나 DL(딥러닝)에서 kernel이 이미 상하좌우로 flip하여 입력하면 된다는 가정 하에 convolution의 구현이 실제로는 cross-correlation인 경우가 대다수임.
Kernel (or Filter, Mask, Window)¶
- 유한한 크기의
impulse response
(or point spread function)의 특성 계수 - 시스템 응답 특성 계수를 가지고 있는 matrix 혹은 tensor임.
DL등에서 convolution layer은 위의 2D kernel이 아닌 3D kernel로 구성되는 게 일반적임. (channel이 보통 3이므로 raw image를 입력으로 삼는 경우 kernel size의 3개의 matrix를 가지고 있다고 생각하면 됨.)
- kernel의 width와 height를 통해 local receptive field의 크기가 결정됨.
- receptive field란 convolution의 결과로 나오는 feature map의 한 pixel(or voxel)의 값을 만드는데 관여한 input map(or image)의 영역을 의미함.
Convolution 수행 방식¶
위의 그림에서 Kernel matrix는 상하좌우로 뒤집힌(reflection) 상태임. (Cross correlation과 차이)
- 다시 강조하지만, DIP나 ML, DL에서는 cross-correlation과 거의 구분하지 않음.
아래 그림은 다채널의 입력에 대해, 2개의 filter (or kernel)이 주어져서 convolution이 이루어지는 과정을 보여주고 있음.
- \(5 \times 5 \times 3\) image를 상하좌우로 1씩 padding을 수행하고,
- \(3 \times 3\) kernel을(엄밀하게는 \(3\times 3\times 3\)) 통해 convolution을 수행하여 \(3 \times 3 \times 2\) image를 얻어냄.
- Kernel은 2 pixels의
stride
를 사용하여 이동함. - 결과 영상의 depth \(2\)는 kernel (or filter)이 2개 (
W0
,W1
) 사용됨을 의미함.
Stride¶
Convolution을 수행할 때, stride
는 일종의 sub-sampling factor로 동작함.
이는 stride
가 클수록 결과 feature map의 사이즈가 줄어들게 되며, DL에서 convolution layer의 computational complex를 효과적으로 낮출 수 있도록 해준다. Kernel이 sliding을 통해 적용되어나가는데, stride
는 어느 간격으로 Kernel이 sliding될지를 나타낸다. (stride
가 클수록 듬성듬성 처리된다고 생각할 수 있음.)
다음은 stride
가 \(2 \times 2\)인 경우(오른쪽으로 sliding할 때 2pixels, 아래로 sliding 할 때도 2pixels)임. (stride
가 1인 경우 \(3\times 3\) feature map이 나오는 것과 달리 이 경우 \(2 \times 2\) feature map이 결과임)
- \(5 \times 5\) 입력에 \(2\times 2\) stide로 \(3\times 3\) kernel로 Convolution.
- 상단의 녹색 matrix가 출력임.
OpenCV를 통한 convolution¶
OpenCV 는 filter2D
를 통해 convolution을 제공.
src
: input imageddepth
: output image dtype :-1
인 경우 input image와 동일한dtype
를 가짐. /CV_8U
,CV_16U
,CV16S
,CV_32F
,CV_64F
kernel
: kernel or window or mask or filter matrixdst
: output imageanchor
: kernel의 기준점. 결과값이 치환될 위치. default (-1,-1) 로 kernel의 중앙을 의미delta
: 결과값에 추가할 값.borderType
: padding 형태 (기본으로BORDER_REFLECT_101
임).
간단한 예제 코드는 다음과 같음.
#img = cv2.imread('./data/lena.jpg')
img = astro_noise.copy() # 아래 예는 poisson noise를 가함.
print(img.dtype, img.shape)
k_size = 10
kernel = np.full((k_size,k_size),1./(k_size**2))
blured = cv2.filter2D(img, -1, kernel)
print(f'from {img.shape} to {blured.shape}')
plt.figure(figsize=(10,20))
plt.imshow(np.concatenate((img,blured),axis=1))
plt.axis('off')
plt.show()
결과는 다음과 같음.