전공 과목 이수2👨‍💻/디지털영상처리

커널 / 필터링

천숭이 2021. 10. 3. 21:35

# 실습 1: OpenCV 기반의 간략형 실험 - averaging kernel을 사용한 filtering

def prt_mtx(a, fmt):     # 어레이를 출력하는 함수
    print(f"\n  shape of the array={a.shape}")
    for r in range(a.shape[0]):
        for c in range(a.shape[1]):
            print(f"{a[r, c]:{fmt}}", end="")
        print()
cv.imshow('img', img)

N = 31
#N = 7
kernel = np.ones((N, N), np.float32)/(N * N)         # N*N으로 나누어 정규화한다.
print(np.sum(kernel))           # 커널의 모든 원소의 값을 합하면 1이 된다. (출력 0.9999..)
np.set_printoptions(precision=3)        # numpy 배열의 정밀도를 소수 이하 3자리로 제한하여 출력하는 것으로 설정한다.
print(kernel)
prt_mtx(kernel, '#6.2f')
# img 영상을 kernel로 필터링(코릴레이션 연산)하여 결과 dst를 반환한다.
# 출력 영상, dst는 shape가 입력 영상과 같다. => dst.shape=src.shape.
# -1은 출력 영상의 depth가 입력 영상과 같음을 의미한다. => dst.dtype=src.dtype.
dst = cv.filter2D(img, -1, kernel)
print('type(dst)=', type(dst), ' | dst.shape=', dst.shape, ' | dst.dtype=', dst.dtype )
cv.imshow('dst', dst)
cv.waitKey()
exit(0)

N=7
N=31


# 실습 2: matplotlib, OpenCV 기반의 실험 - averaging kernel을 사용한 filtering

 

1단계 : matplotlib를 적용해야 하므로 b와 r의 순서를 바꿔야한다

b, g, r = cv.split(img)   # img파일을 b,g,r로 분리
img = cv.merge([r, g, b]) # b, r을 바꿔서 Merge

2단계 : 평균필터를 만든다. 1로채워진 필터 -> 정규화 (방법두개)

kernel = np.ones((N, N), np.float32) / (N * N)
kernel = np.ones((N, N), np.float32)  # 커널 1로 채우기
kernel /= np.sum(kernel)   # 커널의 합으로 나누어 커널의 합이 1이 되도록 정규화한다.
print(np.sum(kernel)0 # 커널의 총합이 1인지 확인

3단계 : correlation 연산 시행. 여러가지 옵션값들을 적용 가능하다.

#dst = cv.filter2D(img, -1, kernel, borderType=cv.BORDER_DEFAULT)        # gfedcb|abcdefgh|gfedcba. 거울 반전
#dst = cv.filter2D(img, -1, kernel, borderType=cv.BORDER_REPLICATE )     # 맨 바깥 화소의 값이 중복된 것으로 간주.
dst = cv.filter2D(img, -1, kernel, borderType=cv.BORDER_ISOLATED )      # 경계처리 안함.

# 실습 3: matplotlib 기반의 실험 - averaging kernel을 사용한 filtering. 세로필터와 가로필터 적용해보기

1단계 : matplotlib를 적용해야 하므로 b와 r의 순서를 바꿔야한다

img = img[..., ::-1]

2단계 : Average filter Kernel 만들기. 1로채워진 필터 -> 정규화

* 이때 커널의 합이 1이 되도록 정규화해야함.

N = 51  # 필터링 강도

kernel_list = []         # 다수의 커널로 list 자료로 기록한다.

# 1) 1xN 커널 정의 - 가로로 averaging 한다.
kernel = np.ones((1, N), np.float32) / (N)      # 주의!!! N으로 나누어 커널의 합이 1이 되도록 정규화한다.
print('np.sum(kernel)=', np.sum(kernel))    # 커널의 총합을 확인.
kernel_list.append(kernel)
print(kernel.shape)

# 2) Nx1 커널 정의 - 세로로 averaging 한다.
kernel = np.ones((N, 1), np.float32)
kernel /= np.sum(kernel)   # 커널의 합으로 나누어 커널의 합이 1이 되도록 정규화한다.
print('np.sum(kernel)=', np.sum(kernel))    # 커널의 총합을 확인.
kernel_list.append(kernel)

만들어진 필터들의 정보와 내용 출력방법

print(type(kernel_list))
np.set_printoptions(precision=2)    # 소수 이하 2자리까지 출력. 이하 0이면 출력 안한다.
print('kernel=\n', kernel)          # 커널의 원소 값을 출력

3단계 : correlation 연산 시행 후  plt 결과창 출력 (위에서 만든 세로 가로 필터 적용)

fig = plt.figure(num='interactive mode', figsize=(16, 5))
plt.subplots_adjust(left=0.02, right=0.98, bottom=0.02, top=0.85)       # 상하좌우 여분 공백 제어하기
fig.patch.set_facecolor('purple')            # 화면 바탕 색상을 정한다.
fig.patch.set_alpha(0.1)        # 위에서 지정한 배경색의 투명도 -> 0이면 투명, 1이면 완전 불투명.

plt.suptitle("Averaging Filtering or Box Filtering", fontsize=14, fontweight='bold')

plt.subplot(1, 3, 1)    # 1x3 창의 첫번째 창 선택
plt.imshow(img)     # 원본 영상
plt.axis('off')
plt.title('Original')

#i = 0   # kernel index
for i, knl in enumerate(kernel_list):
    print(type(knl), knl.shape, knl.dtype)      # <class 'numpy.ndarray'> (1, 51) float32
    dst = cv.filter2D(img, -1, knl, borderType=cv.BORDER_DEFAULT)
    #print(f"dst.dtype={dst.dtype}")     # dst.dtype=uint8
    plt.subplot(132 + i)      # 1x3 창의  2번째 창부터 출력
    plt.imshow(dst)     # filtering 결과 영상
    plt.axis('off')
    plt.title('Kernel=' + str(knl.shape))
    i += 1

#plt.show()      # interactive mode 일 때는 필요 없음
plt.waitforbuttonpress()        # 키 혹은 버튼 입력을 기다린다.
# 이후 프로그램이 종료되므로 모든 창이 닫힌다.
exit(0)

131 132 133 순으로 plt.subplot