下面是我參考《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, 而實際值應該是 0int 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。