【OpenCV學習筆記】之直方圖(Histogram)

 

一、直方圖概述(Histogram Overview)

        在統計學中,直方圖是一種對數據分佈情況的圖形表示,是一種二維統計圖表,他的兩個座標分別是統計樣本(圖像、視頻幀)和樣本的某種屬性(亮度,像素值,梯度,方向,色彩等等任何特徵)。

        也可以這麼理解,直方圖是對數據的統計,並把統計值顯示到事先設定好的bin(矩形條)中,bin中的數值是從數據中計算出的特徵的統計量。總之,直方圖獲取的是數據分佈的統計圖,通常直方圖的維數要低於原始數據。

        圖像直方圖是用一表示數字圖像中亮度分佈的直方圖,標繪了圖像中每個亮度值的像素數。可以藉助觀察該直方圖瞭解需要如何調整亮度分佈的直方圖。這種直方圖中,橫座標的左側爲純黑、較暗的區域,而右側爲較亮、純白的區域。因此,一張較暗圖片的圖像直方圖中的數據多集中於左側和中間部分,而整體明亮、只有少量陰影的圖像則相反。計算機視覺鄰域常藉助圖像直方圖來實現圖像的二值化。

        灰度直方圖是一幅圖像中個像素灰度值出現次數或頻數的統計結果,它只反映該圖像中灰度值出現的頻率,而未反映某一灰度值像素所在的位置。也就是說,它只包含了該圖像中某個灰度值的像素出現的概率,而丟失了其所在的位置的信息

任一幅圖像,都能唯一地算出一幅與它對應的直方圖。但不同的圖像,可能有相同的直方圖。即圖像與直方圖之間是多對一的映射關係。

直方圖意義: 
        1. 直方圖是圖像中像素強度分佈的圖形表達方式。 
        2. 直方圖統計了每一個強度值所具有的像素個數。

           直方圖廣泛應用於許多計算機視覺應用中。通過標記幀和幀之間顯著的邊緣和顏色的統計變化,來檢測視頻中場景的變換。通過在每個興趣點設置一個有相近特徵的直方圖所構成的標籤,用以確定圖像中的興趣點。邊緣、色彩、角度等直方圖構成了可以被傳遞給目標識別分類器的一個通用特徵類型。色彩和邊緣的直方圖還可以用來識別網絡視頻是否被複制等。直方圖是計算機視覺中最經典的工具之一,也是一個很好的圖像特徵表示手段。

直方圖術語: 
dims:需要統計的特徵的數目。例如:dims=1,表示我們僅統計灰度值。 
bins:每個特徵空間子區段的數目。 
range:每個特徵空間的取值範圍。

二、直方圖均衡化

  •  直方圖在圖像增強中的小應用

        直方圖均衡化是通過拉伸像素強度的分佈範圍,使得在0~255灰階上的分佈更加均衡,提高了圖像的對比度,達到改善圖像主觀視覺效果的目的。對比度較低的圖像適合使用直方圖均衡化方法來增強圖像細節。

OpenCV裏面的API介紹:

C++ void equalizeHist(InputArray src, OutputArray dst)
//第一個參數,源圖像,需爲8位單通道圖像
//第二個參數,輸出圖像,尺寸、類型和源圖像一致

該函數採用如下步驟對輸入圖像進行直方圖均衡化:

  1.  計算輸入圖像的直方圖H;
  2. 進行直方圖歸一化,直方圖的組距的和爲255;
  3. 計算直方圖積分:H'(i)=\sum_{0\leqslant j\leq i}H(j)
  4. 以H'作爲查詢表進行圖像變換:dst(x,y)=H'(src(x,y))

       也就是把直方圖的每個灰度級進行歸一化處理,求每種灰度的累積分佈,得到一個映射的灰度映射表,然後根據相應的灰度值來修正原圖中的每個像素。

示例程序:

//equalizeHist(直方圖均衡化);提高圖像對比度

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;

const char*output = "histogram iamge";

