Python과 OpenCV – 23 : 히스토그램(Histogram) 4/4

이 글의 원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.html#histogram-backprojection 입니다.

2차원 히스토그램을 응용하여 이미지에서 원하는 객체만을 추출해 내는 방법인 Backprojection에 대한 코드를 살펴보겠습니다. 바로 예제 나갑니다. 상세한 설명은 원문을 참고하시기 바랍니다.

import cv2
import numpy as np

roi = cv2.imread('./data/messi5_g.jpg')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)

target = cv2.imread('./data/messi5.jpg')
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)

# calculating object histogram
roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )

# normalize histogram and apply backprojection
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)

# Now convolute with circular disc
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.filter2D(dst,-1,disc,dst)

# threshold
ret,thresh = cv2.threshold(dst,50,255,0)

# threshold and binary AND
thresh = cv2.merge((thresh,thresh,thresh))
res = cv2.bitwise_and(target,thresh)

res = np.vstack((thresh,res))

cv2.imshow('result', res)
cv2.waitKey()
cv2.destroyAllWindows()

위에서 messi5.jpg는 어떤 객체를 추출할 대상이고 messi5_g.jpg는 추출할 대상입니다. messi5.jpg는 다음과 같습니다.

messi5_g.jpg는 다음과 같은데, 이 이미지는 messi5.jpg에서 잘라내기로 추출한 이미지입니다.

즉, 이미지에서 잔디에 해당되는 영역을 추출하겠다는 것입니다. 위의 코드의 실행 결과는 다음과 같습니다.

결과로 생성된 이미지가 2개이고, 이를 하나로 합쳐서 표시한 것인데.. 위에는 잔디에 해당되는 영역에 대한 결과 마스크 이미지이고 두번째는 이 마스크 이미지와 원본 이미지에 대한 bitwise 연산을 통해 실제 잔디 영상만을 추출한 결과입니다.

Python과 OpenCV – 22 : 히스토그램(Histogram) 3/4

이 글의 원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.html#twod-histogram 입니다.

지금까지는 하나의 값을 가진 화소, 즉 Grayscale 이미지에 대한 히스토그램을 살펴봤습니다. 이를 1차원 히스토그램이라고 합니다. 이 글에서는 2차원 히스토그램에 대해 살펴봅니다. 2차원 히스토그램은 2개의 값을 가지는 화소에 대한 히스토그램으로, HSV 중 H와 S의 값을 의미합니다. H는 Hue, S는 Saturation입니다.

2차원 히스토그램을 얻는 방법은 OpenCV와 numpy 방식이 있습니다. 먼저 OpenCV 방식에 대한 코드는 다음과 같습니다.

import cv2
import numpy as np

img = cv2.imread('./data/home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

이미지를 읽고 BGR 채널을 HSV로 변환합니다. H에 대한 값의 범위는 0-180이고 S에 대한 값의 범위는 0-256라는 점을 통해 cv2.calcHist의 인자값의 의미를 이해할 수 있습니다. 이제 Numpy 방식에 대한 코드를 살펴보면..

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

img = cv2.imread('./data/home.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)

hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])

2차원 히스토그램을 그래프로 표시하는 방법으로 Matplotlib을 사용해 예제를 살펴보면…

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

img = cv2.imread('./data/home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )

plt.imshow(hist,interpolation = 'nearest')
plt.show()

실행 결과는 다음과 같습니다.

X축은 S이고 Y축은 H입니다.