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次元ヒストグラム

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

ch は1次元ヒストグラムを計算するチャンネルを指定する。
bins はビンの数、l, u はヒストグラムを作成する範囲 [l, u) を指定する。

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


2次元ヒストグラム

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

ch1, ch2 は2次元ヒストグラムを計算するチャンネルを指定する。
bins1 はチャンネル ch1 のビンの数、l1, u1 はチャンネル ch1 のヒストグラムを作成する範囲 [l1, u1) を指定する。
bins2 はチャンネル ch2 のビンの数、l2, u2 はチャンネル ch2 のヒストグラムを作成する範囲 [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])
hist = hist.squeeze(axis=-1)

# 描画する。
fig, ax = plt.subplots()
ax.fill_between(np.arange(256), hist, color="black")
ax.set_xticks([0, 255])
ax.set_xlim([0, 255])
ax.set_xlabel("Pixel Value")

plt.show()


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

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

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

# ヒストグラムを作成する。
hists = []
channels = {0: "blue", 1: "green", 2: "red"}
for ch in channels:
    hist = cv2.calcHist([img], [ch], None, histSize=[256], ranges=[0, 256])
    hist = hist.squeeze(axis=-1)
    hists.append(hist)

# 描画する。
fig, ax = plt.subplots()
for hist, name in zip(hists, channels.values()):
    ax.fill_between(np.arange(256), hist, color=name, label=name)
ax.set_xticks([0, 255])
ax.set_xlim([0, 255])
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 に変換する。
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 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)

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

ch_names = {0: 'Hue', 1: 'Saturation', 2: 'Brightness'}

# 描画する。
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, cmap="jet")

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

plt.show()


参考