오늘은 이진화에 대해서 정리하려한다😑
이진화는 무엇일까?
우선 이진화는 원본 Image를 바로 Binarization을 시킬 수가 없다.
원본 Image -> GrayScale -> Binary Image로
Binarization을 위해서는 GrayScale을 한번 거쳐야 한다.
"아니 그래서 이진화가 뭐냐니까?"
이진화를 이해하기 앞서 Threshold라는 용어를 짚고 넘어가겠다.
Threshold는 임계값을 의미하며 사용자가 특정 수치값을 정해두면 그 기준값을 통해서 값을 도출한다.
쉽게 말하면 그냥 어떤 조건을 판별할때 이용하는 기준값이라고 생각하면 될 거 같다.
이진화는 Segmentation 방법 중 가장 간단한 방법에 속한다.
Segmentation은 Image를 분리하여서 원하는 부분 혹은 물체를 검출할 때 사용하는 기법이다.
즉 이진화는 GrayScale Image의 pixel값을 Threshold를 기준으로
분리를 하여 Segmentation을 할 수 있다.
openCV에서 이진화를 할 떄 사용하는 함수에 대해서 알아보자.
고것은 바로 cv2.threshold(img, threshold_value, value, flag)라는 함수이다.😉
cv2.threshold()의 Argument를 하나하나 살펴보자면
img : 이진화를 할 GrayScale Image 지정
threshold_value : 임계값 지정
value = threshold를 기준으로 크고 작을때에 적용할 value
flag = 임계값 적용 스타일이다. flag는 5가지가 있다.
Flag 종류
1. cv2.THRESH_BINARY = 픽셀값이 지정한 임계값보다 크면 value 값을 부여, 작으면 0을 부여
2. cv2.THRESH_BINARY_INV = 픽셀값이 지정한 임계값보다 크면 0을 부여, 작으면 value 값을 부여
3. cv2.THRESH_TRUNC = 픽셀값이 지정한 임계값보다 크면 임계값을 부여, 작으면 픽셀값을 그대로 사용
4. cv2.THRESH_TOZERO = 픽셀값이 지정한 임계값보다 크면 픽셀값을 그대로사용, 작으면 0을 부여
5. cv2.THRESH_TOZERO_INV = 픽셀값이 지정한 임계값보다 크면 0을 부여, 작으면 픽셀값을 그대로 사용
이제 진짜 코드를 보면서 정리해보자😶
1. Using Global Threshold
import cv2
import sys
import imutils
img_color = cv2.imread("./apple.png", cv2.IMREAD_COLOR)
if img_color is None:
print("Failed")
sys.exit(1)
#GrayScale Change
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
#Threshold == 127
#Binary Flag == THRESH_BINARY
#If Pixel's value is less than 127 and Pixel's value = 0
#Else Pixel's Value = 1
retval, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
#Resize
img_gray = imutils.resize(img_gray, height = 500, width = 500)
img_binary = imutils.resize(img_binary, height = 500 , width = 500)
while True:
cv2.imshow("Grayscale", img_gray)
cv2.imshow("Binary", img_binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
하나하나 뜯어보자
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
이 코드는 많이 봤으니 다들 알텐데 Image를 GrayScale로 변환시켜준다.
#Threshold == 127
#Binary Flag == THRESH_BINARY
#If Pixel's value is less than 127 and Pixel's value = 0
#Else Pixel's Value = 1
retval, img_binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
이 부분이 진짜 Binarization을 하는 부분이다.
현재 Argument에는
IMG = img_gray (GrayScale)
Threshold = 127
value = 255
flag = cv2.THRESH_BINARY
즉 img_gray의 픽셀값을 검증하여 픽셀값이 127보다 낮으면 pixel값에 0 (검정색)을 부여하고
127보다 높다면 pixel값에 255 (하얀색)을 부여한다.
[ Result ]
2. Using_GUI_With_Binarization
이번에는 저번주에 다루었던 openCV에서 지원하는 GUI 함수들을 이용해서
Binarization을 할 떄 Threshold를 지정해보겠다.
import cv2
import sys
import imutils
#CallBack Function
def on_trackbar(x):
pass
img_color = cv2.imread("./apple.png", cv2.IMREAD_COLOR)
if img_color is None:
sys.exit(1)
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
img_gray = imutils.resize(img_gray, width = 500, height = 500)
cv2.imshow("GrayScale", img_gray)
#Plus Window Trackbar
cv2.namedWindow("Binary")
#Create Trackbar
cv2.createTrackbar('threshold', "Binary", 0, 255, on_trackbar)
#Set Pos TrackBar
cv2.setTrackbarPos('threshold', "Binary", 127)
while True:
#Get value of TrackbarPos
thresh = cv2.getTrackbarPos('threshold', "Binary")
#If pixel's value is less than threshold and pixel's color is white
retval, img_binary = cv2.threshold(img_gray, thresh, 255, cv2.THRESH_BINARY_INV)
img_binary = imutils.resize(img_binary, width = 500, height = 500)
cv2.imshow("Binary", img_binary)
if(cv2.waitKey(1) & 0xFF == 27):
break
cv2.destroyAllWindows()
조금 길지만 당황하지 말고 하나하나 살펴보자
#Plus Window Trackbar
cv2.namedWindow("Binary")
#Create Trackbar
cv2.createTrackbar('threshold', "Binary", 0, 255, on_trackbar)
#Set Pos TrackBar
cv2.setTrackbarPos('threshold', "Binary", 127)
cv2.namedWIndow()는 TrackBar를 window에 추가한다.
cv2.createTrackbar은 이름 그대로 TrackBar을 생성한다
cv2.setTrackbarPos는 Trackbar의 pos값을 가져온다.
#Get value of TrackbarPos
thresh = cv2.getTrackbarPos('threshold', "Binary")
#If pixel's value is less than threshold and pixel's color is white
retval, img_binary = cv2.threshold(img_gray, thresh, 255, cv2.THRESH_BINARY_INV)
cv2.getTrackbarPos는 TrackBar의 value를 가져온다.
어김없이 또 나왔다. cv2.threshold()
IMG = img_gray (GrayScale)
Threshold = thresh (Trackbar's value)
value = 255
Flag = cv2.THRESH_BINARY_INV
만약 pixel의 값이 Threshold보다 작다면 무조건 흰색으로 보여준다.
[ Result ]
위에서 설명 안한 코드들은 저번 주에 다루었던 GUI에서
설명이 되어 있는 경우가 많으니 참고해주십셔😏
confidence-10211.tistory.com/75
3. Adaptive Binarization
만약 위 Image들처럼 하나의 임계값을 사용해도 충분히 Segmentation이 되는 Image들이 있습니다.
하지만 Image의 일부분이 너무 어둡다면 하나의 Threshold로는 구별이 안될수가 있습니다.
예를 들자면
위 이미지을 토대로 하나의 Threshold값으로 Binarizaiton을 해보겠습니다.
Threshold를 높였을때 온전한 얼굴의 형태를 잡지 못하거나
Threshold를 낮췄을때는 얼굴이 전부 검은색으로 나옵니다.
이럴때 필요한 함수가 cv2.adaptiveThreshold입니다.
cv2.adaptiveThreshold를 이용하면 Image의 Small Area부터 Thresholding이 가능합니다.
쉽게 말하자면 Adative한 Binarization이 가능해지는겁니다.
cv2.adaptiveThreshold의 Argument를 살펴봅시다.
cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, flag, blockSize, C)
src = GrayScale Image
maxValue = value
adaptiveMethod = thresholding value를 정하는 계산 방법
flag = 위 flag와 동일
blockSize = Thresholding을 적용할 Area
C = Average에서 차감할 값
adaptive Method 종류
cv2.ADAPTIVE_THRESH_GAUSSIAN_C: Pixel의 (X, Y)를 중심으로 block Size * block Size 안에 있는 Gaussian window 기반가중치들의 합에서 C를 뺀 값을 Threshold값으로 한다.
cv2.ADAPTIVE_THRESH_MEAN_C: Pixel의 (X, Y)를 중심으로 block Size * block Size 안에 있는
픽셀 값의 평균에서 C를 뺸 값을 Threshold값으로 함
코드를 보면서 다시 한번 정리해보자
import cv2
import sys
import imutils
img_color = cv2.imread("./half_dark.jpg", cv2.IMREAD_COLOR)
if img_color is None:
print("Failed")
sys.exit(1)
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
img_binary = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5 , 4)
img_gray = imutils.resize(img_gray, height = 500, width = 500)
img_binary = imutils.resize(img_binary, height = 500, width = 500)
while True:
cv2.imshow("GrayScale", img_gray)
cv2.imshow("Binary", img_binary)
if(cv2.waitKey(1) & 0xFF == 27):
break
cv2.destroyAllWindows()
다른 부분은 위의 코드와 동일하니 cv2.adaptiveThreshold()부분만 보자
img_binary = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5 , 4)
IMG = img_gray (Grayscale)
255 = Value
adaptiveMethod = cv2.ADAPTIVE_THRESH_MEAN_C
flag = cv2.THRESH_BINARY
blockSIze = 5
C = 4
그럼 Pixel의 (x, y) 좌표로부터 5 * 5의 영역의 평균을 구해서
4만큼을 뺴주는 것이 이 코드의 Threshold의 값이 될 것이다.
[ Result ]
한결 깨끗하게 Segmentation이 된 모습을 볼 수 있다.
흐어 요즘에 너무 바빠졌는데 조금 많이 힘들기 시작했다.
이 글도 새벽 5시에 써서 그런지 내용도 중구난방에 오타가 있을수도 있다.
오늘도 끄-읕😧
'openCV' 카테고리의 다른 글
[openCV] Draw Function (0) | 2021.02.06 |
---|---|
[ openCV ] Image Operation ( Blending, Operate Image Bit, ROI ) (0) | 2021.02.02 |
[openCV] Graphic User Interface (0) | 2021.01.16 |
[openCV] Numpy Array (1) | 2021.01.09 |
openCV - 기초부터 다지기 (0) | 2021.01.02 |