一維直方圖繪製 帶縱座標
阿新 • • 發佈:2018-11-08
直方圖
灰度直方圖是灰度級的函式,描述的是影象中具有該灰度級的像元的個數。確定影象像元的灰度值範圍,以適當的灰度間隔為單位將其劃分為若干等級,以橫軸表示灰度級,以縱軸表示每一灰度級具有的像元數或該像元數佔總像元數的比例值,做出的條形統計圖即為灰度直方圖。
如下圖所示,做直方圖的過程:
直方圖的性質:
- 直方圖反映了影象中的灰度分佈規律。它描述每個灰度級具有的像元個數,但不包含這些像元在影象中的位置資訊。
- 任何一幅特定的影象都有唯一的直方圖與之對應,但不同的影象可以有相同的直方圖。
- 如果一幅影象有兩個不相連的區域組成,並且每個區域的直方圖已知,則整幅影象的直方圖是該兩個區域的直方圖之和
直方圖的應用:
- 對於每幅影象都可做出其灰度直方圖。
- 根據直方圖的形態可以大致推斷影象質量的好壞。由於影象包含有大量的像元,其像元灰度值的分佈應符合概率統計分佈規律。假定像元的灰度值是隨機分佈的,那麼其直方圖應該是正態分佈。
- 影象的灰度值是離散變數,因此直方圖表示的是離散的概率分佈。若以各灰度級的像元數佔總像元數的比例值為縱座標軸做出影象的直方圖,將直方圖中各條形的最高點連成一條外輪廓線,縱座標的比例值即為某灰度級出現的概率密度,輪廓線可近似看成影象相應的連續函式的概率分佈曲線。
直方圖均衡化
直方圖均衡化是將原影象的直方圖通過變換函式變為均勻的直方圖
計算過程如下:
- 統計原影象每一灰度級的像元數和累積像元數。
- 按下圖公式計算變換後的值
- 四捨五入得到新的灰度值
- 統計像元
接下來介紹:一維直方圖繪製 帶縱座標
程式碼如下:
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> using namespace cv; using namespace std; int main() { Mat srcImage = imread("C://1.bmp",0);//只讀取灰度圖 if (!srcImage.data) { cout << "fail to load image" << endl; return 0; } imshow("原圖", srcImage); MatND dstHist;//得到的直方圖 int dims = 1;//得到的直方圖的維數 灰度圖的維數為1 float hranges[2] = { 1, 255 }; //直方圖統計的灰度值範圍 const float *ranges[1] = { hranges }; // 這裡需要為const型別,二維陣列用來指出每個區間的範圍 int bin = 255;//直方圖橫座標的區間數 即橫座標被分成多少份 int channels = 0;//影象得通道 灰度圖的通道數為0 /* 計算影象的直方圖 */ calcHist(&srcImage, 1/*輸入影象個數*/, &channels, Mat()/*掩碼*/, dstHist, dims, &bin, ranges); int height = 150; //直方圖高度 int scale = 3; //垂直縮放比 int horvizon_scale = 3; //水平縮放比 //獲取最大值和最小值 double minValue = 0; double maxValue = 0; minMaxLoc(dstHist, &minValue, &maxValue, 0, 0); //找到直方圖中的最大值和最小值 int shift_vertical = 13; //直方圖偏移值,偏移用於顯示水平座標 int shift_horvizon = 30; //直方圖偏移值,偏移用於顯示垂直座標 //繪製出直方圖 Mat dstImage(height*scale, bin*horvizon_scale + shift_horvizon, CV_8UC3, Scalar(0, 0, 0)); //建立一個彩色三通道矩陣,大小a*b,填充0 int hpt = saturate_cast<int>((dstImage.rows - shift_vertical)*0.95); //最大值對應的Y座標,防止溢位 for (int i = 0; i < bin; i++) { float binValue = dstHist.at<float>(i); int realValue = saturate_cast<int>(binValue * hpt / maxValue); rectangle(dstImage, Point(i*horvizon_scale + shift_horvizon, dstImage.rows - 1 - shift_vertical), Point((i + 1)*horvizon_scale + shift_horvizon - 1, dstImage.rows - realValue - shift_vertical), Scalar(255, 255, 255), 1, 8, 0); } //繪製垂直刻度 char string[100]; CvFont font; double font_size = 1;//字型大小 cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1, 1, 0, 1, 8);//字型結構初始化 Size text_size; for (int i = hpt; i>=0; ) { _itoa(maxValue*i/hpt, string, 10);//把一個整數轉換為字串 //在影象中顯示文字字串 text_size = getTextSize(string, CV_FONT_HERSHEY_PLAIN, font_size, 1, NULL); //獲得字型大小 putText(dstImage, string, cvPoint(0, dstImage.rows - i - shift_vertical + text_size.height/2), cv::FONT_HERSHEY_PLAIN, font_size, Scalar(0, 255, 0), 1, 8, 0); i -= hpt / 10; //只顯示10個刻度 } //刻畫水平刻度 for (int i = bin; i >= 0;) { _itoa(i, string, 10);//把一個整數轉換為字串 //在影象中顯示文字字串 text_size = getTextSize(string, CV_FONT_HERSHEY_PLAIN, font_size, 1, NULL); //獲得字型大小 putText(dstImage, string, cvPoint(i*horvizon_scale + shift_horvizon - text_size.width/2, dstImage.rows), cv::FONT_HERSHEY_PLAIN, font_size, Scalar(0, 0, 255), 1, 8, 0); i -= bin / 20; //只顯示20個刻度 } //顯示統計資訊 sprintf(string, "bin=%d Ranges from %d to %d", bin, (int)hranges[0], (int)hranges[1]); putText(dstImage, string, cvPoint(dstImage.cols/5, 30), cv::FONT_HERSHEY_PLAIN, (double)1.3, Scalar(255, 0, 0), 1, 8, 0); imshow("一維直方圖", dstImage); waitKey(0); return 0; }
測試結果如下: