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に正規化する
ヒストグラム比較手法
※一部の数式の説明
ヒストグラムの平均↓
Correlation
等しければ1、そうでなければ負に近くなる。
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,そうでなければ値が大きくなる
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として正規化している場合)
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
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); }
実際にやってみた
同じ画像を食わせた時
1 0 1 0
異なる画像を食わせた時
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; }