OpenCV學習心得(8) -- 直方圖的顯示

原创 2012年03月22日 16:55:22

轉載請注明出處與作者

這裡只討論1維的直方圖

void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist,

       int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )

這個函數可以用來計算直方圖.

arrays 源Mat數組的指針

narrays  源Mat數組中Mat的個數

channels 這是一個int型指針,它指向一個數組,為哪些channel需要被計算.當arrays 為多個Mat的時候,channel index是從0開始向下連續計算的.這個數組的大小應該與dims相同.

mask 必須是8-bit 圖像遮罩矩陣,大小與源Mat相同,非0元素對應的源Mat中的點表示為需要計算的點.如果為空則表示所有點都需要計算.

hist 輸出的直方圖矩陣.注意這只是一個數值統計矩陣,並非圖像.

dims 直方圖的維度,必須是正整數,並且不能大於CV_MAX_DIMS.

histSize 表示在計算直方圖的時候要分成多少個塊來計算.最終結果的hist矩陣的行數(rows)就是這個histSize.也就是將要統計的值分成histSize 個區域,像素點落在其中哪個區域,哪個區域的值就增加.

ranges 這是一個指針數組,數組中的每一個元素都是一個指針,這個指針指向一個多元素的數組.這個參數數用來確定histSize 個塊中的每一個塊的數值範圍.

下面詳細說明一下histSize和ranges的關係:

可以這樣認為:histSize和ranges都是數組,histSize數組中存放的是整數,ranges數組中存放的是數組型指針. histSize和ranges這兩個數組的維數應該是一樣的,都等於直方圖的維度dims .也就是說每一個histSize元素都對應一個ranges元素.

當uniform=true的時候,ranges[i]中 只要有2個值(也就是一個區間)就可以了,函數會根據histSize[i] 的數量對這個區間進行等分.

當uniform=false的時候,ranges[i]中要有histSize[i] +1個元素.這histSize[i] +1個元素正好分割成histSize[i]個區間.

當源矩陣中的元素值落在對應區間中,則對應區間的值增加.

accumulate為累加設置,當為true的時候不會清空hist中已經存在的數據,而是在其基礎上進行累加.當為false的時候則從0開始計算.


最後得到一個dims列,每列histSize[i] 行的矩陣.這個矩陣就是我們要得到的直方圖hist.


如何將直方圖矩陣中的數據以圖表的方式顯示出來呢?

方法就是事先準備一個Mat并對其進行初始化,初始化包括設定寬度,高度,type和背景圖像(也就是要填充一個背景,可以用圖片或純色).然後使用OpenCV的劃綫函數在其上進行劃綫或寫文字...然後顯示出來即可.

劃綫的時候一定要先將直方圖中的數值縮放到圖像大小再劃綫.(可以畫線也可以畫矩形)


	//!得到一個channel的一維直方圖.
	//!channelIndex 為channel的序號,從0開始,blockcount為需要將range中的值分成多少個區塊來統計,最終得出的直方圖會有blockcount個點.
	//!range_low為圖像數據範圍的最小值,range_up為圖像數據範圍的最大值,這個範圍之外的數據將不被統計.
	static bool GetHistogram_SingleChannel(const cv::Mat &src,cv::Mat &hist,int channelIndex,int blockcount,float range_low,float range_up);
	//將直方圖矩陣中的數據轉換為圖像.
	//type 圖像類型 0=線型 1=矩形
	//imgsize 圖像大小,如果為空則根據直方圖矩陣中的行數來確定(線型為行數,矩形為行數*2),高度為256.color為線或矩形的顏色(默認為黑色),backcolor為背景填充的顏色(默認為白色).
	static bool GetHistogramImage(const cv::Mat& hist, cv::Mat &image,int type,cv::Size imgsize,cv::Scalar *color=NULL,cv::Scalar *backcolor=NULL);
	//!統計源Mat中的直方圖并將其轉換為圖形.
	//!channelIndex 為channel的序號 ,type 圖像類型 0=線型 1=矩形
	//!color為線或矩形的顏色(默認為黑色),backcolor為背景填充的顏色(默認為白色)
	bool GetHistogram(int channelIndex=0,int type=0,RGBQUAD *color=NULL,RGBQUAD *backcolor=NULL);

