のんびりしているエンジニアの日記

ソフトウェアなどのエンジニア的な何かを書きます。

OpenCVの使い方(4) ヒストグラムの比較

Sponsored Links

皆さんこんにちは
お元気ですか?私はげんきです。

※6/14ソースコード修正
※11/29 更に修正

さて、本日はOpenCV Histogramの比較について

ヒストグラムを比較してみたいと思ったことはありませんか?
ほら、こんなヒストグラムあるんだけどーなんか比較できないかなーみたいな心理です。

気のせいだと思うのですが、最近OpenCVが画像開きツールみたいになっています。

とりあえず、先週作ったヒストグラムを比較してみよう。

ヒストグラム生成方法

①各binごとに固めてヒストグラムを作る。
今回indexが32。

よくわからないと思うので…例を以下に

(ex.R:20,G:100,B:200→ (20 /32) + 8 * (100 / 32) + 16 * (200 /32) = 144)

②全体を1に正規化する
{ \displaystyle
H(I) = \frac{H(I)}{\sum_{I}^{N}H(I)}
}

ヒストグラム比較手法

※一部の数式の説明
ヒストグラムの平均↓
{ \displaystyle
\bar{H_k} = \frac{1}{N} \sum _J H_k(J)
}

Correlation

等しければ1、そうでなければ負に近くなる。
{ \displaystyle
d(H_1,H_2) = \frac{\sum_I (H_1(I) - \bar{H_1}) (H_2(I) - \bar{H_2})}{\sqrt{\sum_I(H_1(I) - \bar{H_1})^2 \sum_I(H_2(I) - \bar{H_2})^2}}
}

class Correlation:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double Correlation::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double sum = 0.0;
	double sum2 = 0.0;
	double sum3 = 0.0;
	for(int i = 0; i < histogram1.size(); i++){
		double diff1 = (normalize_hist1[i] - average(normalize_hist1));
		double diff2 = (normalize_hist2[i] - average(normalize_hist2));

		sum += diff1 * diff2;
		sum2 += diff1 * diff1;
		sum3 += diff2 * diff2;
	}
	return sum / sqrt(sum2 * sum3);
}

Chisquare

等しければ0,そうでなければ値が大きくなる
{ \displaystyle
d(H_1,H_2) = \sum _I \frac{\left(H_1(I)-H_2(I)\right)^2}{H_1(I)+H_2(I)}
}

class ChiSquare:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double ChiSquare::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double distance = 0.0;
	for(int i = 0; i < normalize_hist1.size(); i++){
		double diff = normalize_hist1[i] - normalize_hist2[i];
		if(normalize_hist2[i] != 0.0){
			distance += diff * diff / normalize_hist1[i];
		}
	}
	return distance;
}

Intersection

等しければ1,そうでなければ0(全体を1として正規化している場合)
{ \displaystyle
d(H_1,H_2) = \sum _I \min (H_1(I), H_2(I))
}

class Intersection:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double Intersection::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double distance = 0;
	for(int i = 0; i < histogram1.size(); i++){
		distance += min(normalize_hist1[i],normalize_hist2[i]);
	}
	return distance;
}

Bhattacharyya

等しければ0、そうでなければ1
{ \displaystyle
d(H_1,H_2) = \sqrt{1 - \frac{1}{\sqrt{\bar{H_1} \bar{H_2} N^2}} \sum_I \sqrt{H_1(I) \cdot H_2(I)}}
}

class Bhattacharyya:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double Bhattacharyya::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double sum = 0.0;
	for(int i = 0; i < normalize_hist2.size(); i++){
		sum += sqrt(normalize_hist1[i] * normalize_hist2[i]);
	}
	return sqrt(1.0 - 1.0 / sqrt(average(normalize_hist1) * average(normalize_hist2) * (histogram1.size() * histogram1.size())) * sum);
}

実際にやってみた

同じ画像を食わせた時

f:id:tereka:20140612120650j:plain

1
0
1
0

異なる画像を食わせた時

f:id:tereka:20140612120650j:plainf:id:tereka:20140612120927j:plain

0.657073
3.72287
0.319692
0.678538

ソースコード全文

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/nonfree.hpp>

using namespace std;
using namespace cv;

