OpenCV - Gray와 Binary (이진화)

songmin jeon·2024년 1월 4일
0

0. Gray와 Binary 이미지

  • 시각은 색상정보에 대해 잘못된 정보를 보내주는 경우가 많음
    • 밤에 색상을 볼때 정확한 색상을 보여주지 못함 - 명도 (검정색이 섞이는 것)
    • 색상에 빛을 강하게 비추는 경우 정확한 색상을 보여주지 못함 - 채도 (흰색이 섞이는 것)
  • 칼라는 너무 많은 정보를 가지고 있기때문에 연산량이 많음
    • 실시간 처리가 어려움
    • 따라서 gray 이미지나 binary 이미지로 변환해서 처리하는 것이 일반적

0.1. Gray와 Binary 차이

  • gray 이미지 : 0-255로 된 픽섹로만 구성된 흑백이미지

  • binary(이진) 이미지 : 0(검정색)과 255(흰색)으로만 구성된 이미지 (마스크 패턴, 필터링)

  • Gray -> 회색
    픽셀값을 0~255의 범위로 표현하는 방식
    픽셀 채널이 1인 경우 흑백
    픽셀 채널이 3인 경우 컬러

  • 픽셀 채널이 1인 경우
    0 -> 검은색
    255 -> 흰색
    127 -> 회색

  • Binar -> 이진(2개)

  • 픽셀값을 0과 255의 범위로 표현하는 방식


1. gray 이미지 만들기


사용 명령어

  • 칼라 → gray 이미지 변환 방법 2가지
  1. imread()로 이미지를 읽을 때 변환해서 읽는 방법
	img = cv2.imread(파일명, cv2.IMREAD_GRAYSCALE)

  1. 칼라 이미지로 읽어서 cvtColor() 변환하는 방법 → 칼라 이미지가 필요한 경우 (출력)
	img_gray = cv2.cvtColor(이미지객체, cv2.COLOR_BGR2GRAY)

1.1. imread()를 사용해서 gray 이미지로 변환해서 읽는 방법

import cv2
import matplotlib.pyplot as plt

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

# interpolation = 보건법 설정
# 보건법 : 이미지 픽셀이 비어있는 곳을 채워주는 방법
plt.imshow(img, cmap ='gray', interpolation='bicubic')
plt.xticks([])
plt.yticks([])
plt.title('model')
plt.show()


1.2. 칼라이미지로 읽어서 gray 이미지로 변환하는 방법

# 실습
import cv2
import matplotlib.pyplot as plt

img = cv2.imread('images/lenna.png', cv2.IMREAD_COLOR)

# BGR 컬러 이미지를 gray 이미지로 변환
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

plt.imshow(gray_img, cmap='gray')
plt.yticks([])
plt.xticks([])
plt.show()


2. 이진 (Binary) 이미지 만들기

  • 이진 이미지는 픽셀값이 0과 1(255)로만 구성
  • 이진 이미지의 필요 : 배경과 객체의 구분, 관심영역과 비관심 영역의 구분, 마스크 생성 등

주요 명령어

_, thr = cv2.threshold(img, threshold_value, value, flag)

  • img : Grayscale 이미지

  • threshold_value : 픽셀 문턱값 (경계를 기준으로 0과 1로 나누기 위한 기준값)

  • value : 문턱값보다 클 때 적용되는 값

  • flag : 문턱값 적용 방법

    • cv2.THRESH_BINARY : 픽셀값이 문턱값보다 크면 value, 아니면 0을 할당
    • cv2.THRESH_BINARY_INV : 픽셀값이 문턱값보다 크면 0, 아니면 value를 할당
    • cv2.THRESH_TRUNC : 픽셀값이 문턱값보다 크면 문턱값, 아니면 픽셀값을 그대로 할당
    • cv2.THRESH_TOZERO : 픽셀값이 문턱값보다 크면 픽셀값, 아니면 0을 할당
    • cv2.THRESH_TOZERO_INV : 픽셀값이 문턱값보다 크면 0, 아니면 픽셀값을 할당

2.1. 실습 (flag 값에 따른 출력 비교)

import cv2
import matplotlib.pyplot as plt

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

#  _ : 첫번째 반환 값을 쓰지 않겠다 선언.
# thr : 쓰래스 홀드 의 약자
plt.figure(figsize=(8,8))
#######################################################
plt.subplot(2, 2, 1)
_, thr1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)

plt.imshow(thr1, cmap='gray')

plt.xticks([])
plt.yticks([])
plt.title('THRESH_BINARY_INV')
#######################################################
plt.subplot(2,2,2)
_, thr1 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)

plt.imshow(thr1, cmap='gray')

plt.xticks([])
plt.yticks([])
plt.title('THRESH_BINARY_INV')
#######################################################
plt.subplot(2,2,3)
_, thr1 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO )

plt.imshow(thr1, cmap='gray')

plt.xticks([])
plt.yticks([])
plt.title('THRESH_BINARY_INV')
#######################################################
plt.subplot(2,2,4)
_, thr1 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)

plt.imshow(thr1, cmap='gray')