int main(int argc, char*argv)
{
	Mat src, dst, dst1;
	src = imread("C:\\Users\\59235\\Desktop\\imag\\antiquity_girl2.jpeg");
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	char input[] = "input image";
	namedWindow(input, CV_WINDOW_AUTOSIZE);
	namedWindow(output, CV_WINDOW_AUTOSIZE);
	//轉換成灰度圖像,使原圖成爲單通道圖像
	cvtColor(src, dst, CV_BGR2GRAY);
	//查看圖像通道數
	int c = dst.channels();
	cout << "=" << endl << c << endl;

	//直方圖均衡化
	equalizeHist(dst, dst1);

	imshow(input, dst);
	imshow(output, dst1);
	waitKey(0);
	return 0;
}

效果圖:                           (原圖)                                                                                              (直方圖均衡化後效果圖)

當然前面是針對對彩色圖像進行均衡化也是可以實現的

彩色圖像直方均衡化示例程序:

//彩色圖像直方圖均衡化

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<cmath>

using namespace cv;
using namespace std;

const char*output = "histogram iamge";

int main(int argc, char*argv)
{
	Mat src, dst, dst1;
	src = imread("C:\\Users\\zhj\\Desktop\\image\\霧天.png");
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	char input[] = "input image";
	namedWindow(input, CV_WINDOW_AUTOSIZE);
	namedWindow(output, CV_WINDOW_AUTOSIZE);
	imshow(input, src);

	//分割通道
    vector<Mat>channels;
    split(src, channels);

	Mat blue, green, red;
    blue = channels.at(0);
    green = channels.at(1);
    red = channels.at(2);
    //分別對BGR通道做直方圖均衡化
    equalizeHist(blue, blue);
	equalizeHist(green, green);
    equalizeHist(red, red);
    //合併通道
	merge(channels, dst);

	imshow(output, dst);
	
	waitKey(0);
	return 0;
}

效果圖:                  (原圖)                                                                                                         (均衡化效果圖)

 三、直方圖的計算與繪製

OpenCV裏面的直方圖計算的API介紹:

C++ Void calcHist(
	        const Mat* images,//輸入圖像指針
	        int images,// 圖像數目
	        const int* channels,// 通道數
	        InputArray mask,// 輸入mask,可選,不用
	        OutputArray hist,//輸出的直方圖數據
	        int dims,// 維數
	        const int* histsize,// 直方圖級數
	        const float* ranges,// 值域範圍
	        bool uniform,// true by default
	        bool accumulate)// false by defaut
//尋找最值函數
C++ void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, 
                    Point* minLoc=0,Point* maxLoc=0,InputArray mask=noArray())
        //第一個參數:輸入單通道陣列
        //第二個參數:返回最小值的指針,若無需返回,此值置爲NULL
        //第三個參數:返回最大值的指針,若無需返回,此值置爲NULL
        //第四個參數:返回最小位置的指針(二維情況下),若無需返回,此值置爲NULL
        //第五個參數:返回最大位置的指針(二維情況下),若無需返回,此值置爲NULL
        //第六個參數:用於選擇子陣列的可選掩膜

示例程序:

//直方圖的計算與繪製

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;

const char*output = "histogram iamge";

