Opencv一維直方圖的繪製

下面是我參考《opencv3編程入門》寫的繪製一維直方圖的代碼

using namespace cv;
using namespace std;
#define byte uchar 
#define TYEPE_GRAY 0
#define TYEPE_RGB 1
/*--------------------------繪製RGB三色一維直方圖-------------------------------------*/
Mat My_Rraw_histogram(Mat* srcImage,int type)  //輸入:要處理的灰度圖   輸出:該圖像的直方圖
{
 if (type == TYEPE_GRAY)  //一維灰度直方圖繪製
 {
  //【1】將原圖轉化爲灰度圖
  Mat gray_srcImage;
  cvtColor(*srcImage,gray_srcImage, COLOR_BGR2GRAY);
  //【2】定義變量
  MatND dstHist;
  int dims = 1;  //需要計算的直方圖的維數
  float grayranges[] = { 0,255 };
  const float* ranges[] = { grayranges }; //這裏需要爲const類型
  int size = 256;   //表示的是將統計的灰度值分成的等份
  int Height = 256;
  int channels = 0; //灰度圖只有一個0通道
  //【3】計算圖像直方圖
  calcHist(srcImage, //輸入數組
   1, //數組個數
   &channels, //通道索引
   Mat(),//不使用掩膜
   dstHist, //輸出的目標直方圖
   dims, //需要計算的直方圖的維數
   &size, //存放每個維度的直方圖尺寸的數組
   ranges); //每一維數值的取值範圍 
  int scale = 1;  //scale 每一個像素佔的格數
  Mat dstImage(size * scale, size, CV_8U, Scalar(0));  //長 :size*scale ,寬:size ,值爲0
  //【4】獲取最大值和最小值
  double minVal = 0;
  double maxVal = 0;
  minMaxLoc(dstHist, &minVal, &maxVal, 0, 0);  //獲得直方圖中最大值和最小值
  //【5】繪製出直方圖
  int hpt = saturate_cast<int>(0.9 * Height);   //saturate_cast 是溢出保護    大概意思 :if(data<int的負範圍)  data = 負最大; else if (data > int的正範圍) data = int 正最大;
  for (int i = 0;i < 256;i++)
  {
   float binVal = dstHist.at<float>(i);
   int realVal = saturate_cast<int>(binVal * hpt / maxVal);  //在圖像上的高度 = 像素數目/像素值最大數目 * 0.9*256   這裏0.9是爲了削減圖像像素高度,因爲最大的時候會觸及頂端不美觀
   rectangle(dstImage, Point(i * scale, Height - 1), Point((i + 1) * scale - 1, Height - realVal), Scalar(255));
   //要進行繪製的目標圖像 矩形的左下頂點 矩陣對角線上的右上頂點 線條的顏色(RGB)或亮度(灰度圖)  一共要繪製256個矩形
  }
  return dstImage;
 }
 else if (type == TYEPE_RGB)
	{
		//【1】定義變量
		MatND redHist,greenHist,blueHist;
		int dims = 1;		//需要計算的直方圖的維數
		float grayranges[] = { 0,256 };
		const float* ranges[] = { grayranges };	//這裏需要爲const類型
		int size = 256;			//表示的是將統計的灰度值分成的等份
		int channels_r[] = { 2 };	
		int channels_g[] = { 1 };	
		int channels_b[] = { 0 };	
		//疑問 : RGB圖像的R、G、B是對應channel[0]、channel[1]、channel[2]還是對應channel[2]、channel[1]、channel[0] ?
		//經過驗證是channel[2]、channel[1]、channel[0]
		//【2】計算圖像直方圖
		//--------------------red--------------------------
		calcHist(srcImage,	//輸入數組
			1,	//數組個數
			channels_r,	//通道索引
			Mat(),//不使用掩膜
			redHist,	//輸出的目標直方圖
			dims,	//需要計算的直方圖的維數
			&size,	//存放每個維度的直方圖尺寸的數組
			ranges,//每一維數值的取值範圍	
			true,//指示直方圖是否均勻的標識符,true表示均勻的直方圖
			false);	//累計標識符,false表示直方圖在配置階段會被清零
		//--------------------green--------------------------
		calcHist(srcImage,	//輸入數組
			1,	//數組個數
			channels_g,	//通道索引
			Mat(),//不使用掩膜
			greenHist,	//輸出的目標直方圖
			dims,	//需要計算的直方圖的維數
			&size,	//存放每個維度的直方圖尺寸的數組
			ranges,//每一維數值的取值範圍	
			true,//指示直方圖是否均勻的標識符,true表示均勻的直方圖
			false);	//累計標識符,false表示直方圖在配置階段會被清零
		//--------------------blue--------------------------
		calcHist(srcImage,	//輸入數組
			1,	//數組個數
			channels_b,	//通道索引
			Mat(),//不使用掩膜
			blueHist,	//輸出的目標直方圖
			dims,	//需要計算的直方圖的維數
			&size,	//存放每個維度的直方圖尺寸的數組
			ranges,//每一維數值的取值範圍	
			true,//指示直方圖是否均勻的標識符,true表示均勻的直方圖
			false);	//累計標識符,false表示直方圖在配置階段會被清零

		//【3】獲取最大值和最小值
		double minVal_r = 0, minVal_g = 0, minVal_b = 0;
		double maxVal_r = 0, maxVal_g = 0,maxVal_b = 0;
		minMaxLoc(redHist, &minVal_r, &maxVal_r, 0, 0);		//獲得r直方圖中最大值和最小值
		minMaxLoc(greenHist, &minVal_g, &maxVal_g, 0, 0);		//獲得g直方圖中最大值和最小值
		minMaxLoc(blueHist, &minVal_b, &maxVal_b, 0, 0);		//獲得b直方圖中最大值和最小值

		int scale = 1;		//scale 每一個像素佔的格數
		int Height = 256;	//直方圖高度
		Mat dstImage(Height, size*3, CV_8UC3, Scalar(0,0,0));		//長 :size*scale ,寬:size*3 ,值爲0  將三個直方圖橫放在一起
		//【4】繪製出直方圖
		int hpt = saturate_cast<int>(0.9 * Height);			//saturate_cast 是溢出保護    大概意思 :if(data<int的負範圍)  data = 負最大; else if (data > int的正範圍) data = int 正最大;
		for (int i = 0;i < 256;i++)
		{
			float binVal_r = redHist.at<float>(i);
			float binVal_g = greenHist.at<float>(i);
			float binVal_b = blueHist.at<float>(i);
			//疑問:是否存在一張圖片中maxVal_r or maxVal_g or maxVal_b 有一個值爲0?這樣算出來的值將會是0/0, 而實際值應該是 0
			int intensityl_r = saturate_cast<int>(binVal_r * hpt / maxVal_r);		//在圖像上的高度 = 像素數目/像素值最大數目 * 0.9*256   這裏0.9是爲了削減圖像像素高度,因爲最大的時候會觸及頂端不美觀
			int intensityl_g = saturate_cast<int>(binVal_g * hpt / maxVal_g);
			int intensityl_b = saturate_cast<int>(binVal_b * hpt / maxVal_b);
			
			rectangle(dstImage, Point(i * scale, Height - 1), Point((i + 1) * scale - 1, Height - intensityl_r), Scalar(0,0,255));
			rectangle(dstImage, Point((i+size)* scale, Height - 1), Point((i + size + 1)* scale - 1, Height - intensityl_g), Scalar(0,255,0));
			rectangle(dstImage, Point((i + 2*size)* scale, Height - 1), Point((i + 2*size + 1)* scale - 1, Height - intensityl_b), Scalar(255,0,0));
			//要進行繪製的目標圖像 矩形的左下頂點 矩陣對角線上的右上頂點 線條的顏色(RGB)或亮度(灰度圖)  一共要繪製256個矩形
		}
		return dstImage;
	} 
else
	{

	}
}
//主函數
int main()
{
	//【1】載入原圖
	Mat srcImage = imread("D:\\opencv_picture_test\\RGB純色圖\\red.jpg", 2|4);			//原圖
	//Mat srcImage = imread("D:\\opencv_picture_test\\JQ\\JQ14.jpg", 2 | 4);			//原圖
	namedWindow("原圖", WINDOW_NORMAL);//WINDOW_NORMAL允許用戶自由伸縮窗口
	imshow("原圖", srcImage);
	if (srcImage.empty())
	{
		printf("Could not find the image!\n");
		return -1;
	}
	Mat dstImage = My_Rraw_histogram(&srcImage, TYEPE_RGB);
	namedWindow("一維直方圖", WINDOW_NORMAL);//WINDOW_NORMAL允許用戶自由伸縮窗口
	imshow("一維直方圖", dstImage);
	waitKey(0);
	return 0;
}

下面是代碼實現的效果
原圖純紅
一維直方圖
純紅時,cahnnel【2】值爲255的像素個數最多,其他爲0,channel【1】和channel【0】值爲0的像素個數最多,其他爲0。

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