이전 장에서 학습한 HSV포맷을 기준으로 2D Histogram 분석을 진행하겠다 

 

1. 2D Histogram 

  • calcHist()  : 1D와 마찬가지로 calcHist 함수를 이용하여 HSV 포맷의 Hue와 Saturation의 histogram을 생성하겠다
from typing import no_type_check
import cv2
import numpy as np
from matplotlib import pyplot as plt

image = cv2.imread('test.jpg')
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
hist = cv2.calcHist(hsv_image,[0,1], None, [360,256], [0,360,0,256])
stack_hist = np.stack((hist,)*3,axis=-1)
print('image의 shape \t\t: ',image.shape)
print('hist의 shape \t\t: ',hist.shape)
print('stack hist의 shape \t: ',stack_hist.shape)

fig = plt.figure(figsize=(8,3))
plt.tight_layout()
plt.subplot((131)),plt.imshow(image)
plt.subplot((132)),plt.imshow(hist)
plt.subplot((133)),plt.imshow(stack_hist)

plt.show()

  • 기존 1D Histogram을 그릴 때와 변경된 부분은
    4번째 파라미터인 x축 간격이 2개의 값을 넘겨 x와 y축으로 변경되었고
    5번째 파라미터인 축의 범위또한 x, y 각각 0~360 , 0~256의 범위로 설정되었다 
  • 1D 일 때는 ply.plot으로 그래프를 그렸지만 2D에서는 imshow를 통해 보였다 그 이유는 1D에서는 각 그 값에 해당하는 픽셀의 개수를 표현했지만 2D에서는 H일 때 S 픽셀이 있나 를 표현해서 0, 1 의값이 리턴된다 그렇기 때문에 plot으로 2D를 그리면 0과 1만 표현된다 
  • hist의 결과값은 H, S 2개의 값이 리턴되기 때문에 shape이 (360,256)이 된다 위에 가운데 사진에 보다시피 imshow로 보였을 때 잘 구분이 되지 않는다 
  • 좀더 보기 쉽게 np.stack을 통해 RGB 같은 (360,256,3)의 shape으로 변경하였다
  • 여기서 의문이 생긴다 각 값이 0과 1로 표현됐는데 왜 결괏값으로 보이는 이미지는 왜 검은색과 하얀색으로 표현되나 하얀색은 255가 아닌가? matplotlib.pyplot에서 0과 1로 되어있는 데이터는 자동으로 0,255로 변경해준다 

  • 자 이제 나온 결과값을 해석해 보자 
  • 세로의 값은 Hue를 뜻한다 (100,110) 정도에 점이 찍혀있다 그 뜻은 Hue:110, Saturation:100이란 뜻이므로 약간 어두운 초록색 부분이 많다는 뜻이다 사진에서 숲의 영역을 뜻한다
  • 또한 H:160~250 S:150~200 까지의 부분에 점이 몰려있다 그 뜻은 밝은 하늘색이 다양한 밝기와 색상으로 존재한다는 뜻이다 사진에서 바다와 하늘을 뜻한다

 

다음장에서는 바운딩 박스를 읽어와

해당 바운딩박스 내에 객체들이

어떤 특성을 가지고 있는지 분석해 보겠다

이미지 형태, 비디오 형태의 분석을 위한 기초 분석 

 

1. cv2.calcHist(images, channels, mask, histSize, ranges)

  • images : 분석 대상 이미지 (uint8 or float32) 
  • channels : 분석 채널 grayscale은 [0], color는 [0],[0,1] : 1 Blue 2:Green 3: Red
  • mask : 이미지의 분석 영역, None 은 전체 영역 
  • histSIze : 분석 값 x축의 간격 하나의 
  • range : x 축 범위  
import cv2
import os 
import numpy as np
from matplotlib import pyplot as plt

image = cv2.imread('test.jpg', cv2.IMREAD_COLOR)
image = cv2.resize(image, (512,512))
# image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# 0 : Blue, 1: Green, 2: Red
blue_hist = cv2.calcHist([image],[0],None,[256],[0,256])
green_hist = cv2.calcHist([image],[1],None,[256],[0,256])
red_hist = cv2.calcHist([image],[2],None,[256],[0,256])

