본문 바로가기
AI 컴퓨터 비전프로젝트

[DL] 오츠의 이진화(스레숄드값을 자동으로 잡아주기)

by 바다의 공간 2024. 10. 3.

이번에는 오츠의 이진화를 통해서 쓰레숄드값을 자동으로 잡아주려고합니다.

이전예제인 이진화에서는 직접 100,150,200 등 찾아주었는데 이번같은경우는 오츠의 이진화를 통해서 

자동으로 임계값을 구하게 만들어주려고합니다.

 

사용할 이미지는 위와 같습니다(rice)쌀.

 


## otus

3. 오츠의 이진화 알고리즘( 오츠의이진화 = 자동 이진화를 하고싶을 때 사용하는 알고리즘)
- 자동 이진화 알고리즘
- 자동으로 임계값을 구해줌 (임계값을 구분하는 가장 좋은 방법으로 찾아줌)
- cv2.threshold(영상, 임계값(암거나 넣어도 됨 0넣어도됨), 최대값, 플래그|cv2.THRESH_OTSH)
- 임계값을 임의로 정해 픽셀을 두 부류로 나누고 두 부류의 명암 분포를 구하는 작업을 반복하여 

모든 경우의 수 중에서 두 부류의 명암 분류가 가장 균일할 때의 임계값을 선택해줌

import cv2
img = cv2.imread('./rice.png',cv2.IMREAD_GRAYSCALE)

th, dst = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
print(f'otsu: ', th)

th, dst1 = cv2.threshold(img, 131, 255, cv2.THRESH_BINARY)

cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.imshow('dst1', dst1)
cv2.waitKey()

 

원래는 thresh값에 임계값을 직접 넣어줘야하는데 이번에는 0을 넣었습니다.

이렇게되어도 상관이없는것이 오츠알고리즘을 사용하면 자동으로  임계값(스레숄드)를 잡아줍니다 

그렇기때문에 thresh값에 0(아무숫자잡아도 상관없음)을 넣습니다. 

그리고 잡아보면 otsh : 131값이 나오게 되는데 그 값을 가지고 다시 살행을 해보면 

 

이렇게 나오게됩니다. 그런데 오른쪽을 보면 쌀 뿐만 아니라 다른것도 잡은것같아요

그리고 원본 밑에를 보면 아래쪽은 좀 더 어두운데이런 곳에서 오브젝트는 잘 못잡는것같습니다.

 

실제로 쓰레숄드값을 131로 했었을때는 어떨지 궁금해서 dst1변수로 잡고 진행해봤는데

결과는 역시 똑같이 나옵니다!

 

만약 특정부위를 뽑고싶다면 빛의밝기, 어두운부분이 좀 나뉘어져있기때문에 이부분에 대한

전처리를 잘 해야하는데 하는 방법이 지역이진화 입니다. 


#이진화

4. 지역 이진화
- 균일하지 않은 조명 환경에서 사용하는 이진화 방법
- 전체구역을 n등분하고 각각의 구역에 이진화를 한 뒤에 이어 붙이는 방법을 사용
- 여러개의 임계값을 이용할 수 있다는장점이 생김
- 오츠처럼 자동으로 계산해줍니다.

import cv2
import numpy as np

img = cv2.imread('./rice.png', cv2.IMREAD_GRAYSCALE)

#전역 자동 이진화
_, dst1 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)

#지역 자동 이진화(4*4)
#가로세로 크기 확인하기
#zeros로 만들었기 때문에 검정색 도화지가 됨
dst2 = np.zeros(img.shape, np.uint8)
#세로를 4로 나눈 정수값을 취함
bw = img.shape[1] // 4
#가로를 4로 나눈 정수값을 취함
bh = img.shape[0] // 4

for y in range(4):
    for x in range(4):
        # 한 칸씩 옆으로 가는것
        img_ = img[y*bh: (y+1)*bh, x*bw: (x+1)*bw]
        dst_ = dst2[y*bh: (y+1)*bh, x*bw: (x+1)*bw]
        #빛 자동 이진화시키기
        cv2.threshold(img_, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU, dst_)

cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()

 

 

#전역 자동 이진화

_, = 스레숄드값은 받지 않도록 합니다. 그리고 자동이진화를 합니다.

 

지역이진화를 하려면 일단 크기를 알아야합니다. 

bw, bh를 하는 이유는 전체적인 크기를 맞춰주기 위해서 입니다. 

 

for 구문에서는 16바퀴를 돌면서 이미지에서 이진화 해서  dst(검정)영상으로 넣습니다.

그 구문이 cv2.threshold절 입니다.

이렇게 빛때문에 잘 안되는 부분을 지역으로 해서 나눠서 처리를 해주면됩니다.