class Image{
private:
	Mat image;

public:
	Image(string path);
	void executeProgram();
	vector<double> createHistogram();
	int calcIndex(int pixel,int index);
};

Image::Image(string path){
	image = cv::imread(path);
}

vector<double> Image::createHistogram(){
	int index = 32;
	int index_number = 255 / 32;
	vector<double> histogram(pow(index_number + 1,3.0));
    fill(histogram.begin(),histogram.end(),0);

	for(int height = 0; height < image.rows; height++){
		for(int width = 0; width < image.cols; width++){
			int blue_pixel = image.data[height * image.step + width * image.elemSize() + 0];
			int green_pixel = image.data[height * image.step + width * image.elemSize() + 1];
			int red_pixel = image.data[height * image.step + width * image.elemSize() + 2];

			histogram[calcIndex(blue_pixel, index) + (index_number + 1) * calcIndex(green_pixel, index) + (index_number + 1) * (index_number + 1) * calcIndex(red_pixel, index)]++;
		}
	}
	return histogram;
}

int Image::calcIndex(int pixel,int index){
	return pixel / index;
}

class Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
	double sumVector(vector<double> &histogram);
	double average(vector<double> &histogram);
	vector<double> normalize(vector<double> &histogram);
};


double Distance::sumVector(vector<double> &histogram){
	double sum = 0.0;
	for(int i = 0; i < histogram.size(); i++){
		sum += histogram[i];
	}
	return sum;
}

double Distance::average(vector<double> &histogram){
	return sumVector(histogram) / histogram.size();
}

vector<double> Distance::normalize(vector<double> &histogram){
	vector<double> normalize_vector(histogram.size());
	double sum = sumVector(histogram);

	for(int i = 0; i < histogram.size(); i++){
		normalize_vector[i] = histogram[i] / sum;
	}
	return normalize_vector;
}

class Correlation:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double Correlation::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double sum = 0.0;
	double sum2 = 0.0;
	double sum3 = 0.0;
	for(int i = 0; i < histogram1.size(); i++){
		double diff1 = (normalize_hist1[i] - average(normalize_hist1));
		double diff2 = (normalize_hist2[i] - average(normalize_hist2));

		sum += diff1 * diff2;
		sum2 += diff1 * diff1;
		sum3 += diff2 * diff2;
	}
	return sum / sqrt(sum2 * sum3);
}

class ChiSquare:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double ChiSquare::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double distance = 0.0;
	for(int i = 0; i < normalize_hist1.size(); i++){
		double diff = normalize_hist1[i] - normalize_hist2[i];
		if(normalize_hist2[i] != 0.0){
			distance += diff * diff / normalize_hist1[i];
		}
	}
	return distance;
}

class Intersection:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double Intersection::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double distance = 0;
	for(int i = 0; i < histogram1.size(); i++){
		distance += min(normalize_hist1[i],normalize_hist2[i]);
	}
	return distance;
}

class Bhattacharyya:public Distance{
public:
	double calcDistance(vector<double> &histogram1,vector<double> &histogram2);
};

double Bhattacharyya::calcDistance(vector<double> &histogram1,vector<double> &histogram2){
	vector<double> normalize_hist1 = normalize(histogram1);
	vector<double> normalize_hist2 = normalize(histogram2);

	double sum = 0.0;
	for(int i = 0; i < normalize_hist2.size(); i++){
		sum += sqrt(normalize_hist1[i] * normalize_hist2[i]);
	}
	return sqrt(1.0 - 1.0 / sqrt(average(normalize_hist1) * average(normalize_hist2) * (histogram1.size() * histogram1.size())) * sum);
}

int main(int argc, char const *argv[]){
	Image image(argv[1]);
	Image image2(argv[2]);
	vector<double> hist1 = image.createHistogram();
	vector<double> hist2 = image2.createHistogram();

	//距離計測
	Correlation correlation;
	cout << correlation.calcDistance(hist1, hist2) << endl;

	ChiSquare chisquare;
	cout << chisquare.calcDistance(hist1, hist2) << endl;

	Intersection intersection;
	cout << intersection.calcDistance(hist1,hist2) << endl;

	Bhattacharyya bhattacharyya;
	cout << bhattacharyya.calcDistance(hist1, hist2) << endl;

	return 0;
}