基於直方圖的圖像匹配方案(opencv3)

2018/10/20

1.最近一段時間可以說有點忙吧,一直在學習opencv3的基礎內容,漸漸的也發現了很多好玩的事物,作爲計算機開源視覺庫,資源是及其豐富和充滿奧祕的,記得和朋友說過,單純調用一個庫就像夾娃娃一樣(並不是每一次都可以調用成功是吧,但是成功率或許會比真正的夾娃娃要高出不少),opencv看了也將近兩個月,基礎的知識也慢慢梳理了,會漸漸的發一些筆記吧!!!

2.直方圖的簡單介紹(一維)

2-1:直方圖的簡單介紹:

簡單來說,直方圖就是對數據統計的一種方法,描述的是對於像素強度的分佈形式,通過自設的強度,來統計基於該強度值上的像素分佈情況

2-2:直方圖(一維)

下面爲RGB三通道直方圖的簡單介紹

2-2-1:代碼部分:

//實現三色直方圖的繪製
//picture adress C:\\Users\\ASUS\\Pictures\\opencv_Pirture
//直方圖 統計了每一個強度所擁有的像素個數
//通過給定的範圍區間 實現不同的統計方式 

#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat src;
	src = imread("C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\1.jpg");
	int bins = 600;
	int hist_size[] = { bins };//代表着全局範圍 框的尺寸
	float range[] = {0, 256 };//確定像素的範圍 在這裏是爲了實現對0--255像素區間強度的描述 
	const float* ranges[] = {range};
	MatND hist_r, hist_g, hist_b;//專門用來儲存直方圖
	int channels_r[] = { 0 };//channel_red
	calcHist(&src, 1, channels_r, Mat(), // do not use mask  
		hist_r, 1, hist_size, ranges,
		true, // the histogram is uniform  
		false);
	/*
	FUNCTION DETAILS:
	1.輸入的數組集,需要有相同的深度
	2.輸入數組的個數(前面有幾張圖)
	3.通道索引 數組名
	4.操作掩碼
	5.輸出目標(redhist) MatND
	6.直方圖的維度(在這裏爲1維)
	7.直方圖的尺寸 數組名
	8.每一維數據的範圍 數組名
	9.直方圖是否均勻
	10.累計標識符 (默認爲false)
*/

	int channels_g[] = { 1 };//channel_green
	calcHist(&src, 1, channels_g, Mat(), // do not use mask  
		hist_g, 1, hist_size, ranges,
		true, // the histogram is uniform  
		false);

	int channels_b[] = { 2 };//channel_blue
	calcHist(&src, 1, channels_b, Mat(), // do not use mask  
		hist_b, 1, hist_size, ranges,
		true, // the histogram is uniform  
		false);
	double max_val_r, max_val_g, max_val_b;
	minMaxLoc(hist_r, 0, &max_val_r, 0, 0);
	minMaxLoc(hist_g, 0, &max_val_g, 0, 0);
	minMaxLoc(hist_b, 0, &max_val_b, 0, 0);
	/*FUNCTION DETAILS:
	1.輸入的單通道陣列
	2.返回最小值指針
	3.返回最大值指針
	4.返回最小位置指針
	5.返回最大位置指針
	*/
	int scale = 1;
	int hist_height = 256;
	Mat hist_img = Mat::zeros(hist_height, bins * 3, CV_8UC3);
	for (int i = 0; i<bins; i++)
	{
		float bin_val_r = hist_r.at<float>(i);
		float bin_val_g = hist_g.at<float>(i);
		float bin_val_b = hist_b.at<float>(i);
		int intensity_r = cvRound(bin_val_r*hist_height / max_val_r);  //要繪製的高度  
		int intensity_g = cvRound(bin_val_g*hist_height / max_val_g);  //要繪製的高度  
		int intensity_b = cvRound(bin_val_b*hist_height / max_val_b);  //要繪製的高度  
		rectangle(hist_img, Point(i*scale, hist_height - 1),
			Point((i + 1)*scale - 1, hist_height - intensity_r),
			CV_RGB(255, 0, 0));

		rectangle(hist_img, Point((i + bins)*scale, hist_height - 1),
			Point((i + bins + 1)*scale - 1, hist_height - intensity_g),
			CV_RGB(0, 255, 0));

		rectangle(hist_img, Point((i + bins * 2)*scale, hist_height - 1),
			Point((i + bins * 2 + 1)*scale - 1, hist_height - intensity_b),
			CV_RGB(0, 0, 255));
	}
	imshow("Source", src);
	imshow("RGB Histogram", hist_img);
	while (waitKey(0) != 27);
	return 0;
}

2-2-2:效果圖

 

3.基於直方圖的簡單匹配方案