int main(int argc, char*argv)
{
	Mat src, dst, dst1;
	src = imread("C:\\Users\\zhj\\Desktop\\image\\heart.jpg");
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	char input[] = "input image";
	namedWindow(input, CV_WINDOW_AUTOSIZE);
	namedWindow(output, CV_WINDOW_AUTOSIZE);
	imshow(input, src);

	//步驟一:分通道顯示
	vector<Mat>bgr_planes;
	split(src, bgr_planes);
	//split(// 把多通道圖像分爲多個單通道圖像 const Mat &src, //輸入圖像 Mat* mvbegin)// 輸出的通道圖像數組

	//步驟二:計算直方圖
	int histsize = 256;
	float range[] = { 0,256 };
	const float*histRanges = { range };
	Mat b_hist, g_hist, r_hist;
	calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histsize, &histRanges, true, false);
	calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histsize, &histRanges, true, false);
	calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histsize, &histRanges, true, false);
	

	//歸一化
	int hist_h = 400;//直方圖的圖像的高
	int hist_w = 512;////直方圖的圖像的寬
	int bin_w = hist_w / histsize;//直方圖的等級
	Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));//繪製直方圖顯示的圖像
	normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());//歸一化
	normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
	normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());

	//步驟三:繪製直方圖(render histogram chart)
	for (int i = 1; i < histsize; i++)
	{
		//繪製藍色分量直方圖
		line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
			Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, CV_AA);
		//繪製綠色分量直方圖
		line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
			Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, CV_AA);
		//繪製紅色分量直方圖
		line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
			Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, CV_AA);
	}
	imshow(output, histImage);
	waitKey(0);
	return 0;
}

效果圖:                               (原圖)                                                                                                  (直方圖)

四、直方圖比較

           直方圖比較,是用一定的標準來判斷兩個直方圖的相似度方法;

OpenCV中提供的API是:

//對輸入的兩張圖像計算得到直方圖H1與H2,歸一化到相同的尺度空間然後可以通過計算H1與H2的之間的距離得到兩個直方圖的相似程度進而比較圖像本身的相似程度。
//Opencv提供的比較方法有四種:Correlation 相關性比較   Chi - Square 卡方比較   Intersection 十字交叉性   Bhattacharyya distance 巴氏距離
//步驟:首先把圖像從RGB色彩空間轉換到HSV色彩空間cvtColor
//計算圖像的直方圖,然後歸一化到[0~1]之間calcHist和normalize;
//使用上述四種比較方法之一進行比較compareHist

四種比較方法: 

注意:方法1和方法3的是當值越大時表示相似度越高

示例程序:

//直方圖比較

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;

