728x90

목표

-단순 이진화, 적응적 이진화, 오츠 이진화

 

 

단순 이진화

- 이진화는 간단하게 임계값보다 크다면 1, 아니면 0을 주는 간단한 문제

 -> cv2.thresold 함수 사용. 명암영상만 가능

- 둘째 매개변수는 이진화에 사용할 임계값.

- 3번째 매개변수는 픽셀의 최대값

- 냇쨰 파라미터로 아래와 같은 것들이 있음.

   cv2.THRESH_BINARY

   cv2.THRESH_BINARY_INV

   cv2.THRESH_TRUNC

   cv2.THRESH_TOZERO

   cv2.THRESH_TOZERO_INV

 

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/gradient.png',0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in xrange(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

plt.show()

 

1. 원본 영상 

2. 이진화 : 명암값 127 기준으로

3. 역이진화 : 127보다 작으면 1

4. truc : 127보다 작으면 0

...

 

 

 

 

 

 

 

적응적 이진화

- 조금전 예제에선 임계치값을 지정해줌

- 빛이 비쳐 그늘 생긴 이미지에선 안좋음 -> 적응적 이진화 사용

- 영상 일부분을 서로 다른 이진화 값 사용 -> 모든 영역에 다른 이진화 값을 적용하여 조명 변화시에도 좋은 결과 나옴

 

적응적 이진화 파라미터

- 적응화 방법

   cv2.ADAPTIVE_THRESH_MEAN_C : 주위 영역의 평균값을 임계치로 사용

   cv2.ADAPTIVE_THRSH_GAUSSIAN_C : 가우시안 윈도우로 주위 픽셀들의 가중치 합을 임계치로 사용

- BLOCK SIZE : 주변 공간 크기

- C : 상수로 평균과 가중치에서 얼마만큼 -할지 지정하는값

* 반환값 ret은 나중에 설명

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/dave.jpg',0)
img = cv2.medianBlur(img,5)

ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

 

 

 

 

 

 

 

 

오츠 이진화

- 이전에 살펴본 전역적인 이진화에선 특정한 임계값을 사용

  => 이 임계값이 좋은지 나쁜지 알려면 시행착오(trial and error)를 해야함

- 하지만 양봉 이미지(히스토그램상 봉우리가 2개인) 경우를 생각해보면 양 봉우리의 평균을 근사해서 임계치를 사용해야함 -> 오츠 이진화가 수행

 => 이미지 히스토그램으로 자동으로 임계치 계산 해줌

 

오츠 이진화 코드

- cv2.threshold() 함수를 사용. 플래그 cv2.THRESH_OTS 추가. 임계값은 0으로 설정

- 다음 예시에서 노이즈 영상 사용

- 1번째 케이스는 전역 임계치를 127로 설정

- 2번째는 오츠 이진화를 바로 수행

- 셋째는 5 x5 가우시안 커널로 노이즈 제거후 오츠 이진화 수행

 

 

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/noisy2.png',0)

# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]

for i in range(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()

 

 

 

 

 

 

 

오츠 이진화 동작 방법

- 양봉 이미지에서 오츠 이진화를 수행할떄, 오츠 알고리즘은 두 가중화된 클래스의 분산을 최소화 하는 임계치를 찾음

 

 

=>  두 클래스의 분산이 최소가 되는 값 t를 찾게됨

- 위 식을 아래와 같이 구현할 수 있다.

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('C:/Users/do/Documents/github/opencv_python/res/noisy2.png',0)
blur = cv2.GaussianBlur(img,(5,5),0)

# find normalized_histogram, and its cumulative distribution function
hist = cv2.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()

bins = np.arange(256)

fn_min = np.inf
thresh = -1

for i in range(1,256):
    p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
    q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
    b1,b2 = np.hsplit(bins,[i]) # weights

    # finding means and variances
    m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
    v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2

    # calculates the minimization function
    fn = v1*q1 + v2*q2
    if fn < fn_min:
        fn_min = fn
        thresh = i

# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print(thresh)
print(ret)

 

 

오츠 이진화 알고리즘 수행과정 

- 수식 

1. 이미지 읽고 블러링

 

2. 히스토그램을 구하고, 정규화 후 누적 확률 분포(위 식에서 q) 얻기

3. 이진화 구간, 파라미터 설정

4. i 값에 따라 정규화 히스토그램, 누적합, 이진화 구간 분리

 

5. 4에서 구한 확률들과 두 클래스의 누적확률분포, 이진화 구간(가중치로 사용)으로 기대값 계산

 

6. 오츠 임계화에 필요한 omega^2구하기

 - [가중치(이진 구간) - 기대값]^2 * i일 확률 / 누적확률분포

 

 

 

7. 오츠 최소화 함수 계산

- 모든 픽셀에 대해 루프 돌면서, 비용 함수가 최소가 될때 오츠값(ft_min)과 임계치(thresh)를 구함

 

300x250

+ Recent posts