Pynote

Python、機械学習、画像処理について

OpenCV - calcHist() で画像のヒストグラムを作成する

試した環境

calcHist()

OpenCVcalcHist() で画像から指定したチャンネルのヒストグラムを計算できる。

hist = cv2.calcHist(
    images, channels, mask, histSize, ranges[, hist[, accumulate]])
  • 引数
    • images: 画像の一覧。
    • channels: ヒストグラムを計算するチャンネルの一覧。
    • mask: マスクの一覧。
    • histSize: 各チャンネルのビン数
    • ranges: 各チャンネルのヒストグラムの範囲。この範囲外の画素値は集計対象外となる。
    • hist: 引数経由で結果を受け取る場合、指定する。
  • 返り値

channels, histSize, ranges 引数の指定方法が少々複雑である。

1次元ヒストグラム

ch は1次元ヒストグラムを計算するチャンネルを指定する。
bins はビンの数、l, u はヒストグラムを作成する範囲 [l, u) を指定する。
bins=[15], ranges=[0, 256] とした場合、[0, 255] を15等分したビンが作成される。

hist = cv2.calcHist(
    [img], [ch], None, histSize=[bins], ranges=[l, u])


2次元ヒストグラム

ch1, ch2 は2次元ヒストグラムを計算するチャンネルを指定する。
bins1 はチャンネル ch1 のビンの数、l1, u1 はチャンネル ch1 のヒストグラムを作成する範囲 [l1, u1) を指定する。
bins2 はチャンネル ch2 のビンの数、l2, u2 はチャンネル ch2 のヒストグラムを作成する範囲 [l2, u2) を指定する。

hist = cv2.calcHist(
    [img], [ch1, ch2], None, histSize=[bins1, bins2], ranges=[l1, u1, l2, u2])

bins=[15, 17], ranges=[0, 256, 0, 256] とした場合、
x 軸は [0, 255] を15等分、y 軸は [0, 255] を17等分したビンが作成される。


グレースケール画像の1次元ヒストグラムを作成する。

使用した画像

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

img = cv2.imread('sample.jpg', cv2.IMREAD_GRAYSCALE)  # 画像を読み込む。

# 1次元ヒストグラムを作成する。
hist = cv2.calcHist([img], [0], None, histSize=[256], ranges=[0, 256])
hists.append(hist)
# 描画する。
fig, ax = plt.subplots()
ax.plot(hist, color='gray', label='brightness')
ax.set_xlim([0, 256])
ax.set_xlabel('Pixel Value')
ax.legend()
plt.show()


カラー画像の1次元ヒストグラムを作成する。

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

img = cv2.imread('sample.jpg')  # 画像を読み込む。
ch_names = {0: 'blue', 1: 'green', 2: 'red'}  # チャンネルとその意味

# 1次元ヒストグラムを作成する。
hists = []
channels = [[0], [1], [2]]
for ch in channels:
    hist = cv2.calcHist([img], ch, None, histSize=[256], ranges=[0, 256])
    hists.append(hist)

# 描画する。
fig, ax = plt.subplots()
for hist, [ch] in zip(hists, channels):
    ax.plot(hist, color=ch_names[ch], label=ch_names[ch])
ax.set_xlim([0, 256])
ax.set_xlabel('Pixel Value')
ax.legend()
plt.show()


HSV 画像の2次元ヒストグラムを作成する。

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

# 画像を読み込む。
img = cv2.imread('sample.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

ch_names = {0: 'Hue', 1: 'Saturation', 2: 'Brightness'}
# 2次元ヒストグラムを作成する。
hists = []
channels = [[0, 1], [0, 2], [1, 2]]
for ch in channels:
    hist = cv2.calcHist(
        [hsv], ch, None, histSize=[32] * 2, ranges=[0, 256] * 2)
    hists.append(hist)

ヒートマップで描画する。

# 描画する。
fig = plt.figure(figsize=(12, 8))
for i, (hist, ch) in enumerate(zip(hists, channels), 1):
    xlabel, ylabel = ch_names[ch[0]], ch_names[ch[1]]

    ax = fig.add_subplot(1, 3, i)
    ax.imshow(hist, interpolation='nearest', cmap='jet')

    # 2Dヒストグラムを描画する。
    ax.set_title('2D Histogram for {} and {}'.format(xlabel, ylabel))
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
plt.show()


参考