1. 程式人生 > >【VC++、OpenCV3.4】直方圖以及相關

【VC++、OpenCV3.4】直方圖以及相關

直方圖(Histogram)均衡化:是一種體改影象對比度的方法,拉伸影象灰度值範圍。

/*
The algorithm normalizes the brightness and increases the contrast of the image.

@param src Source 8-bit single channel image.
@param dst Destination image of the same size and type as src .
 */
CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );

src必須是8位的單通道影象。

直方圖均衡化思想:把原始影象的直方圖變為均勻分佈的的形式,這樣就增加了畫素灰度值的動態範圍,從而達到了增強影象的整體對比度的效果。

直方圖本身:

直方圖是對一幅影象中出現的所有畫素值的頻次統計。將統計結果話在座標系中,x橫座標代表畫素值,y縱座標代表的是對應畫素值出現的次數。

除了對影象畫素值的直方圖,還有影象梯度、每個畫素的角度、等一切影象的屬性值,我們都可以建立直方圖。但是,影象畫素的直方圖是最常見的。

直方圖有幾個屬性:

dims:表示維度,對灰度影象來說只有一個通道,則dims=1;

bins:表示在維度中子區域大小劃分,bins=256,劃分為256個級別;

range:表示值的範圍,灰度值範圍為[0~255]之間。

相關API:

/*
@param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same
size. Each of them can have an arbitrary number of channels.
@param nimages Number of source images.
@param channels List of the dims channels used to compute the histogram. The first array channels
are numerated from 0 to images[0].channels()-1 , the second array channels are counted from
images[0].channels() to images[0].channels() + images[1].channels()-1, and so on.
@param mask Optional mask. If the matrix is not empty, it must be an 8-bit array of the same size
as images[i] . The non-zero mask elements mark the array elements counted in the histogram.
@param hist Output histogram, which is a dense or sparse dims -dimensional array.
@param dims Histogram dimensionality that must be positive and not greater than CV_MAX_DIMS
(equal to 32 in the current OpenCV version).
@param histSize Array of histogram sizes in each dimension.
@param ranges Array of the dims arrays of the histogram bin boundaries in each dimension. When the
histogram is uniform ( uniform =true), then for each dimension i it is enough to specify the lower
(inclusive) boundary \f$L_0\f$ of the 0-th histogram bin and the upper (exclusive) boundary
\f$U_{\texttt{histSize}[i]-1}\f$ for the last histogram bin histSize[i]-1 . That is, in case of a
uniform histogram each of ranges[i] is an array of 2 elements. When the histogram is not uniform (
uniform=false ), then each of ranges[i] contains histSize[i]+1 elements:
\f$L_0, U_0=L_1, U_1=L_2, ..., U_{\texttt{histSize[i]}-2}=L_{\texttt{histSize[i]}-1}, U_{\texttt{histSize[i]}-1}\f$
. The array elements, that are not between \f$L_0\f$ and \f$U_{\texttt{histSize[i]}-1}\f$ , are not
counted in the histogram.
@param uniform Flag indicating whether the histogram is uniform or not (see above).
@param accumulate Accumulation flag. If it is set, the histogram is not cleared in the beginning
when it is allocated. This feature enables you to compute a single histogram from several sets of
arrays, or to update the histogram in time.
*/
CV_EXPORTS void calcHist( const Mat* images, int nimages,
                          const int* channels, InputArray mask,
                          OutputArray hist, int dims, const int* histSize,
                          const float** ranges, bool uniform = true, bool accumulate = false );

/** @overload

this variant uses %SparseMat for output
*/
CV_EXPORTS void calcHist( const Mat* images, int nimages,
                          const int* channels, InputArray mask,
                          SparseMat& hist, int dims,
                          const int* histSize, const float** ranges,
                          bool uniform = true, bool accumulate = false );

/** @overload */
CV_EXPORTS_W void calcHist( InputArrayOfArrays images,
                            const std::vector<int>& channels,
                            InputArray mask, OutputArray hist,
                            const std::vector<int>& histSize,
                            const std::vector<float>& ranges,
                            bool accumulate = false );

直方圖比較方法:

將兩幅圖的直方圖H1、H2歸一化到相同的尺度空間然後通過比較H1和H2之間的距離得到兩個直方圖的相似程度進而比較影象本身的相似程度。OpenCV提供的比較方法有4中:

Correlation相關性比較

Chi-Square卡方比較

Intersection十字交叉性

Bhattacharyya distance巴氏距離

1、相關性(CV_COMP_CORREL)

d(H_{1},H_{2})=\frac{\sum (H_{1}(I)-H_{1})*(H_{2}(I)-H_{2})}{\sqrt{\sum (H_{1}(I)-H_{1})^{2}*\sum (H_{2}(I)-H_{2})^{2}}}  

其中,Hk是對應直方圖的均值,Hk(I)是對應畫素值。N是直方圖的BIN個數。H1和H2月接近,計算結果越接近1。

