【初学者向け】PythonとOpenCVによる画像処理超入門③(~画像ヒストグラムと基本統計量~)

PythonとOpenCVによる画像処理超入門
こんにちは、都内のスタートアップでデータ分析屋をしている、やじろべえ(@yajirobe_papa)です。
前回までは、カラー画像とグレースケール画像、グレースケール変換までやりましたね。
本記事では、画像ヒストグラムと基本統計量について書いていきます!
✔本記事の内容
  • 画像ヒストグラムと基本統計量
  • OpenCVを使って画像ヒストグラムと基本統計量を算
  • (おまけ)ImageJの紹介

 

画像ヒストグラムと基本統計量

画像ヒストグラム
統計量というと難しく感じるかもしれませんが、ようするに画像の特徴の一つである輝度情報を数学的に表した値のことです。
なぜ画像の統計量を知る必要があるのでしょう?その大きな目的の一つは、画像のコントラストを調整したいことがあげられます。その他にも二値化処理といった画像処理の際の閾値を決定することなどがあげられます。
そしてこういった画像処理を行うためには、その画像の持つ明るさ情報を知る必要があります。
この画像の持つ明るさ情報こそがこれまでの記事で解説してきた画素値になります。
画像全体の明るさがどうなっているかを知るために便利なのが、ヒストグラムです。
ヒストグラムとは画像全体に含まれる同じ明るさ情報の画素数を数え、グラフ化したものです。通常は横軸に画素値、縦軸に画素値の出現頻度をのせた棒グラフが用いられます。
下図はグレースケール画像のヒストグラムを算出したものになります。
ヒストグラムの分布が広ければ、その画像は暗いところから明るいところまでまんべんなく含むような画像ですし、画素値が大きなところにだけ分布があれば、その画像は全体として明るい画像となります。
ちなみに、横断歩道のような白線といった白の領域と暗い領域がはっきりと分かれている画像の場合は分布が2つに分かれたりします。
また、入力画像がRGBカラー画像の場合は、各カラーチャンネルに対してグレースケール画像と同じようにヒストグラムを求めることも出来ます。
画像の基本統計量
次に、基本的な統計量も確認していきましょう。
  • 最大値と最小値
ある画像の画素値の中で最大もしくは最小の値のことを言います。ヒストグラムだと両端の値ということになります。
  • 平均値
ある画像の画像サイズM画素×N画素としたときの、平均値(mean)μは以下の式で表されます。

$$μ = \frac{1}{MN}\sum_{i=0}^{N-1}\sum_{j=0}^{M-1} f(i,j)$$

  • 中央値
ある画像の画像サイズM画素×N画素としたときの、中央値(median)は画素値を小さい方からMN/2番目の画素値になります。
一方、画素数MNが奇数のときは、画素値の小さい方から(MN+1)/2番目とします。
  • 最頻値
画像ヒストグラムの中で最も頻度が高い画素値のことを言います。
  • 分散
ある画像の画像サイズM画素×N画素としたときの、分散(variance)$σ^2$は以下の式で表されます。

$$σ^2 = \frac{1}{MN}\sum_{i=0}^{N-1}\sum_{j=0}^{M-1} f^2(i,j)-μ^2$$

また、分散の正の平方根を標準偏差σと言います。分散と標準偏差どちらの値も画像ヒストグラムの広さや狭さを知る指標となります。
では、次からはOpenCVを使って画像ヒストグラムと画像の基本統計量を算出していきましょう!

OpenCVを使って画像ヒストグラムと基本統計量の算出

今回も以下の画像を元画像として画像ヒストグラムと基本統計量を計算してみます。
OpenCVを使って画像ヒストグラムを計算するには、calcHist関数を使います。
calcHist関数は以下のように使います。
   cv2.calcHist(image, channel, mask, histSize, ranges)
・image:入力画像
・channel:画像のチャンネル(グレースケール画像は0, カラー画像はB[0], G[1], R[2])
・mask:特定領域の画像ヒストグラムを取得したい場合の設定です。全画素のヒストグラムを取得したい場合は’None’を指定します。
・histSize:画像ヒストグラムのビンの数を指定します。全画素値を対象とする場合は[256]を指定します。
・ranges:算出したい画素値の範囲を指定します。全画素値を対象とする場合は[0, 256]を指定します。通常はこの設定で問題ありません。
calcHist関数は、256×1の配列で出力され、各要素は対応する画素値を持つ画素の数が格納されています。(256×1の配列というのは、255列×1行という意味です!)
calcHist関数でヒストグラムを計算した後は、matplotlibでグラフ化してみます。matplotlibはグラフ描画ライブラリです。
では、まず元画像をグレースケール変換してやってみましょう。
import matplotlib.pyplot as plt
img = cv2.imread('./space-shuttle.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([gray_img],[0],None,[256],[0,256])
plt.plot(hist)
plt.show()
このようにグレースケール画像の画像ヒストグラムが計算出来ましたね!
次に、基本統計量を確認しておきましょう。基本統計量はpythonの数値計算ライブラリnumpyを使って以下のように簡単に取得できます。
ただし、最頻値は他の統計量と異なり、「登場する回数が最も多い値」と「登場回数」の二つの値が共に必要になります。ここではscipyライブラリのstats関数を使用して最頻値を求めます。
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
img = cv2.imread('./space-shuttle.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
max = np.max(gray_img)
min = np.min(gray_img)
mean = np.mean(gray_img)
std = np.std(gray_img)
median = np.median(gray_img)
mode, count = stats.mode(gray_img, axis=None)#axis=Noneは全要素を対象にするという設定
print(max)#255
print(min)#0
print(mean)#130.61416991039954
print(std)#64.07492972540032
print(median)#127.0
print(mode, count)#[86] [8434]
最後に、RGBカラー画像のカラーチャンネルそれぞれに対してヒストグラムを計算してみます。やり方は色々ありますが、ここではカラーリストを作ってenumerate関数でループさせて計算しています。
enumerate関数はリストのインデックス番号と要素を同時に取得出来る便利な関数ですよ。
では、やってみましょう。
img = cv2.imread('./space-shuttle.jpg')
color = ('b','g','r')
for i,col in enumerate(color):
  hists = cv2.calcHist([img],[i],None,[256],[0,256])
  plt.plot(hists,color = col)
plt.show()
RGBカラー画像のカラーチャンネルごとのヒストグラムが計算出来ました!

(おまけ)ImageJの紹介

本記事の最後はOpenCVとは関係ないですが、フリーの画像処理ソフトウェア ImageJの紹介についてして終わりにしたいと思います。
ImageJはフリーで使えるJavaベースの画像処理ソフトウェアで、世界中の多くの研究者で使われています。
ImageJは基本的な画像処理機能は大抵備わっていますので、プログラミングする前に解析結果をクイックに確認したい時に使うと便利です。
ImageJの画像解析画面
画像処理や画像解析をこれからやっていきたい人はこれを機会に使えるようになることをオススメします!

OpenCVによる画像ヒストグラムと基本統計量の算出まとめ
  • cv2.calcHist(image, channel, mask, histSize, ranges)→ 画像ヒストグラムの算出
  • 画像の基本統計量はnumpyとscipyライブラリを使って算出出来る

 

まとめ

今回は、画像ヒストグラムと基本統計量の算出を行いました。
次回は明るさとコントラスト変換を記事にしたいと思います!
では、今回はこの辺で!

参考文献

 

人気記事

タイトルとURLをコピーしました