plt.xticks([])
plt.yticks([])
plt.title('THRESH_BINARY_INV')


2.2. threshold() 함수를 이용하여 다른 이미지를 아래와 같이 변환해보자.

# 실습
# flag 값에 따른 출력 비교
plt.figure(figsize=(8,8))
plt.subplot(2, 2, 1)
_, thr1 = cv2.threshold(img, 100, 255, cv2.THRESH_TOZERO )

plt.imshow(thr1, cmap='jet')

plt.xticks([])
plt.yticks([])
plt.title('jet')

plt.subplot(2, 2, 2)
_, thr1 = cv2.threshold(img, 100, 255, cv2.THRESH_TOZERO  )

plt.imshow(thr1, cmap='spring')

plt.xticks([])
plt.yticks([])
plt.title('spring')
plt.show()

3. 임계값 결정 : OTSU 알고리즘과 적응형

3.1. 임계값 결정하기 1 : OTSU 알고리즘

  • 이진 이미지를 만들때 가장 중요한 요소 : 임계값 설정
  • OTSU의 이진화 알고리즘
    • 임계값을 임의로 정하고 픽셀을 두 분류로 나눔
    • 두 분류의 명암 분포를 구하는 작업을 반복
    • 두 분류의 명암 분포가 가장 균일할 때의 임계값을 선택
  • OTSU의 이진화 알고리즘 적용하기
    • 임계값을 -1로하고 옵션을 THRESH_OTSU로 설정하여 이진화
  • 단점 : 모든 경우의 수를 조사해야 하므로 속도가 느림

3.1.1. OTSU 알고리즘 실습문제

# 실습
import cv2
import matplotlib.pyplot as plt

img = cv2.imread('images/news_paper.jpg', cv2.IMREAD_GRAYSCALE)

# 우리가 경계값을 설정해줘 보자!
_, thr1 = cv2.threshold(img, 125, 255, cv2.THRESH_BINARY)

plt.imshow(thr1, cmap='gray')
plt.xticks([])
plt.yticks([])
plt.title('binary')
plt.show()

# 오츠 알고리즘을 이용해서 경계값을 찾아보자 !
t, thr2 = cv2.threshold(img, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

plt.imshow(thr2, cmap='gray')
plt.xticks([])
plt.yticks([])
plt.title(f'otsu{t}')
plt.show()


3.2. 임계값 결정 : 적응형 thresholding

사용 코드

cv2.adaptiveThreshold(img, value, method, type_flag, block_size, C)

  • img : 입력영상
  • value : 임계값을 만족하는 픽셀에 적용할 값
  • method : 임계값 결정 방법
  • cv2.ADAPTIVE_THRESH_MEAN_C : 이웃 픽셀의 평균으로 결정
  • cv2.ADAPTIVE_THRESH_GAUSSIAN_C : 가우시안 분포에 따른 가중치의 합으로 결정
  • type_flag : 스레시홀딩 적용 방법 (cv2.threshod()와 동일)
  • block_size : 영역으로 나눌 블록의 크기(n x n), 홀수
  • C : 계산된 임계값 결과에서 가감할 상수(음수 가능)

3.2.1. 실습

# 실습
import cv2
import matplotlib.pyplot as plt

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

# 일반 이진화
_, thr1 = cv2.threshold(img, 123, 255 ,cv2.THRESH_BINARY)
# 오프 알고리즘
_, thr2 = cv2.threshold(img, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

# 적응형 Threshold
blk_size = 9 # 블럭의 사이즈
C = 5 # 임계값의 차감 상수

thr3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY , blk_size, C)
thr4 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY , blk_size, C)

# 이진화된 이미지 출력
plt.figure(figsize=(8,8))
plt.subplot(2,2,1)
plt.imshow(thr1, cmap='gray')
plt.xticks([])
plt.yticks([])
plt.title('binary')
#############################################
# 오즈 알고리즘 이미지 출력
plt.subplot(2,2,2)
plt.imshow(thr2, cmap='gray')
plt.xticks([])
plt.yticks([])
plt.title(f'otsu:{t}')
#############################################
# 이진화된 이미지 출력
plt.subplot(2,2,3)
plt.imshow(thr3, cmap='gray')
plt.xticks([])
plt.yticks([])
plt.title('AD_TH_MEAN_C')
#############################################
# 가우시안 이미지 출력
plt.subplot(2,2,4)
plt.imshow(thr4, cmap='gray')
plt.xticks([])
plt.yticks([])
plt.title('AD_TH_GAU_C')


4. 학습요약

○ 칼라이미지를 gray 이미지로 변환하는 방법

  • imread() 함수로 직접 변환하는 방법
  • 칼라이미지로 읽은 후에 cvtColor() 함수로 변환하는 방법

○ gray 이미지를 binary로 변환하는 방법

  • threshold() 함수를 사용하는 방법
  • OTSU 이진화 알고리즘을 사용하는 방법
  • adaptiveThreshold() 함수를 사용하는 방법
profile
제가 한 번 해보겠습니다.

0개의 댓글