2、卡方(CV_COMP_CHISQR)

d(H_{1},H_{2})=\sum \frac{(H_{1}(I)-H_{2}(I))^2}{H_{2}(I)}

H1和H2越接近,計算結果越接近0。H1和H2是兩個直方圖資料。

3、十字交叉(CV_COMP_INTERSECT)——不好用

d(H_{1},H_{2})=\sum min(H_{1}(I),H_{2}(I))

4、巴氏距離又叫巴塔恰裡雅距離 / Bhattacharyya distance(CV_COMP_BHATTACHARYYA)

d(H_{1},H_{2})=\sqrt{1-\frac{1}{\sqrt{H_{1}H_{2}N^2}}*\sum H_{1}(I)H_{2}(I)}

H1和H2代表直方圖的均值。當H1和H2一樣時,H1(I)*H2(I)達到最大值,那麼d越接近1.

相關API:

首先將影象從RGB彩色空間轉換到HSV色彩空間:cvtColor

計算影象的直方圖,然後歸一化到【0-1】之間:calcHist和normalize

使用上述四種比較方法之一進行比較:compareHist

#include<opencv2/opencv.hpp>
#include<iostream>
#include<string>
#include<vector>
#include<math.h>

using namespace cv;
using namespace std;

String Path_zuo = "C:\\Users\\admin\\Desktop\\zuo.jpg";
String Path_you = "C:\\Users\\admin\\Desktop\\you.jpg";
String SourceWin = "Source window";
String OutWin = "Output window";

void mergeImg(cv::Mat &dst, cv::Mat &src1, cv::Mat &src2);
String convertToString(double d);
int main(int argv, char**argc) {

	Mat src_zuo = imread(Path_zuo, IMREAD_COLOR);
	Mat src_you = imread(Path_you, IMREAD_COLOR);
	if (!src_zuo.data | !src_you.data)
	{
		printf("Could not load the demo pic...");
		return false;
	}
	Mat dst;
	cvtColor(src_zuo, dst, COLOR_BGR2GRAY);
	Mat dst2(dst.rows, dst.cols * 2, dst.type());
	namedWindow(SourceWin, CV_WINDOW_AUTOSIZE);
	mergeImg(dst2, src_zuo, src_you);


	Mat zuo_gray, you_gray;
	cvtColor(src_zuo, zuo_gray, COLOR_BGR2HSV);
	cvtColor(src_you, you_gray, COLOR_BGR2HSV);

	//灰度等級
	int h_bins = 100;
	int w_bins = 100;
	int histSize[] = { h_bins,w_bins };
	//hue varies from 0 to 179,saturation from 0 to 255
	float h_ranges[] = { 0,180 };
	float w_ranges[] = { 0,256 };
	const float *ranges[] = { h_ranges,w_ranges };

	//use the 0-th and 1-st channels
	int channels[] = { 0,1 };
	MatND hist_src1;
	MatND hist_src2;

	calcHist(&zuo_gray, 1,channels, Mat(), hist_src1, 2, histSize, ranges, true, false);
	normalize(hist_src1, hist_src1, 0, 1, NORM_MINMAX, -1, Mat());

	calcHist(&you_gray, 1, channels, Mat(), hist_src2, 2, histSize, ranges, true, false);
	normalize(hist_src2, hist_src2, 0, 1, NORM_MINMAX, -1, Mat());

	double score = compareHist(hist_src1, hist_src2, CV_COMP_CORREL);
	printf("The coorelation about zuo and you is: %f", score);
	
	putText(dst2, convertToString(score), Point(50, 100), 1, 1, Scalar(0, 0, 255), 2);
	imshow("Out", dst2);

	//imshow("1", hist_src1);
	waitKey(0);
}

void mergeImg(cv::Mat &dst, cv::Mat &src1, cv::Mat &src2)

{

	int rows = src1.rows>src2.rows ? src1.rows : src2.rows;//合成影象的行數

	int cols = src1.cols + 10 + src2.cols;//合成影象的列數

	CV_Assert(src1.type() == src2.type());

	Mat zeroMat = Mat::zeros(rows,cols, src1.type());

	zeroMat.copyTo(dst);

	src1.copyTo(dst(cv::Rect(0, 0, src1.cols, src1.rows)));

	src2.copyTo(dst(cv::Rect(src1.cols + 10, 0, src2.cols, src2.rows)));//兩張影象之間相隔20個畫素
	putText(dst, "source_zuo", Point(50, 50), 2, 1, Scalar(0, 0, 255));
	putText(dst, "source_you", Point((50+src1.cols),50), 2, 1, Scalar(0, 255, 0));

	cv::imshow(SourceWin, dst);

}

String convertToString(double d) {
	ostringstream os;
	if (os<<d)
	{
		return os.str();
	}
	return "invalid conversion:";
}