string convertToString(double d);
int main(int argc, char*argv)
{
	Mat base, test1, test2;
	Mat hsvbase, hsvtest1, hsvtest2;
	base = imread("C:\\Users\\zhj\\Desktop\\image\\test.jpg");
	test1 = imread("C:\\Users\\zhj\\Desktop\\image\\SaltNoise.jpg");
	test2 = imread("C:\\Users\\zhj\\Desktop\\image\\GaussianNoise.jpg");
	if (!base.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	//步驟一:從RGB空間轉換到HSV空間
	cvtColor(base, hsvbase, CV_BGR2HSV);
	cvtColor(test1, hsvtest1, CV_BGR2HSV);
	cvtColor(test2, hsvtest2, CV_BGR2HSV);

	//步驟二:計算直方圖與歸一化
	int h_bins = 50;
	int s_bins = 60;
	int histsize[] = { h_bins,s_bins };
	//hue varies from 0 to 179,saturation from 0 to 255
	float h_ranges[] = { 0,180 };
	float s_ranges[] = { 0,256 };
	const float*histRanges[] = { h_ranges,s_ranges };
	//use the 0-th and 1-st channels
	int channels[] = { 0,1 };
	MatND hist_base;
	MatND hist_test1;
	MatND hist_test2;
	//計算直方圖
	calcHist(&hsvbase, 1, channels, Mat(), hist_base, 2, histsize, histRanges, true, false);
	calcHist(&hsvtest1, 1, channels, Mat(), hist_test1, 2, histsize, histRanges, true, false);
	calcHist(&hsvtest2, 1, channels, Mat(), hist_test2, 2, histsize, histRanges, true, false);

	//歸一化
	normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());//歸一化
	normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat());
	normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat());

	//步驟三:比較直方圖,並返回值
	double basebase = compareHist(hist_base, hist_base, CV_COMP_BHATTACHARYYA);//比較直方圖
	double basetest1 = compareHist(hist_base, hist_test1, CV_COMP_BHATTACHARYYA);
	double basetest2 = compareHist(hist_base, hist_test2, CV_COMP_BHATTACHARYYA);
	double test1test2 = compareHist(hist_test1, hist_test2, CV_COMP_BHATTACHARYYA);
	printf("test1 with test2 correlation value :%f", test1test2);

	//在原圖中顯示相關性參數
	putText(base, convertToString(basebase), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);
	putText(test1, convertToString(basetest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);
	putText(test2, convertToString(basetest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);
	putText(test2, convertToString(test1test2), Point(100, 100), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, CV_AA);

	namedWindow("base", CV_WINDOW_AUTOSIZE);
	namedWindow("test1", CV_WINDOW_AUTOSIZE);
	namedWindow("test2", CV_WINDOW_AUTOSIZE);

	imshow("base", base);
	imshow("test1", test1);
	imshow("test2", test2);

	waitKey(0);
	return 0;
}

//由於comparehist計算出來的相關性的值是一個double型,這個函數就是把double轉變爲string
string convertToString(double d)
{
	ostringstream os;
	if (os << d)
	return os.str();
	return "invalid conversion";
}

結果圖:       (原圖)                                                           (添加椒鹽噪聲)                                       (添加高斯噪聲)

分析:圖一和圖一直方圖相似度最大是1,原圖與圖二,圖三的相似度分別爲0.552549、0.462446;圖二和圖三的相似度是0.905106;顯然結果是正確的。

五、直方圖的反向投影

       反向投影是反映直方圖模型在目標圖像中的分佈情況;簡單點說就是用直方圖模型去目標圖像中尋找是否有相似的對象。通常用HSV色彩空間的HS兩個通道直方圖模型
步驟:

  1. 建立直方圖模型
  2. 計算待測圖像直方圖並映射到模型中
  3. 從模型反向計算生成圖像

需要用到的API介紹:

C++ void calcBackProject(const Mat* arrays, int narrays, const int* channels, InputArray hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true )

參數解釋: 
const Mat* images:輸入圖像,圖像深度必須位CV_8U,CV_16U或CV_32F中的一種,尺寸相同,每一幅圖像都可以有任意的通道數 
int nimages:輸入圖像的數量 
const int* channels:用於計算反向投影的通道列表,通道數必須與直方圖維度相匹配,第一個數組的通道是從0到image[0].channels()-1,第二個數組通道從圖像image[0].channels()到image[0].channels()+image[1].channels()-1計數 
InputArray hist:輸入的直方圖,直方圖的bin可以是密集(dense)或稀疏(sparse) 
OutputArray backProject:目標反向投影輸出圖像,是一個單通道圖像,與原圖像有相同的尺寸和深度 
const float ranges**:直方圖中每個維度bin的取值範圍 
double scale=1:可選輸出反向投影的比例因子 
bool uniform=true:直方圖是否均勻分佈(uniform)的標識符,有默認值true

C++ void mixChannels(const Mat*src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs)
//src– 輸入矩陣,可以爲一個也可以爲多個,但是矩陣必須有相同的大小和深度.
    //nsrcs– 輸入矩陣的個數。
    //dst– 輸出矩陣,可以爲一個也可以爲多個,但是所有的矩陣必須事先分配空間(如用create),大小和深度須與輸入矩陣等同.
    //ndsts– Number of matrices in dst.輸出矩陣的個數。
    //fromTo –設置輸入矩陣的通道對應輸出矩陣的通道,規則如下:首先用數字標記輸入矩陣的各個通道。輸入矩陣個數可能多於一個並且每個矩陣的通道可能不一樣,
    //第一個輸入矩陣的通道標記範圍爲:0 ~src[0].channels() - 1,第二個輸入矩陣的通道標記範圍爲:src[0].channels() ~src[0].channels() + src[1].channels() - 1,
    //以此類推;其次輸出矩陣也用同樣的規則標記,第一個輸出矩陣的通道標記範圍爲:0 ~dst[0].channels() - 1,第二個輸入矩陣的通道標記範圍爲:dst[0].channels()
    //~dst[0].channels() + dst[1].channels() - 1, 以此類推;最後,數組fromTo的第一個元素即fromTo[0]應該填入輸入矩陣的某個通道標記,而fromTo的第二個元素即
    //fromTo[1]應該填入輸出矩陣的某個通道標記,這樣函數就會把輸入矩陣的fromTo[0]通道里面的數據複製給輸出矩陣的fromTo[1]通道。fromTo後面的元素也是這個
    //道理,總之就是一個輸入矩陣的通道標記後面必須跟着個輸出矩陣的通道標記。
    //npairs– Number of index pairs in fromTo.即參數fromTo中的有幾組輸入輸出通道關係,其實就是參數fromTo的數組元素個數除以2.

示例程序:

//直方圖的反向投影
//加載圖片imread
//將圖像從RGB色彩空間轉換到HSV色彩空間cvtColor
//計算直方圖和歸一化calcHist與normalize
//Mat與MatND其中Mat表示二維數組,MatND表示三維或者多維數據,此處均可以用Mat表示。
//計算反向投影圖像 - calcBackProject

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace std;
using namespace cv;
Mat src, hsv_src;
Mat hue;
int bins = 12;
void Hist_And_Backprojection(int, void*);
int main(int argc, char*argv)
{
	src = imread("C:\\Users\\59235\\Desktop\\imag\\test.jpg");
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("input", CV_WINDOW_AUTOSIZE);

	//將圖像從RGB色彩空間轉換到HSV色彩空間
	cvtColor(src, hsv_src, CV_BGR2HSV);

	hue.create(hsv_src.size(), hsv_src.depth());
	int nchannels[] = { 0,0 };

	//mixChannels主要就是把輸入的矩陣(或矩陣數組)的某些通道拆分複製給對應的輸出矩陣(或矩陣數組)的某些通道中,其中的對應關係就由fromTo參數制定.
	mixChannels(&hsv_src, 1, &hue, 1, nchannels, 1);

	createTrackbar("Histogram Bins:", "input", &bins, 180, Hist_And_Backprojection);
	Hist_And_Backprojection(0, 0);

	imshow("input", src);
	waitKey(0);
	return 0;
}

void Hist_And_Backprojection(int, void*)
{
	//計算直方圖
	float range[] = { 0,180 };
	const float *histRanges = { range };
	Mat h_hist;
	calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
	//歸一化
	normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());

	//計算反向投影圖像 - calcBackProject
	Mat backProjectIamge;
	calcBackProject(&hue, 1, 0, h_hist, backProjectIamge, &histRanges, 1, true);

	namedWindow("BackProjectIamge", CV_WINDOW_AUTOSIZE);
	imshow("BackProjectIamge", backProjectIamge);

	//畫直方圖
	int hist_h = 400;
	int hist_w = 400;
	int bin_w = (hist_w / bins);
	Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
	for (size_t i = 1; i < bins; i++)
	{
		rectangle(histImage,
			Point((i - 1)*bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1)*(400 / 255)))),
			Point(i*bin_w, (hist_h - cvRound(h_hist.at<float>(i)*(400 / 255)))),
			Scalar(0, 0, 255), 2, LINE_AA);
	}
	imshow("Histogram", histImage);
	return;
}

