Python/파이썬 OpenCV 공부

[파이썬 OpenCV] 이진 영상 처리 - 지역 이진화 - cv2.adaptiveThreshold

AI 꿈나무 2020. 10. 10. 19:28
반응형

황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.

 

예제 코드 출처 :  황선규 박사님 github홈페이지

 

『OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝』

예제 소스 코드는 아래 링크를 참고하세요

sunkyoo.github.io


 

 

[파이썬 OpenCV] 이진 영상 처리 - 자동 이진화 - Otsu 방법

황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다. 예제 코드 출처 :  황선규 박사님 github홈페이지 『OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝』 �

deep-learning-study.tistory.com

 이전 포스팅에서는 자동으로 임계값을 설정해주는 Otsu 이진화 방법에 대해 공부해보았습니다.

 이번에는 균일하지 않은 조명 환경에서 찰영된 영상에서 사용할 수 있는 지역 이진화에 대해 알아보겠습니다.

 

지역 이진화

 균일하지 않은 조명 환경에서 찰영된 영상에서 사용할 수 있습니다.

 

 

 이처럼 불균일한 조명이 있는 영상에서는 이진화 결과가 지저분하게 나옵니다.

 이를 해결하기 위해서는 지역 이진화 방법을 이용해야 합니다.

 

 두 가지 지역 이진화 방법에 대해 알아보겠습니다.

 

1. 구역을 나눠서 Otsu 이진화 사용하기

 전체 구역을 N등분 하고 각각의 구역에 이진화를 한 뒤에 이어 붙이는 방법입니다.

 여러 개의 임계값을 이용하게 됩니다.

 

예제 코드

src = cv2.imread('rice.png', cv2.IMREAD_GRAYSCALE)

# 입력 영상 불러오기
if src is None:
    print('Image load failed!')
    sys.exit()
    
# 전역 이진화
_, dst1 = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

# 지역 이진화
dst2 = np.zeros(src.shape, np.unit8) # 검정색 영상

# 넓이 / 4, 높이 / 4
bw = src.shape[1] // 4
bh = src.shape[0] // 4

# 가로 세로 4등분 하기
for y in range(4):
    for x in range(4):
        src_ = src[y*bh:(y+1)*bh, x*bw:(x+1)bw]   # threshold 입력값으로 주기 위해 입력 영상도 등분
        dst_ = dst2[y*bh:(y+1)*bh, x*bw:(x+1)*bw] # dst_를 변경하면 dst2도 변경됍니다.
        
        # dst_를 입력인자로 주었습니다.
        # dst_를 입력인자로 입력하면 dst_를 입력이자 출력으로 받을 수 있습니다.
        # _, dst_ = cv2.~ 로 값을 받게 되면 등분한 dst_ 정보는 사라집니다.
        cv2.threshold(src_, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU, dst_)
        
# 결과 출력
cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
cv2.destroyAllWindows()

원본 영상
전역 이진화

 

지역 이진화

 

 전역 이진화와 지역 이진화 영상을 비교했을 때 아랫 부분에서 확연한 차이를 볼 수 있습니다.

 

2. OpenCV 적응형 이진화 - cv2.adaptiveThreshold

 OpenCV에서 제공하는 적응형 이진화 함수입니다.

 가우시안 블러를 적용하여 노이즈를 제거한 뒤에 Otsu 이진화를 적용합니다.

 방법 1 보다 더 느립니다.

 

함수 설명

cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None) -> dst

• src: 입력 영상. 그레이스케일 영상
• maxValue: 임계값 함수 최댓값. 보통 255.
• adaptiveMethod: 블록 평균 계산 방법 지정. cv2.ADAPTIVE_THRESH_MEAN_C는 산술 평균, cv2.ADAPTIVE_THRESH_GAUSSIAN_C는 가우시안 가중치 평균
• thresholdType: cv2.THRESH_BINARY 또는 cv2.THRESH_BINARY_INV 지정
• blockSize: 블록 크기. 3 이상의 홀수
• C: 블록 내 평균값 또는 블록 내 가중 평균값에서 뺄 값. (x, y) 픽셀의 임계값으로 𝑇(𝑥, 𝑦) = 𝜇(𝑥, 𝑦 )− 𝐶 를 사용

 

 blosize는 크게 줘야 합니다. 작게 주면 결과가 좋지 않습니다.

 또한 3 이상의 홀수를 입력해야 하며 경우에 따라 51 X 51을 이용할 때도 있습니다.

 

 C는 임계값을 결정하는 파라미터입니다.

 픽셀의 임계값으로 T(x,y) = u(x,y) - C를 이용합니다.

 

예제 코드

src = cv2.imread('sudoku.jpg', cv2.IMREAD_GRAYSCALE)

if src is None:
    print('Image load failed!')
    sys.exit()

# 블럭 사이즈
def on_trackbar(pos):
    bsize = pos
    
    # 짝수면 -1
    if bsize % 2 == 0:
        bsize = bsize - 1
        
    # 3보다 작으면 무조건 3
    if bsize < 3:
        bsize = 3

    dst = cv2.adaptiveThreshold(src, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                cv2.THRESH_BINARY, bsize, 5) # C값은 5를 줌

    cv2.imshow('dst', dst)


cv2.imshow('src', src)
cv2.namedWindow('dst')
cv2.createTrackbar('Block Size', 'dst', 0, 200, on_trackbar)
cv2.setTrackbarPos('Block Size', 'dst', 11)

cv2.waitKey()
cv2.destroyAllWindows()

 

원본 영상

 

블럭 사이즈 : 11

 

블럭 사이즈 128

 

 블럭 사이즈를 너무 작게 주면 블럭 안에 배경이나 객체만 존재하는 상황이 생깁니다.

 이 경우에 픽셀값의 차이가 적어 지저분하게 결과가 출력될 수 있습니다.

 감사합니다. 

 

반응형