오늘은 openCV에서 Convolution과 Mask에 대해서 공부해보자
0. What Is Convolution?
Convolution
입력 영상 스캔하면서 현재 위치의 픽셀에 마스크의 중심이 오도록 한 후,
마스크 범위 내에 포함되는 이웃 픽셀을 마스크의 원소와 곱하여
결과 영상의 현재 위치 값을 결정하는 것
사진과 함께 보면서 이해를 해봅시다
우선 밑 설명은 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 ]
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 ]
2. Gaussian Bluring
모든 pixel에 똑같은 가중치를 부여했던 Average Bluring과 달리
Gaussian Bluring은 Convolution Filter Kernel의 중심에 있는 원소에
높은 가중치를 부여합니다
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 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 ]
왼쪽은 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 ]
왼쪽이 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 |