效果圖:      (原圖)                                                            (反向投影圖)                                                         (直方圖模型)

六、模板匹配

        模板匹配(TemplateMatching)就是在一幅圖像中尋找和模板圖像(template)最相似的區域,該方法原理簡單計算速度快,能夠應用於目標識別,目標跟蹤等多個領域。

C++: void matchTemplate(InputArray image, InputArray templ, OutputArray result, int method);
C: void cvMatchTemplate(const CvArr* image, const CvArr* templ, CvArr* result, int method);
//參數介紹在下面代碼裏面

 匹配方法(method):

示例程序:

//模板匹配(template match)
//模板匹配就是在整個圖像區域發現與給定子圖像匹配的小塊區域。
//工作方法,在帶檢測圖像上,從左到右,從上向下計算模板圖像與重疊子圖像的匹配度,匹配程度越大,兩者相同的可能性越大。
//OpenCV 提供了 6 種計算兩幅圖像相似度的方法。
//差值平方和匹配 CV_TM_SQDIFF
//標準化差值平方和匹配 CV_TM_SQDIFF_NORMED
//相關匹配 CV_TM_CCORR
//標準相關匹配 CV_TM_CCORR_NORMED
//相關匹配 CV_TM_CCOEFF
//標準相關匹配 CV_TM_CCOEFF_NORMED

