이 글의 원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.html#histograms-getting-started 입니다.
아래 그림을 보면..
이미지에 대해 어떤 그래프를 표시하고 있는데, 화소의 강도(Gray 값 또는 하나의 채널에 대한 값)를 갖는 화소의 개수를 각각 X축과 Y축으로 표시하고 있습니다. 대부분의 경우 화소의 강도는 0-255입니다.
히스토그램을 얻는 방법은 Numpy를 이용하는 것과 OpenCV를 이용하는 것이 있습니다. 먼저 OpenCV를 이용한 예제를 보면..
import cv2 img = cv2.imread('./data/home.jpg',0) hist = cv2.calcHist([img],[0],None,[256],[0,256])
4번째 cv2.calcHist 함수가 이미지에 대한 히스토그램 정보를 얻는데, 이 함수의 첫번째는 입력 이미지의 배열이며 두번째는 히스토그램을 얻을 채널 인덱스, 세번째는 Mask 이미지, 네번째는 X 축 요소(BIN)의 개수이고 다섯번째는 Y 축 요소값의 범위로 하나의 채널에 대한 화소 강도가 0~255이므로 대부분의 경우 [0,256]이 됩니다. 이 함수의 반환값은 256개의 요소를 갖는 배열입니다.
Numpy를 이용하여 히스토그램을 얻는 코드는 다음과 같습니다.
import cv2 import numpy as np img = cv2.imread('./data/home.jpg',0) hist,bins = np.histogram(img.ravel(),256,[0,256])
5번째 코드의 np.histogram 함수가 히스토그램을 얻는 함수인데 반환값은 반환값은 256개의 요소를 갖는 배열인 hist와 X축 요소의 값을 나타내는 배열인 bins입니다. 이 함수 이외에도 hist = np.bincount(img.ravel(),minlength=256) 와 같은 더 빠른 함수가 가능합니다.
속도면에서 Numpy보다 OpenCV 방식이 훨씬 빠르므로 OpenCV를 사용하는 것이 좋습니다.
히스토그램 값을 그래프로 표시하기 위한 예제는 다음과 같습니다.
import cv2 from matplotlib import pyplot as plt img = cv2.imread('./data/home.jpg',0) plt.hist(img.ravel(), 256, [0,256]); plt.show()
결과는 다음과 같습니다.
BGR 형태와 같이 3개의 채널로 구성된 이미지에 대한 각 채널의 히스토그램도 시각화가 가능한데, 관련된 예제는 다음과 같습니다.
import cv2 from matplotlib import pyplot as plt img = cv2.imread('./data/home.jpg') color = ('b','g','r') for i,col in enumerate(color): histr = cv2.calcHist([img],[i],None,[256],[0,256]) plt.plot(histr,color = col) plt.xlim([0,256]) plt.show()
결과는 다음처럼 3개 채널 각각의 히스토그램 결과가 표시됩니다.
지금까지는 히스토그램 분석을 이미지 전체에 대해서 수행했는데, 필요할 경우 이미지의 원하는 영역에 대한 마스크를 지정해 해당 영역에 대한 히스토그램만을 분석할 수 있습니다. 아래의 코드가 예입니다.
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('./data/home.jpg',0) # create a mask mask = np.zeros(img.shape[:2], np.uint8) mask[100:300, 100:400] = 255 masked_img = cv2.bitwise_and(img,img,mask = mask) # Calculate histogram with mask and without mask # Check third argument for mask hist_full = cv2.calcHist([img],[0],None,[256],[0,256]) hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256]) plt.subplot(221), plt.imshow(img, 'gray') plt.subplot(222), plt.imshow(mask,'gray') plt.subplot(223), plt.imshow(masked_img, 'gray') plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask) plt.xlim([0,256]) plt.show()
결과는 다음과 같습니다.
혹시 이미지말고 영상으로 하려면 어떻게 해야하나요?
OpenCV는 입력소스를 동영상에서 간단히.. 이미처와 동일한 자료 구조로 얻을 수 있습니다. 자세한 내용은 역시 꾸글링이 최고죠..