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

轉載請注明出處與作者

這裡只討論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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值