본문 바로가기
OpenCV/OpenCV-Chapter

CH03 Opencv-Python Histogram backprojection

by kiimy 2021. 12. 18.
728x90

히스토그램 역투영(Histogram backprojection)

* 영상의 각 픽셀이 주어진 히스토그램 모델에 얼마나 일치하는지를 검사하는 방법

* 임의의 색상 영역을 검출할 때 효과적

* 확률론적 의미를 가지고 있음(역투영 이미지)

cv2.calcBackProject(images, channels, hist, ranges, scale, dst=None) -> dst

import cv2
import sys
import matplotlib.pyplot as plt

src = cv2.imread('ch03\\images\\cropland.png')

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

# ROI 창 생성(드래그 할 수 있음) / spacebar 누르면 ROI 적용됨
x, y, w, h = cv2.selectROI('ROI', src)
print(x, y, w, h)

# Histogram(RGB가 아닌 YCrCb가 임의의 색추출에 용의)
src_ycrcb = cv2.cvtColor(src, cv2.COLOR_BGR2YCrCb)
crop = src_ycrcb[y:y+h, x:x+w] # ROI 

channels = [1,2] # Y: 밝기 정보라 필요 X(Cr, Cb)
cr_bins = 128 # 0~255, 256을 써야하지만 128( 결과는 비슷함 )
cb_bins = 128
histsize = [cr_bins, cb_bins]
cr_range = [0,256] # 256 = 255까지의 값이기 때문에 
cb_range = [0,256]
ranges = cr_range + cb_range
print(ranges) ## [0,256,0,256]

'''
cv2.normalize(cv2.log(hist + 1)) 
= Histogram이 큰 애들은 너무 큰 값이 나오기 때문에 큰 몇개의 픽셀만 밝게 나옴
= 나머지는 0에 가까운 검정색이 나옴. so, log값이 0이 나올수 있으니 +1을 해줌
hist 그래프 = plt.plot(hist)

# *mask = 특정영역(mask)에서만 Histogram을 계산하고 싶다면*
'''
hist = cv2.calcHist([crop], channels, None, histsize, ranges, cv2.CV_8U)
hist_norm = cv2.normalize(cv2.log(hist+1), None, 0, 255, cv2.NORM_MINMAX)

# cv2.calcBackProject = cv2.calcHist와 인자값이 비슷하다
# 하지만 calcHist는 Histogram을 출력으로 내주는 것이고
# calcBackProject는 calcHist를 입력으로 받고 그 histogram과 부합되는 영역만
# 0보다 큰 값으로 되있는 확률과 같은 개념의 이미지를 반환
# backproj = grayscale 
backproj = cv2.calcBackProject([src_ycrcb], channels, hist, ranges, 1)
dst = cv2.copyTo(src, backproj) 
# cv2.copyTo : ROI를 지정한 backproj(grayscale) = 흰 부분만 가져오기

ROI / Hist_norm(Cr,Cb)
projection / copyTo

# 특정 mask만 추출시

src1 = cv2.imread('ch03\\images\\kids1.png')
mask = cv2.imread('ch03\\images\\kids1_mask.bmp', cv2.IMREAD_GRAYSCALE)
print(mask.shape) # grayscale로 안불러오면 d= 3

if src1 is None or src2 is None or mask is None:
    print('Image load failed')
    sys.exit()

# 임의의 색을 추출하기위한 변환
src1_ycrcb = cv2.cvtColor(src1, cv2.cv2.COLOR_BGR2YCrCb)

channels = [1,2]
histSize = [128, 128]
ranges = [0,256,0,256] # Cr, Cb 범위 지정

# *mask = 특정영역(mask)에서만 Histogram을 계산하고 싶다면*
# histsize = 픽셀의 범위는 0 ~ 255
# ranges = 픽셀 범위의 값들을 계산하기위함
hist = cv2.calcHist([src1_ycrcb], channels, mask, histSize, ranges)

hist_norm = cv2.normalize(cv2.log(hist+1), None, 0, 255, \
                            cv2.NORM_MINMAX, cv2.CV_8U) # cv2.CV_8U default

backproj = cv2.calcBackProject([src1_ycrcb], channels, hist, ranges, 1)
728x90

댓글