[openCV] Convolution & Mask (1)
openCV

[openCV] Convolution & Mask (1)

오늘은 openCV에서 Convolution과 Mask에 대해서 공부해보자

 

 

0. What Is Convolution?


Convolution

 

입력 영상 스캔하면서 현재 위치의 픽셀에 마스크의 중심이 오도록 한 후,

마스크 범위 내에 포함되는 이웃 픽셀을 마스크의 원소와 곱하여

결과 영상의 현재 위치 값을 결정하는 것


 

사진과 함께 보면서 이해를 해봅시다

 

https://www.slipp.net/wiki/pages/viewpage.action?pageId=26641520

우선 밑 설명은 3x3 Pixel을 기준으로 한다.

 

Convolution이 이루어질 때는 Convolution Filter를 기준으로 한다.

 

위의 사진에서는 openCV에서 Edge Detection을 할 때 사용되는 Sobel Filter를

Convolution Filter를 지정한거 같다.

 

사용자가 Convolution Filter를 지정했다면

Source Pixel와 Convolution Filter의 operate값을 기반으로

Destination Pixel을 지정할 수 있다.

 

여기서의 Operate Method는 시계 방향으로 

Source Code_Pixel * Convolution Filter_Pixel을 다 더해서

Destination Filter의 값이 되도록 한다.

 

그럼 위 사진에서는 이와 같은 operate가 일어난다.


(-1 x 3) + (0 x 0) + (1 x 1) + (-2 x 2) + (0 x 6) + (2 x 2) + (-1 x 2) + (0 x 4) + (1 x 1)  = -3 

 

-3 => Destination Pixel


 

이런 연산을 마지막 Pixel까지 반복하는 것을 Convolution Operate라고 합니다.

 

그럼 우리는 Convolution Operate를 어떤 상황에서 사용할까요😕?

 

우리는 Convolution Filter의 값을 조정하여서

Input Image ( Source Pixel )를 Bluming하게 만들 수도 있고,

sharpening하게 만들 수 도 있습니다.

 

※ Convolution Filter는 보통 3, 5, 7, 9... 와 같이 홀수 크기를 가진다.

 

 

 

1. Average Bluring (1)

 

Bluring은 많은 사람이 알겠지만 Input Image를 흐리게 처리하는 기술을 의미합니다.

 

동시에 Input Image의 noise가 제거되는 효과 역시 얻을 수 있습니다.

 

openCV에서 Bluring의 종류는 다양합니다.

 

우선 가장 기본적인 Average Blurring 방식을 살펴봅시다.

 

import cv2
import numpy as np

img = cv2.imread("./test.png")
kernel = np.ones((5,5), np.float32) / 5 ** 2
dst = cv2.filter2D(img, -1, kernel)

