A. 흐림 효과¶
- 흐림 효과는 블러링(Blurring) 또는 스무딩(Smoothing)이라고 불리며, 노이즈를 줄이거나 외부 영향을 최소화하는데 사용된다.
- 흐림 효과는 노이즈를 제거해 연산 시 계산을 빠르고 정확하게 수행하는 데 도움이 된다.
- 이미지의 해상도를 변경할 때 존재하지 않는 데이터를 생성하거나(확대) 존재하는 데이터를 줄여(축소) 샘플링된 이미지를 재구성할 때 사용된다.
- 흐림 효과는 영상이나 이미지를 번지게 하여, 해당 픽셀을 주변 값들과 비교한다.
- 픽셀 색상을 재조정한다.
- 크게 다섯가지 종류가 있으며, 세 가지의 중요 매개변수가 있다.
세 가지 중요 매개변수¶
1. 커널과 고정점¶
- 커널은 이미지에서 $(x,y)$의 픽셀과 해당 픽셀을 포함한 작은 크기의 공간을 말한다.
- 이 "커널"에 특정 수식이나 함수를 적용해 새로운 이미지를 얻게 된다.
- 커널은 필터라고 불리기도 한다.
새로운 픽셀을 만들어내기 위해 커널 크기의 화소 값을 어떤 시스템을 통과하도록 하여 계산하는 것을 컨볼루션(Convolution)이라 한다.
- 컨볼루션의 예로
- 블러링(Blurring) : 이미지를 흐리게 만듦
- 샤프닝(Sharpening) : 이미지의 윤곽을 선명하게 만듦
- 미분(Gradient, Laplacian) : 이미지 명도의 변화량을 구함
등이 있다.
- 고정점은 커널을 통해 컨볼루션된 값을 할당한 지점이다.
- 커널 내에서 고정점은 하나의 지점을 가지며, 이미지가 어떻게 정렬되는지를 나타낸다.
- 컨볼루션을 적용할 때 이미지의 가장자리는 계산이 불가하다.
- 이 문제를 해결하기 위해 테두리의 이미지 바깥에 가상의 픽셀을 만들어 처리한다.
이 때 수행할 수 있는 방법의 종류¶
- 가상 픽셀의 값을 0으로 할당
- 커널이 연산 가능한 부분부터 연산을 수행
- 이미지의 시작과 끝을 연결해 폐곡선을 형성해서 이미지의 테두리 부분을 대신하게 함
Q1. 표 5.8(테두리 유형)을 정독해보세요.
- 고정 값으로 픽셀을 확장, 테두리 픽셀을 복사해서 확장, 픽셀을 반사해서 확장, 반대쪽 픽셀을 복사해서 확장, 이중 픽셀을 만들지 않고 반사해서 확장, reflect1010, 픽셀 투명한 확장, roi 밖은 신경 안 씀!
흐림 효과¶
- 이제 이미지를 흐림 처리 하는 방법에 대해 알아봅시다.
1. 단순 흐림 효과¶
Q2. 단순 흐림 효과 함수를 적어보고, 설명해주세요. 하나의 이미지를 불러와 흐림 효과를 적용하여 출력해보세요.
dst = cv2.blur(src, ksize, anchor, borderType)
import cv2
import os
import matplotlib.pyplot as plt
image_path = './PostingPic/cat.jpg'
image = cv2.imread(image_path)
plt.imshow(image)
<matplotlib.image.AxesImage at 0x7f10486b47d0>
dst = cv2.blur(image, (5,5))
plt.imshow(dst)
<matplotlib.image.AxesImage at 0x7f104403cbd0>
dst2 = cv2.blur(image, (16,16))
plt.imshow(dst2)
<matplotlib.image.AxesImage at 0x7f103675e950>
2. 박스 필터 흐림 효과¶
- 박스 필터 함수의 경우, 커널의 내부 값이 일반적으로 모두 같으며, 그 값은 1의 값을 갖는다.
- 하지만 normalizae의 값을 True로 설정할 경우 정규화된 박스 필터로 변경되며 커널의 모든 값이 커널의 개수만큼 나눠진다. (일반적으로 커널의 값이 모두 1일 때,커널의 개수가 33이라면 $ {1 \over 9} 1$의 값이 필터 값이 된다.)
Q3. 박스 필터 흐림 효과 함수를 읽어보고, 이미지에 박스 필터 흐림을 적용해보세요.
cv2.BoxFilter(src, ddepth, ksize, anchor, normalize, borderType)
커널 내부 값이 모두 같다
box_image1 = cv2.boxFilter(image, -1, (5,5))
plt.imshow(box_image1)
<matplotlib.image.AxesImage at 0x7f10366ce810>
box_image1 = cv2.boxFilter(image, -1, (16,16))
plt.imshow(box_image1)
<matplotlib.image.AxesImage at 0x7f103663f650>
box_image3 = cv2.boxFilter(image, cv2.CV_8U, (5,5))
plt.imshow(box_image3)
<matplotlib.image.AxesImage at 0x7f10365b13d0>
3. 중간값 흐림 효과¶
- 중간값 흐림 효과 함수는 고정점을 사용하지 않고, 중심 픽셀 주변으로 사각형 크기의 이웃한 픽셀의 중간값(평균 아님!)을 사용해 각 픽셀의 값을 변경한다.
- 즉, 고정점이 항상 커널의 중심에 있다고 가정한다.
- 중간값을 선택하기 위해서는 정사각형 형태의 커널에서 항상 중간에 있는 값을 선택해야 하므로 ksize는 홀수만 가능하다.
Q4. 중간값 흐림 효과 함수를 읽어보고, 이미지에 중간값 흐림을 적용해보세요.(커널은 항상 홀수인 것 잊지 마세요!)
dst = cv2.medianBlur(src, ksize)
median1 = cv2.medianBlur(image, ksize=3)
plt.imshow(median1)
<matplotlib.image.AxesImage at 0x7f1036592e90>
4. 양방향 필터 흐림 효과¶
- 양방향 필터 흐림 효과는 가장자리를 선명히 보존하면서 노이즈를 우수하게 제거하는 흐림 효과 함수이다.
- 양방향 필터는 두 종류의 가우시안 필터를 사용하여 흐림 효과를 적용한다.
- 양방향 필터 흐림 효과는 다른 흐림 효과 함수에 비해 느리다.(지름이 클수록 수채화처럼 변형된다.)
Q5. 양방향 필터 함수를 적어보고, 각 옵션을 설명해주세요.
dst = cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst, borderType)
Q6. 이미지를 불러와 예제 5.14(python opencv에서의 양방향 필터 흐림 효과 함수)를 적용해보세요.
bia = cv2.bilateralFilter(image, 100,33,11,borderType=cv2.BORDER_ISOLATED)
plt.imshow(bia)
<matplotlib.image.AxesImage at 0x7f10440a1250>
- 얘는 이상하게 수행시간이 조금 걸린다이
1. 영상의 필터링¶
- "필터" 라는 말은, 무언가를 걸러 내고 일부를 통과시키는 장치를 의미한다.
- 영상처리에서 필터링이란 영상에서 원하는 정보만 통과시키고 원치않은 정보는 걸러 내는 작업이다.
- 예를 들어, 영상에서 noise(잡음)를 걸러내어 영상을 깔끔하게 만들 수 있고, 영상에서 부드러운 성분을 제거하여 날카로운 느낌이 나도록 만들 수 있다.
2. 마스크를 이용한 필터링 연산 방법¶
- $m$ 은 마스크 행렬을 나타낸다.
- $f$ 와 $g$는 각각 입력 영상, 출력 영상을 나타낸다.
- 마스크를 이용한 필터링은 모든 입력 영상의 픽셀 위로 마스크 행렬을 이동시키면서 마스크 연산을 수행하는 방식으로 이루어진다.
- 마스크 연산이란 : 마스크 행렬의 모든 원소에 대하여 마스크 행렬 원소 값과 같은 위치에 있는 입력 영상의 픽셀 값을 서로 곱한 후, 그 결과를 모두 더하는 연산이다.
- 외부 픽셀에 대해서는 테두리 외삽법을 적용한다.
2. 샤프닝¶
- 샤프닝은 초점이 잘 맞은 사진처럼 사물의 윤곽이 뚜렷하고 선명한 느낌이 나도록 영상을 변경하는 필터링 기법이다.
언샤프 마스크 필터¶
- 이미 촬영된 사진을 초점이 잘 맞는 사진처럼 보이게 하려면 영상 에지 근방에서 픽셀 값의 명암비가 커지도록 해야 한다.
- 샤프닝 영상을 만들기 위해서는 블러링된 영상을 사용하여야 한다.이처럼, 언샤프한 영상을 사용하여 역으로 날카로운 영상을 생성하는 필터를 언샤프 마스크 필터 라고 한다.
- (a) : 영상의 모습. 영상의 엣지 부근에서 픽셀값이 증가하는 모양을 나타낸다.
- (b) : $f(x,y)$에 블러링을 적용한 모습(삐쭉한 값을 부드럽게 증가하도록 수정한 모양이다.)
- (c) : 원본 값에서 수정한 값을 빼서, 차이를 드러나도록 한 것이다.
- (d) : 원본에 (c)를 더해서 차이가 더 두드러지도록 한 것이다.
Q7. 아래의 소스코드를 참고하여, 특정 이미지에 언샤프 마스크를 적용해보세요.
- opencv는 언샤프 마스크 필터를 따로 제공하지는 않으니 소스코드를 참고해야 한다.
import sys
import numpy as np
import cv2
src = cv2.imread('rose.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
sys.exit()
cv2.imshow('src', src)
for sigma in range(1, 6):
blurred = cv2.GaussianBlur(src, (0, 0), sigma)
alpha = 1.0
dst = cv2.addWeighted(src, 1 + alpha, blurred, -alpha, 0.0)
desc = "sigma: %d" % sigma
cv2.putText(dst, desc, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
1.0, 255, 1, cv2.LINE_AA)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
3. 잡음 제거 필터링¶
- 영상을 획득하는 과정에서는 항상 잡음이 포함될 수 있으므로, 전처리 과정으로 잡음 제거 필터를 사용해야 한다.
- 디지털 카메라에서 카메라 렌즈가 바라보는 장면을 원본 신호($s(x,y)$) 라고 하고, 추가되는 잡음을 ($m(x,y)$)이라고 하면
- 실제 카메라에서 획득되는 영상 신호는 다음과 같이 표현할 수 있다.
$f(x,y) = s(x,y) + m(x,y)$
- 잡음이 생성되는 방식을 잡음 모델(noise model)이라고 한다.
- 다양한 잡음 모델 중에서 가장 대표적인 잡음 모델은 가우시안 잡음 모델이다.
- (평균이 0이고, 표준편차가 10인 가우시안 분포 그래프)
- 입력 영상에서 픽셀 값이 크게 변하지 않은 평탄한 영역에 가우시안 필터를 적용할 경우, 주변 픽셀 값이 부드럽게 블러링되며 잡음의 영향도 크게 줄어든다.
- 그러나, 픽셀 값이 급격히 변경되는 엣지 영역에 가우시안 필터를 적용할 경우, 엣지 성분까지 함께 감소한다.
- 따라서 잡음이 줄면서 엣지도 함께 무뎌지기 때문에 객체의 윤곽이 흐릿하게 바뀐다.
양방향 필터¶
- 위에서 살펴본 "양방향 필터" 와 동일하다.
- 양방향 필터의 작동 방식
목적 : 엣지는 그대로 유지하면서 가우시안 잡음을 효과적으로 적용한다.
- $f$ : 입력영상
- $g$ : 출력영상
- $p, q$ : 픽셀의 좌효
- $G_{\sigma_s}$, $G_{\sigma_r}$ : 각각 표준 편차가 $\sigma_s$, $\sigma_r$인 가우시안 분포 함수

- 두 점 사이의 거리에 대한 가우시안 함수(가우시안 필터와 동작 방식이 같다)

- 두 점 사이의 픽셀 값 차이에 의한 가우시안 함수
- 두 점의 픽셀 밝기 차이가 적다면 -> 큰 가중치를 가짐
- 두 점의 픽셀 밝기 차이가 크다면 -> 적은 가중치를 가짐, 위의 공식 값은 0에 가까워지므로 에지 근방에서 가우시안 블러링 효과가 0에 가까워짐
Q8. 아래의 소스코드를 참고하여 가우시안 노이즈, 양방향 필터를 적용한 이미지를 출력해주세요.
import numpy as np
import cv2
import random
def noise_gaussian():
src = cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!').
return
cv2.imshow('src', src)
for stddev in [10, 20, 30]:
noise = np.zeros(src.shape, np.int32)
cv2.randn(noise, 0, stddev)
dst = cv2.add(src, noise, dtype=cv2.CV_8UC1)
desc = 'stddev = %d' % stddev
cv2.putText(dst, desc, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
1.0, 255, 1, cv2.LINE_AA)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
def filter_bilateral():
src = cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
return
noise = np.zeros(src.shape, np.int32)
cv2.randn(noise, 0, 5)
cv2.add(src, noise, src, dtype=cv2.CV_8UC1)
dst1 = cv2.GaussianBlur(src, (0, 0), 5)
dst2 = cv2.bilateralFilter(src, -1, 10, 5)
cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
cv2.destroyAllWindows()
미디언 필터¶
- 미디언 필터는 입력 영상에서 자기 자신 픽셀과 주변 픽셀 값 중 중간값을 선택하여 결과 영상 픽셀 값으로 설정하는 필터링 기법이다.
- 미디언 필터는 특히 잡음 픽셀 값이 주변 픽셀 값과 큰 차이가 있는 경우 효과적으로 동작한다.(솔트앤페퍼 노이즈)
def filter_median():
src = cv2.imread('lenna.bmp', cv2.IMREAD_GRAYSCALE)
if src is None:
print('Image load failed!')
return
for i in range(0, int(src.size / 10)):
x = random.randint(0, src.shape[1] - 1)
y = random.randint(0, src.shape[0] - 1)
src[x, y] = (i % 2) * 255
#여기서도 위와 똑같이 cv2 함수를 사용하고 있군요!
dst1 = cv2.GaussianBlur(src, (0, 0), 1)
dst2 = cv2.medianBlur(src, 3)
cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
cv2.destroyAllWindows()
Q9. 위의 소스코드를 참고하여, 미디언 필터를 적용한 이미지를 출력해보세요. (위에서 했지만 한번 더 적용해볼까요 ㅎㅎ)
image_path = './PostingPic/test.jpg'
image = cv2.imread(image_path)
plt.imshow(image)
<matplotlib.image.AxesImage at 0x7f1036722bd0>
median1 = cv2.medianBlur(image, 17)
plt.imshow(median1)
<matplotlib.image.AxesImage at 0x7f10363d9290>
'OpenCV > 쇼미더CV' 카테고리의 다른 글
쇼미더 CV_아홉번째 날 (0) | 2021.06.20 |
---|---|
쇼미더 CV_여덟번째 날 (0) | 2021.06.20 |
쇼미더 CV_여섯번째 날 (0) | 2021.06.20 |
쇼미더 CV_다섯번째 날 (0) | 2021.06.20 |
쇼미더 CV_넷째 날 (0) | 2021.06.20 |