250x250
Notice
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 막내의막무가내 프로그래밍
- 막내의막무가내 알고리즘
- 막내의막무가내 rxjava
- 막내의 막무가내
- 막내의막무가내 안드로이드 에러 해결
- 프래그먼트
- 막내의막무가내 안드로이드 코틀린
- 막내의막무가내 일상
- 막내의막무가내 목표 및 회고
- 2022년 6월 일상
- 막내의막무가내 SQL
- 막내의막무가내 안드로이드
- 막내의막무가내 코틀린 안드로이드
- 막내의막무가내
- 막내의막무가내 플러터 flutter
- 막무가내
- 주택가 잠실새내
- 막내의막무가내 플러터
- 막내의 막무가내 알고리즘
- flutter network call
- 막내의막무가내 코볼 COBOL
- 안드로이드 sunflower
- 안드로이드 Sunflower 스터디
- 부스트코스
- 부스트코스에이스
- 프로그래머스 알고리즘
- 막내의막무가내 코틀린
- Fragment
- 주엽역 생활맥주
- 안드로이드
Archives
- Today
- Total
막내의 막무가내 프로그래밍 & 일상
[OpenCV] Gaussian Filtering 구현 본문
728x90
Blur +Filtering은 여러가지 방식이 있습니다. (Gaussian , box, median, Sobel 등등)
블러와 필터링을 아주 간략하게 설명하면 블러는 말 그대로 영상을 흐리게 하는 기능이고 픽셀의 색상값을 어떠한 공식으로 바꾸냐에 따라 여러가지 블러 효과가 나올 수 있고 해당 블러공식이 적용된 특정 크기의 Kernel 을 만들어 이미지를 이 Kernel로 한칸한칸 이동하면서 블러효과를 적용하는 필터링 과정을 진행하게 됩니다. (제가 간략하게 정리한거라 다른 문서 참고바랍니다...)
그 중 가우시안 블러링은 중심에 있는 픽셀에 높은 가중치를 부여합니다.
이 Gaussian blur 를 사용한 filtering을 구현 해봤고 1D, 2D 시간차이를 비교해봤습니다.
https://en.wikipedia.org/wiki/Gaussian_filter
구현을 위한 Gaussian filter 공식은 다음과 같습니다.
[공식]
[
[코드]
import cv2
import numpy as np
import time
# 바깥쪽 패딩 채우기
def my_padding(img, shape, boundary=0):
'''
:param img: boundary padding을 해야할 이미지
:param shape: kernel의 shape
:param boundary: default = 0, zero-padding : 0, repetition : 1, mirroring : 2
:return: padding 된 이미지.
'''
row, col = len(img), len(img[0])
pad_sizeY, pad_sizeX = shape[0] // 2, shape[1] // 2
res = np.zeros((row + (2 * pad_sizeY), col + (2 * pad_sizeX)), dtype=np.float)
pad_row, pad_col = len(res), len(res[0])
if pad_sizeY == 0:
res[pad_sizeY:, pad_sizeX:-pad_sizeX] = img.copy()
elif pad_sizeX == 0:
res[pad_sizeY:-pad_sizeY, pad_sizeX:] = img.copy()
else:
res[pad_sizeY:-pad_sizeY, pad_sizeX:-pad_sizeX] = img.copy()
if boundary == 0:
return res
elif boundary == 1:
res[0:pad_sizeY, 0:pad_sizeX] = img[0, 0] # 좌측 상단
res[-pad_sizeY:, 0:pad_sizeX] = img[row - 1, 0] # 좌측 하단
res[0:pad_sizeY, -pad_sizeX:] = img[0, col - 1] # 우측 상단
res[-pad_sizeY:, -pad_sizeX:] = img[row - 1, col - 1] # 우측 하단
# axis = 1, 열반복, axis = 0, 행반복. default 0
res[0:pad_sizeY, pad_sizeX:pad_col - pad_sizeX] = np.repeat(img[0:1, 0:], [pad_sizeY], axis=0) # 상단
res[pad_row - pad_sizeY:, pad_sizeX:pad_col - pad_sizeX] = np.repeat(img[row - 1:row, 0:], [pad_sizeY],
axis=0) # 하단
res[pad_sizeY:pad_row - pad_sizeY, 0:pad_sizeX] = np.repeat(img[0:, 0:1], [pad_sizeX], axis=1) # 좌측
res[pad_sizeY:pad_row - pad_sizeY, pad_col - pad_sizeX:] = np.repeat(img[0:, col - 1:col], [pad_sizeX],
axis=1) # 우측
return res
else:
res[0:pad_sizeY, 0:pad_sizeX] = np.flip(img[0:pad_sizeY, 0:pad_sizeX]) # 좌측 상단
res[-pad_sizeY:, 0:pad_sizeX] = np.flip(img[-pad_sizeY:, 0:pad_sizeX]) # 좌측 하단
res[0:pad_sizeY, -pad_sizeX:] = np.flip(img[0:pad_sizeY, -pad_sizeX:]) # 우측 상단
res[-pad_sizeY:, -pad_sizeX:] = np.flip(img[-pad_sizeY:, -pad_sizeX:]) # 우측 하단
res[pad_sizeY:pad_row - pad_sizeY, 0:pad_sizeX] = np.flip(img[0:, 0:pad_sizeX], 1) # 좌측
res[pad_sizeY:pad_row - pad_sizeY, pad_col - pad_sizeX:] = np.flip(img[0:, col - pad_sizeX:], 1) # 우측
res[0:pad_sizeY, pad_sizeX:pad_col - pad_sizeX] = np.flip(img[0:pad_sizeY, 0:], 0) # 상단
res[pad_row - pad_sizeY:, pad_sizeX:pad_col - pad_sizeX] = np.flip(img[row - pad_sizeY:, 0:], 0) # 하단
return res
# Gaussian kernel 생성 코드를 작성해주세요.
def my_getGKernel(shape, sigma):
'''
:param shape: 생성하고자 하는 gaussian kernel의 shape입니다. (5,5) (1,5) 형태로 입력받습니다.
:param sigma: Gaussian 분포에 사용될 표준편차입니다. shape가 커지면 sigma도 커지는게 좋습니다.
:return: shape 형태의 Gaussian kernel
'''
# a = shape[0] , b = shape[1] , (s = 2a+1, t = 2b+1)
s = (shape[0] - 1) / 2
t = (shape[1] - 1) / 2
# 𝑠,𝑡 가 –a~a, -b~b의 범위를 가짐 , np.ogrid[-m:m+] : -m~m까지 증가하는 array를 반환한다.
# 𝑥 :−𝑏~𝑏 범위의 Kernel에서의 x좌표(열) , 𝑦 :−𝑎~𝑎 범위의 Kernel에서의 y좌표(행)
y, x = np.ogrid[-s:s + 1, -t:t + 1]
# e^-(x^2 + y^2)/2𝜎^2
# - np.exp(x) : 𝑒^𝑥 를 구한다
gaus_kernel = np.exp(-(x * x + y * y)) / (2. * sigma * sigma)
# arr.sum() : array의 값을 모두 더해 반환한다.
sum = gaus_kernel.sum()
gaus_kernel /= sum
return gaus_kernel
def my_filtering(img, kernel, boundary=0):
'''
:param img: Gaussian filtering을 적용 할 이미지
:param kernel: 이미지에 적용 할 Gaussian Kernel
:param boundary: 경계 처리에 대한 parameter (0 : zero-padding, default, 1: repetition, 2:mirroring)
:return: 입력된 Kernel로 gaussian filtering이 된 이미지.
'''
# 이미지 행열
row, col = len(img), len(img[0])
# 커널 행열, arr.shape : array의 shape를 나타낸다
ksizeY, ksizeX = kernel.shape[0], kernel.shape[1]
pad_image = my_padding(img, (ksizeY, ksizeX), boundary=boundary) # 패딩처리
filtered_img = np.zeros((row, col), dtype=np.float32) # 음수 소수점 처리위해 float형
# filtering 부분
for i in range(row):
for j in range(col):
filtered_img[i, j] = np.sum(
np.multiply(kernel, pad_image[i:i + ksizeY, j:j + ksizeX])) # filter * image
return filtered_img
# 1000x500 img read by grayscale(0)
src = cv2.imread('img/mtjin_filtering.jpg', 0)
# get Gaussian Kernal 필터 크기 홀수 x 홀수인 모든 필터를 만족해야한다.
gaus2D = my_getGKernel((51, 51), 13)
gaus1D = my_getGKernel((1, 51), 13)
start = time.perf_counter() # 시간 측정
# 2D filtering
img2D = my_filtering(src, gaus2D)
end = time.perf_counter()
print("2D:", end - start)
start = time.perf_counter()
# 1D filtering
img1D = my_filtering(src, gaus1D)
img1D = my_filtering(img1D, gaus1D.T)
end = time.perf_counter()
print("1D:", end - start)
cv2.imshow('img1D', img1D.astype(np.uint8))
cv2.imshow('img2D', img2D.astype(np.uint8))
cv2.waitKey()
cv2.destroyAllWindows()
[결과]
둘다 블러 처리가 됨을 느낄 수 있고 1D가 2D 필터링보다 빠르다. 연산 수가 줄어들어 filtering 속도가 빨라집니다.
1. 원래사진
2. 2D 필터링
3. 1D 필터링
728x90
'OpenCV' 카테고리의 다른 글
[OpenCV] 함수 정리 (0) | 2020.03.26 |
---|---|
[OpenCV] bgr 이미지 -> grayscale 이미지로 변환 (grayscale 구현) (0) | 2020.03.26 |
[openCV] HSV 특정색 검출하기 (0) | 2019.07.15 |
[openCV] 이미지 이진화 하기 (0) | 2019.07.14 |
[openCV] 동영상 관련 (0) | 2019.07.11 |
Comments