cv2.imshow("Original", img)
cv2.imshow("Result", dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

하나 하나 살펴봅시다.

 

kernel = np.ones((5,5), np.float32) / 5 ** 2

Convolution Filter Kernel을 우리는 5 x 5 Array 형태로 만들어준다.

 

그러면 Total Index 값이 25개가 되므로 Total Index 값으로 나눠주면

 

Average Bluring 위한 Convolution Filter Kernel이 만들어진다.

 

dst = cv2.filter2D(img, -1, kernel)

dst = cv2.filter2D( src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

 

src = img

ddepth = depth Of Destination Pixel( -1일 경우 Source Pixel과 동일)

kernel = Convolution Filter Kernel

 

openCV 공식 문서까지 확인해봤는데 ddepth을 통해서

Detination Pixel의 Depth를 지정해준다는 것이 사실 잘 이해가 가지 않는다.

 

그냥 아무 값이나 대입 해봤을때 Bluring의 강도가 변하는거 같은데

아직 정확하게는 잘 모르겠다.

 

어쨌든 cv2.filter2D를 이용한다면 Convolution Filter Kernel만 주어진다면

손쉽게 Detination Pixel을 제작 할 수 있다.

 

[ Result ]

Original Image

 

Bluring Image

 

1. Average Bluring (2)

 

openCV에서는 직접 Convolution Filter Kernel을 만들지 않고

정말 간단하게 Average Bluring을 할 수 있는 방법이 있다.

 

import cv2

img = cv2.imread("./test.png")
img_blur = cv2.blur(img, (5,5))


while True:
    cv2.imshow("Original", img)
    cv2.imshow("Blur", img_blur)

    key = cv2.waitKey(1)

    if key == 27:
        break

cv2.destroyAllWindows()

 

위 코드에서도 볼 수 있듯이 cv2.blur()를 이용하는것이다.

 

cv2.blur을 이용하면 Convolution Filter를 자동으로 만들어줘

 

Average Bluring이 된다.

 

[ Result ]

 

original image
Bluring Image

 

 

2. Gaussian Bluring

 

모든 pixel에 똑같은 가중치를 부여했던 Average Bluring과 달리

Gaussian Bluring은 Convolution Filter Kernel의 중심에 있는 원소에

높은 가중치를 부여합니다

 

Gaussian Blurring Filter
Gaussian Distribution

Gaussian Blurring Filter에서 볼 수 있듯이

가운데의 Pixel값이 가장 크며 가장자리에서 멀어질 수록

점점 Pixel Value가 낮아지는것을 볼 수 있다.

 

1 / 273을 곱해주는 이유는 위 사진의 Gaussian Filter에 있는

모든 원소의 합이 273이기 때문이다. 

 

Gaussian Blurring이 주로 사용되는 이유는 보통 에지 검출 전

노이즈를 제거하기 위해 사용된다고 한다.

 

코드를 살펴봅시다.

 

import cv2
import numpy as np

img = cv2.imread("./test.png")
Gaussian_blur = cv2.GaussianBlur(img, (5, 5), 0)
ave_blur = cv2.blur(img, (5,5))

merged = np.hstack((img, Gaussian_blur, ave_blur))

while True:
    cv2.imshow("Merged", merged)

    key = cv2.waitKey(0)

    if key == 27:
        break

cv2.destroyAllWindows()

주요 코드를 살펴봅시다

 

Gaussian_blur = cv2.GaussianBlur(img, (5, 5), 0)

cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)

 

src = img

ksize = Size Of Kernel

sigmaX = X방향 표준편차 ( 0 = Auto )

sigmaY = Y방향 표준편차 ( Default = sigmaY )

 

openCV에서는 Gaussian Blurring을 할 때에

GaussianBlur() 함수를 이용하면 Kernel도 쉽게 자동으로 만들어주고

Destination Pixel 역시 쉽게 만들 수 있다.

 

※ cv2.getGaussianBlur()를 이용하면 kernel을 만들 수도 있음

 

[ Result ]

 

Original, Gaussian, Average

왼쪽부터 차례대로 Original Img, Gaussian Blurring Img, Average Blurring Img이다.

 

여기서 관심있게 살펴봐야 되는것은 Gaussian vs Average이다.

 

Gaussian Blurring은 확실히 Average Blurring 보다는

Noise가 제거되고 선명한것을 볼 수 있다.

 

 

3. Median Blurring

 

이번에는 Median Blurring이다.

 

우선 Median Blurring은 Kernel의 Pixel들을 크기 순으로 정렬한 후에

Pixel의 중간값을 선정해 사진를 Blurring 해주는 기술이다.

 

Median Blurring은 흔히들 말하는 소금-후추 잡음을

제거하는데에 가장 효과적이다.

 

하지만 edge가 있는 이미지의 경우에는 edge가 사라질 수 있다는

단점이 존재합니다.

 

코드를 살펴봅시다.

 

import cv2
import numpy as np

img = cv2.imread("./median.png")
median = cv2.medianBlur(img, 5)

merged = np.hstack((img, median))

while True:
    cv2.imshow("Merged", merged)

    key = cv2.waitKey(0)

    if key == 27:
        break

cv2.destroyAllWindows()

주요 코드를 살펴보자

 

median = cv2.medianBlur(img, 5)

cv2.medianBlur(src, ksize)

 

src = img

ksize= Kernel Size

 

medianBlurring은 간단하다

 

[ Result ]

 

medianBlurring

왼쪽은 Original Img이며, 오른족은 Median Blurring이 적용된 이미지이다.

 

확실히 소금-후추 잡음이 없어진 것을 볼 수 있다.

 

 

4. Bilateral Filtering

 

위에서 공부한 Blurring 종류는 속도는 빠르지만

edge가 보존되지 않는 경우가 있었습니다.

 

이번에는 Bilateral Filtering입니다.

 

Bilateral Filtering은 Gaussian Filter와 Boundary Filter가 결합되어 있는 기술입니다.

 

위의 Blurring들과 대비해서 edge가 잘 보존됩니다.

 

edge도 뚜렷하게 잘 보존되고 noise가 잘 제거된다는 강점이 있지만

처리 속도가 느리다는 단점이 있습니다.

 

코드로 가봅시다.

 

import cv2
import numpy as np

img = cv2.imread("./texture.png")
blur = cv2.bilateralFilter(img, 9, 75, 75)

merged = np.hstack((img, blur))

while True:
    cv2.imshow("merged", merged)

    key = cv2.waitKey(1)

    if key == 27:
        break

cv2.destroyAllWindows()

어렵지 않으니 바로 주요 코드를 봅시다

 

blur = cv2.bilateralFilter(img, 9, 75, 75)

cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst, BorderType)

 

src = img

d = Filter의 직경(Diameter) => 5보다 크면 느림

sigmaColor = ColorArea의 Sigma ValuesigmaSpace = PositionArea의  Sigma Value

 

일반적으로 sigmaColor == sigmaSpace를 하며 두 Argument의 값의 범위를 1 ~ 150으로 권장

 

[ Result ]

Bilateral Filter

왼쪽이 Original Image이고 오른쪽이 Bilateral Filter가 적용된 이미지이다.

 

이미지에서 질감이 느껴지는 부분을 Noise로 인식하여 제거되었지만

Edge가 잘 보존되어 있는 것을 볼 수 있다.

 

그런가..?

 

어쨌든 오늘 내용이 좀 길어져서

다음에 이어서 써야겠다

 

오늘도 끄-읕😑

'openCV' 카테고리의 다른 글

[openCV] Morphology  (0) 2021.03.12
[openCV] Convolution & Mask (2)  (0) 2021.03.06
[openCV] Image Geometric Transformation (2)  (0) 2021.02.21
[openCV] Image Geometric Transformation (1)  (0) 2021.02.20
[openCV] ROI  (0) 2021.02.17