OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
ヒストグラム - 3 : 2次元ヒストグラム

目的

この章では、2Dヒストグラムを求めてプロットする方法を学ぶ。今後の章で役立つ内容である。

はじめに

最初の記事では、1次元ヒストグラムを計算してプロットした。1次元と呼ぶのは、ピクセルのグレースケール強度値という1つの特徴のみを考慮しているためである。しかし2次元ヒストグラムでは、2つの特徴を考慮する。通常、各ピクセルの色相 (Hue) と彩度 (Saturation) の2つの特徴を用いるカラーヒストグラムを求めるのに使われる。

カラーヒストグラムを求めるためのpythonサンプル (samples/python/color_histogram.py) はすでに存在する。本稿ではこのようなカラーヒストグラムをどのように作成するかを理解しようと試みる。これはヒストグラム逆投影 (Histogram Back-Projection) のような後続のトピックを理解する上で役立つ。

OpenCVにおける2Dヒストグラム

これは非常に単純で、同じ関数 cv.calcHist() を使って計算する。カラーヒストグラムでは、画像を BGR から HSV に変換する必要がある。(1Dヒストグラムでは BGR からグレースケールに変換したことを思い出してほしい。) 2Dヒストグラムでは、引数を次のように変更する。

  • channels = [0,1] H プレーンと S プレーンの両方を処理する必要があるため。
  • bins = [180,256] H プレーンに 180、S プレーンに 256。
  • range = [0,180,0,256] 色相値は 0 から 180 の間、彩度は 0 から 256 の間にある。

では以下のコードを確認しよう。

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
Converts an image from one color space to another.
void calcHist(const Mat *images, int nimages, const int *channels, InputArray mask, OutputArray hist, int dims, const int *histSize, const float **ranges, bool uniform=true, bool accumulate=false)
Calculates a histogram of a set of arrays.

これで完了である。

Numpyにおける2Dヒストグラム

Numpyにもこのための専用関数がある: np.histogram2d()。(1Dヒストグラムでは np.histogram() を使ったことを思い出してほしい。)

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])

第1引数は H プレーン、第2引数は S プレーン、第3引数は各プレーンのビン数、第4引数はそれらの範囲である。

次に、このカラーヒストグラムをプロットする方法を確認しよう。

2Dヒストグラムのプロット

方法1 : cv.imshow() を使う

得られる結果はサイズ 180x256 の2次元配列である。したがって、通常通り cv.imshow() 関数を使って表示できる。これはグレースケール画像となり、異なる色の色相値を知らない限り、どのような色があるのかはあまり分からない。

方法2 : Matplotlibを使う

matplotlib.pyplot.imshow() 関数を使うと、さまざまなカラーマップで2Dヒストグラムをプロットできる。これにより異なるピクセル密度についてずっと良く理解できる。ただしこれもまた、異なる色の色相値を知らない限り、一見してどのような色があるのかは分からない。それでも私はこの方法を好む。単純で優れているからである。

覚え書き
この関数を使う際は、より良い結果を得るために補間フラグを nearest にすべきことを覚えておこう。

コードを見てみよう。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
hist = cv.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
plt.imshow(hist,interpolation = 'nearest')
plt.show()

以下は入力画像とそのカラーヒストグラムのプロットである。X軸は S 値を、Y軸は色相を示す。

image

ヒストグラムでは、H = 100、S = 200 付近に高い値が見られる。これは空の青に対応する。同様に、H = 25、S = 100 付近にも別のピークが見られる。これは宮殿の黄色に対応する。GIMP のような画像編集ツールで確認できる。

方法3 : OpenCVサンプル流 !!

OpenCV-Python2 のサンプル (samples/python/color_histogram.py) にカラーヒストグラムのサンプルコードがある。このコードを実行すると、ヒストグラムが対応する色も表示しているのが分かる。つまり、色分けされたヒストグラムを出力する。その結果は非常に優れている(ただし、追加で多数の行を加える必要がある)。

そのコードでは、作者は HSV でカラーマップを作成した。そしてそれを BGR に変換した。得られたヒストグラム画像はこのカラーマップと乗算される。また、小さな孤立ピクセルを除去するための前処理も行っており、良好なヒストグラムが得られている。

コードの実行、解析、そして独自の工夫は読者に委ねる。以下は上と同じ画像に対するそのコードの出力である。

image

ヒストグラムを見れば、どの色が存在するかがはっきり分かる。青があり、黄があり、チェス盤による白も少しある。見事だ !!!