それが僕には楽しかったんです。

僕と MySQL と時々 MariaDB

画像処理におけるヒストグラム

はじめに

今回は画像処理をするとき(2値化などで)に使うヒストグラムというものについてまとめる

ヒストグラムとは

ヒストグラムとは画像処理以外の分野で使われることもあるが
画像処理の分野では、各濃度値に対してその濃度値を持った画素数を求めたもので、濃度ヒストグラム
または単純にヒストグラムという。

ヒストグラムは主に横軸が濃度値、縦軸に画素数をとったグラフで表現される

{\displaystyle
濃度値がq_i以上、q_i+\Delta q_i以上である画素数を
}
{\displaystyle
それぞれA(q_i)、A(q_i+\Delta q_i)とすると
}

{\displaystyle
濃度値q_iを持った画素数H(q_i)はH(q_i)=A(q_i)-A(q_i+\Delta q_i)となる
}
{\displaystyle
濃度レベル数nに対しH(0)〜H(n-1)によりヒストグラムを表現できる
}


ヒストグラムはその画像がどのような濃度値を持った画素から成り立っているかの情報をまとめたもので
画像処理において処理が容易なのもあり非常に有用な手段といえる

ヒストグラムの性質

ヒストグラムにはいくつかの性質がある

まずはヒストグラムは各画素の濃度値だけをとりあげているので、その画素の場所には関係しないグラフとなる
なのでその濃度値を持った画素がどれくらいあるかはわかってもその画素がどこにあるかまではわからない

つまり画像の持つ空間的特徴は考慮されずその情報はヒストグラム上では失われる


次に、ヒストグラムは同一の画像に対しては一意に、つまり一通りに定まるが
異なる画像であってもそれと同一のヒストグラムを持つことも可能性としてないわけではない

最後にヒストグラムは画像の各画素の濃度値を集めたのもなので
画像を分割してヒストグラムを求めた場合、それらの和が全体のヒストグラムと一致する

ヒストグラムの計算法

大きさMxN画素の濃度レベルがNGLの画像imgのヒストグラムを求め
配列hstに格納する方法でC言語ライクな擬似コードでしめす

また配列hstの初期値は各要素とも0であるとする

int i,j;
int img[N][M];
int hst[NGL];

for(i = 0; i < N; i++){
    for(j = 0; j < M; j++){
         hst[img[i][j]]++;
    }
}

濃度レベルが256で8bitだとすると
ヒストグラムは0〜255までの範囲となる

実用例

ヒストグラムの具体的な使い方は後述することにして
今回はpythonOpenCVを使ってヒストグラムを表示するものを紹介する

f:id:RabbitFoot141:20160206171235p:plain

例によりこのLenna.pngの画像を使う

結果
f:id:RabbitFoot141:20160208213332p:plain

#coding:utf-8

import cv2
import pylab as plt

img = cv2.imread("lenna256.png")
hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.plot(hist)
plt.xlim([0,256])
plt.show()

今回はカラーのままでやったがグレースケールにするとまた少し違って見える

ヒストグラム計算を自作してみる

ヒストグラムを求めること自体は結構簡単なので画像の入出力だけにOpenCVを使い
それ以外を自作するなんていうことも可能

#coding:utf-8

import numpy as np
import cv2

img = cv2.imread("lenna256.png")
#画像をグレースケールに変換
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

#ヒストグラムを作成
histgram = [0]*256
for i in range(0,len(gray)):
	for j in range(0,len(gray[0])):
		histgram[gray[i][j]] += 1