plt.subplot(111), 
plt.plot(blue_hist , color='b'), 
plt.plot(green_hist, color='g'), 
plt.plot(red_hist, color='r'),

cv2.imshow('test',image)

plt.xlim([0,256])

plt.show()

 

  • 위의 코드에서 주석처리된 부분에 cvt color 부분을 주석 처리한 이유는 opencv는 기본적으로 모든 색상 순서가 BGR로 되어있다. 그래서 변환 없이 바로 imshow로 보여주면 bgr을 bgr로 보여주기 때문에 cv2.imshow를 할 때는 ctvCOLOR를 이용할 이유가 없다. 하지만 plt.imshow()의 경우는 ctvCOLOR를 이용하여 보여줘야 원래 이미지대로 볼 수 있다. 

    같은 이미지이지만 왼쪽은 cv2.imshow()이고 오른쪽은 plt.imshow()이다 
  • 왼쪽은 cv2.imshow()를 한 이미지, 오른쪽은 plt.imshow()를 한 이미지 
  • cv2.imshow는 BGR로 불러와 내보낼 때도 BGR로 내보내지만 cv2로 읽어온 객체를 plt로 내보내면 RGB 순서로 돼있
  • 다는 가정하에 읽어오기 때문에 파란 이미지가 빨간색으로 표현된다 


    BGR과 RGB가 햇갈려서 테스트를 통해 확인하였다
  • cv2.calcHist의 2번째 파라미터는 0: blue, 1:green, 2:red 이다 
  • 각각 히스토그램의 shape를 찍어본 이유는 cv2.calcHist의 return value를 확인하기 위해서다. 각 1차원의 결괏값을 가진다 

  • 다음과 같이 hist의 return 값은 x와 y 축의 2차원 배열이다 shape은 (256,1) 로써 첫 차원에는 0~ 255까지의 pixel의 개수가 포함되어 있다
  • 왼쪽 사진은 위의 파란 이미지의 BGR 히스토그램 return값을 print 한것이다 
    Blue는 255 색상뿐이여서 0, 0, 0이라 나왔고 
    green과 red는 0 색상뿐이여서 배열의 첫 번째인 0 값이 해당 이미지의 넓이만큼 나왔다 ( 512x 512 = 262144 ) = blue는 모두 255이고 green, red는 모두 0이다라는 뜻 

2. calcHist mask 

  • calcHist에 파라미터인 mask를 추가하여 특정 영역의 히스토그램을 추출할 수 있다 
  • 차량의 레이블을 생성하여 읽어와 해당 레이블 영역의 히스토그램을 추출하여 보겠다 
    # print(image.dtype) : uint8
    mask = np.zeros(image.shape[:2], np.uint8)
    mask[box_ymin:box_ymax, box_xmin:box_xmax ] = 255
    
    mask_image = image[box_ymin:box_ymax, box_xmin:box_xmax]
    
    blue_hist = cv2.calcHist([image],[0],mask,[256],[0,256])
    green_hist = cv2.calcHist([image],[1],mask,[256],[0,256])
    red_hist = cv2.calcHist([image],[2],mask,[256],[0,256])
    
    plt.subplot(221),plt.imshow(image)
    plt.subplot(222),plt.imshow(testtestest)
    plt.subplot(223),plt.imshow(mask_image)
    plt.subplot(224), plt.plot(blue_hist, color='b'),plt.plot(green_hist, color='g'),plt.plot(red_hist, color='r')
    plt.xlim([-10,266])
    
    plt.show()​

  • 기존의 calcHist 함수에 None으로 돼있던 위치에 mask 값을 추가하였다 
  • mask 는 해당 이미지에서 추출할 영역을 선택한다 
  • 중요한 점은 cv2.imread()로 읽어온 이미지는 uint8형 자료이기 때문에 mask를 적용할 때 mask의 값 또한 uint8로 맞춰줘야 한다 그렇기 때문에 mask = np.zeros()를 할 때 dtype=np.uint8로 지정하였다 

 

소스코드https://github.com/dldidfh/tistory_code/blob/master/%ED%9E%88%EC%8A%A4%ED%86%A0%EA%B7%B8%EB%9E%A8/histogram_opencv.py

 

GitHub - dldidfh/tistory_code

Contribute to dldidfh/tistory_code development by creating an account on GitHub.

github.com

 

+ Recent posts