3-1:匹配方法

對於opencv3而言,比較常見的圖像匹配方案是通過surf算法進行特徵點匹配(不詳細說明,有興趣的大家可以自行百度),,但是說實話,比較難實現(雖然效果很好),在opencv3中提供了一個函數compareHist()用於直方圖的匹配,通過對函數的返回值的對比,實現對圖像是否匹配的判斷

3-2:compareHist(srcImage,dstImage,compare_method)

srcImage:原圖

dstImage:輸出圖

compare_method:這個值以int形式出現,在opencv3中有着較好的封裝,一般來說有四種方法

0:Correlation(相關) 反饋的數值越大 說明越匹配 歸一化後完全匹配爲1 完全不匹配爲-1 隨機爲0

1:Chi_Square(卡方)完全匹配爲0 不完全匹配爲任意值

2:Intersection(直方圖相較)數值越高代表着匹配值越高,數值越低代表着匹配值越低

3.Bhattacharyya(距離) 數值越低越好,越高代表圖像越不匹配,完全匹配爲0 不匹配爲1

 

3-3:設計思路:構建直方圖並且歸一化,最後比較compareHist()的返回值(使用原圖和原圖比較以及原圖和效果圖比較,通過一個邏輯判斷是否是相同的圖)

(注:邏輯閾值爲自設 可以自行設計爲百分數參數或者任意邏輯輸出)

代碼如下:(在這裏使用了方法2)

//直方圖匹配
//進入hsv空間進行匹配
//C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\base.jpg

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
	//【0】改變console字體顏色
	system("color 2F");
	//【1】聲明儲存基準圖像和另外兩張對比圖像的矩陣( RGB 和 HSV )
	Mat srcImage_base, hsvImage_base;
	Mat srcImage_test1, hsvImage_test1;
	Mat srcImage_test2, hsvImage_test2;
	Mat hsvImage_halfDown;//半身圖

						  //【2】載入基準圖像(srcImage_base) 和兩張測試圖像srcImage_test1、srcImage_test2,並顯示
	srcImage_base = imread("C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\base.jpg", 1);//基準圖
	srcImage_test1 = imread("C:\\Users\\ASUS\\Pictures\\opencv_Pirture\\text.jpg", 1);//測試圖1																			  
	imshow("基準圖像", srcImage_base);
	imshow("測試圖像1", srcImage_test1);

	// 【3】將圖像由BGR色彩空間轉換到 HSV色彩空間
	cvtColor(srcImage_base, hsvImage_base, COLOR_BGR2HSV);
	cvtColor(srcImage_test1, hsvImage_test1, COLOR_BGR2HSV);
	//【4】創建包含基準圖像下半部的半身圖像(HSV格式)
	//【5】初始化計算直方圖需要的實參
	// 對hue通道使用30個bin,對saturatoin通道使用32個bin
	int h_bins = 50; int s_bins = 60;
	int histSize[] = { h_bins, s_bins };
	// hue的取值範圍從0到256, saturation取值範圍從0到180
	float h_ranges[] = { 0, 256 };
	float s_ranges[] = { 0, 180 };
	const float* ranges[] = { h_ranges, s_ranges };
	// 使用第0和第1通道
	int channels[] = { 0, 1 };

	// 【6】創建儲存直方圖的 MatND 類的實例:
	MatND baseHist;
	MatND testHist1;
	// 【7】計算基準圖像,測試圖像
	calcHist(&hsvImage_base, 1, channels, Mat(), baseHist, 2, histSize, ranges, true, false);
	normalize(baseHist, baseHist, 0, 1, NORM_MINMAX, -1, Mat());
	calcHist(&hsvImage_test1, 1, channels, Mat(), testHist1, 2, histSize, ranges, true, false);
	normalize(testHist1, testHist1, 0, 1, NORM_MINMAX, -1, Mat());
	int compare_method = 1;
	double base_base = compareHist(baseHist, baseHist, 2);
	double base_text1 = compareHist(baseHist, testHist1, 2);
	//printf("基準值爲%lf\n", base_base);
	cout << "原圖基準值爲" << base_base << endl;
	//printf("匹配值爲%lf\n", base_text1);
	cout << "比較值爲" << base_text1 << endl;
	if (base_base == base_text1)
	{
		cout << "圖像匹配成功" << endl;
	}
	else
	{
		cout << "圖像匹配失敗" << endl;
	}
	cout << "檢測結束" << endl;
	waitKey(0);
	return 0;
}

效果圖:


注:該內容基於淺墨大神的opencv3編程入門,學完了直方圖部分,基於書籍談一下自己的認識和看法,如果有紕漏,請大家及時提出,小白一枚,希望大家多多指教!!! 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章