#include"stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace std;
using namespace cv;

Mat test, temp;
const char*input = "deteected image";
int match_method = CV_TM_SQDIFF;
int max_track = 5;
void template_match_demo(int, void*);
int main(int argc, char*argv)
{
	test = imread("C:/Users/zhj/Desktop/image/mixed_02.png");//待檢測圖像
	temp = imread("C:/Users/zhj/Desktop/image/template1.png");//模板圖像
	if (test.empty())
	{
		cout << "could not load image...\n" << endl;
		return -1;
	}
	namedWindow(input, CV_WINDOW_AUTOSIZE);
	namedWindow("template image", CV_WINDOW_AUTOSIZE);
	namedWindow("template_match_demo", CV_WINDOW_AUTOSIZE);
	namedWindow("result", CV_WINDOW_AUTOSIZE);
	imshow(input, test);
	imshow("template image", temp);

	createTrackbar("template match means", input, &match_method, max_track, template_match_demo);//上面六種方法對應數字依次是0到5;
	template_match_demo(0, 0);

	waitKey(0);
	return 0;
}

void template_match_demo(int, void*)
{
	int result_rows = test.rows - temp.rows + 1;
	int result_cols = test.cols - test.cols + 1;
	Mat result(result_rows, result_cols, CV_32FC1);

	//模板匹配
	matchTemplate(test, temp, result, match_method);
	//matchTemplate(
	//InputArray image,// 源圖像,必須是8-bit或者32-bit浮點數圖像
	//InputArray templ,// 模板圖像,類型與輸入圖像一致
	//OutputArray result,// 輸出結果,必須是單通道32位浮點數,假設源圖像WxH,模板圖像wxh,則結果必須爲W - w + 1, H - h + 1的大小。
	//int method,//使用的匹配方法
	//InputArray mask = noArray()//(optional) )

	//歸一化
	normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

	//尋找模板匹配的最大最小匹配值
	Point minLoc;
	Point maxLoc;
	Point match_loc;
	double min_value, max_value;
	minMaxLoc(result, &min_value, &max_value, &minLoc, &maxLoc, Mat());
	//void minMaxLoc(const MatND& src, double* minVal, double* maxVal, int* minIdx=0, int* maxIdx=0, const MatND& mask=MatND() );
	//說明:1 minMaxLoc尋找矩陣(一維數組當作向量, 用Mat定義) 中最小值和最大值的位置.
	// 2 參數若不需要, 則置爲NULL或者0, 即可.
	//3 minMaxLoc針對Mat和MatND的重載中, 第5個參數是可選的(optional), 不使用不傳遞即可

	//如果選用平方(平方差和標準平方差)不同的方法應該取最小值,其他取最大值,這與算法的原理有關,其計算匹配值,當匹配值越小時,匹配程度越高
	if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)
	{
	match_loc = minLoc;
	}
	else
	{
	match_loc = maxLoc;
	}
	//將待檢測圖中與模板匹配出框起來
	rectangle(test, Rect(match_loc.x, match_loc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2,CV_AA);
	rectangle(result, Rect(match_loc.x, match_loc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, CV_AA);

	imshow("template_match_demo", result);
	imshow("result", test);
	return;
}

效果圖:

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