bool COpenCVImage::GetHistogram_SingleChannel(const cv::Mat &src,cv::Mat &hist,int channelIndex,int blockcount,float range_low,float range_up)
{
	if(src.channels()<=channelIndex || src.depth()!=CV_8U) return false;
	int channels[]={channelIndex};
	int histSize[]={blockcount};
	float hrange[]={range_low,range_up};
	const float *ranges[]={hrange};
	cv::calcHist(&src,1,channels,cv::Mat(),hist,1,histSize,ranges);
	return true;
}
bool COpenCVImage::GetHistogramImage(const cv::Mat& hist, cv::Mat &image,int type,cv::Size imgsize,cv::Scalar *color,cv::Scalar *backcolor)
{
	double maxVal = 0;
	double minVal = 0;
	cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
	if(imgsize==cv::Size())
	{
		switch(type)
		{
			case 1://矩形
				{
					imgsize.width=2*hist.rows;
					imgsize.height=256;
					break;
				}
			case 0://連線
			default:
				{
					imgsize.width=hist.rows;
					imgsize.height=256;
				}
		}
	}
	cv::Mat histImg(imgsize, CV_8UC3,(backcolor==NULL? cv::Scalar(255,255,255,0):*backcolor));
	//int hpt = static_cast<int>(0.9*imgsize.height);
	float tmp;
	for(int h=0; h<hist.rows; h++)
	{       
		switch(type)
		{
		    
			case 1://矩形
				{
					float binVal = hist.at<float>(h);
					int rectangle_w= cvRound((imgsize.width/hist.rows+0.5)/2);
					int Point2 = cvRound(binVal*0.9*imgsize.height/maxVal);
					cv::rectangle(histImg,cv::Rect(h*(imgsize.width/hist.rows),imgsize.height-Point2,rectangle_w,Point2),(color==NULL?cvScalar(0,0,0,0):*color));
					//tmp=binVal;
				
					break;
				}
			case 0: //連線
			default:
			{
				if(h==0)
				{
					tmp=hist.at<float>(h);
					continue;
				}
				float binVal = hist.at<float>(h);
				int Point1 = static_cast<int>(tmp*0.9*imgsize.height/maxVal);
				int Point2 = static_cast<int>(binVal*0.9*imgsize.height/maxVal);
				cv::line(histImg, cv::Point(h-1,imgsize.height-Point1),cv::Point(h,imgsize.height-Point2), (color==NULL?cvScalar(0,0,0,0):*color));
			    tmp=binVal;
			}
		}
	}
	image=histImg;
	return true;
}

bool COpenCVImage::GetHistogram(int channelIndex,int type,RGBQUAD *color,RGBQUAD *backcolor)
{
	cv::Mat hist;
	if(!GetHistogram_SingleChannel(m_src(r_roi),hist,channelIndex,256,0.0f,255.0f))
	{
		return false;
	}
	GetHistogramImage(hist,m_src,type,cv::Size(),
		(color==NULL?&cv::Scalar(0,0,0,0):&cv::Scalar(color->rgbBlue,color->rgbGreen,color->rgbRed,color->rgbReserved)),
		(backcolor==NULL?&cv::Scalar(255,255,255,0):&cv::Scalar(backcolor->rgbBlue,backcolor->rgbGreen,backcolor->rgbRed,backcolor->rgbReserved))
		);
    m_modifyed_for_draw=true;
	return true;
}

OpenCV還提供了一個直方圖均衡化的函數

void equalizeHist(InputArray src, OutputArray dst)

可以進行直方圖均衡化.

bool COpenCVImage::equalizeHist()
{
	if(m_src.channels()!=1 || m_src.depth()!=CV_8U) return false;
	cv::equalizeHist(m_src(r_roi),m_src(r_roi));
	m_modifyed_for_draw=true;
	return true;
}


相关文章推荐

OpenCV数字图像处理五:显示直方图

本程序的开发环境为OpenCV2.4.3,其中OpenCV2.0以上版本都可以使用,编译环境为VS。 源程序如下: #include "opencv2/highgui/highgui.hpp" #in...

opencv计算图像互信息熵

主要代码如下://单幅图像信息熵计算

opencv学习心得(一)鼠标响应事件绘制轮廓

//#include "gaosi.h" #include #include #include using namespace cv; using namespace std; //声明全局变...

c++和opencv学习心得

1.表达式a^2中,a必须为int型的,而pow(a,2)中a可以是float型的;2.sqrt(b),b在c++下为float或double long型,在c下一般为double型;(msdn:C+...
  • ycx2006
  • ycx2006
  • 2011年03月10日 21:44
  • 729

OpenCV學習心得(11) -- Mat類型與Arraya

轉載請注明出處與作者 下面對Mat矩陣進行一些說明: 1. cv::Mat中的數據不需要釋放.cv::Mat會自動釋放. 例如,cv::Mat m=cv::imread("123.jpg")...

OpenCV學習心得(7) -- 閾值處理

轉載請注明出處與作者 OpenCV提供了2個函數來處理閾值. 第一個函數 double threshold(InputArray src, OutputArray dst, double thr...

OpenCV學習心得(6) -- 圖像的縮放

轉載請著名出處與作者 OpenCV提供了一個實現圖像縮放的函數:cv::resize void resize(InputArray src, OutputArray dst, Size dsize...

opencv学习心得(六)新版本绘制外形轮廓。

最近在研究opencv2.3.1版本函数,因为函数结构使用C++类型的,所以在一些函数调用上有很多差别,但是在运行速度上提高不少,所以还是新版本好用。其实在新版本发布是,会有相关的使用手册,很多例子会...

OpenCV學習心得(5) -- 圖像通道分離

轉載請注明出處與作者 OpenCV提供了一個函數可以進行通道的分離,就是 cv::split. void split(const Mat& mtx, vector& mv); void sp...

opencv学习心得(四)——opencv提取截获图像

首先确定选区区域,这里利用鼠标选取区域具体操作看opencv学习心得(一)。 下面就是从感兴趣区域选取图像。 第一:创建图像空间,大小与rect相同。 第二:利用setroi选取区域。 第三:...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:OpenCV學習心得(8) -- 直方圖的顯示
举报原因:
原因补充:

(最多只允许输入30个字)