OpenCV 2.4.13
calcHist 通過圖像計算直方圖
函數聲明如下:
void calcHist( const Mat* images, int nimages,
const int* channels, InputArray mask,
OutputArray hist, int dims, const int* histSize,
const float** ranges, bool uniform=true, bool accumulate=false );
//1.輸入的圖像數組 2.輸入數組的個數 3.通道數 4.掩碼 5.直方圖
//6.直方圖維度 7.直方圖每個維度的尺寸數組 8.每一維數組的範圍 9.直方圖是否是均勻 10.累加標誌
1.圖像數組
2.圖像數組個數
3.圖像的通道數
4.圖像掩碼
5.計算得到的直方圖
6.直方圖的維度(灰度直方圖爲1維)
7.直方圖每一維度上的數組個數(bin 的個數)
8.每一維進行直方圖統計的數組的範圍 範圍如 0~256 表示統計 0~255的數組 這裏注意 (0,256) 包含0而不包含256 包含的是256-1
9.是否均勻的統計(個人理解爲是否統計的每個bin包含相同的灰度級 可能理解有誤)
10.累加標誌 在多幅圖像輸入時,對其中數據進行累加,單幅圖像不進行累計所以例子中爲false
以下做個了計算直方圖的例子 並進行直方圖的顯示
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
//////////////////////////////////////////////////////////////////////////////////////
// 1.一維直方圖(以灰度直方圖爲例)
//////////////////////////////////////////////////////////////////////////////////////
//以灰度讀取圖像 得到的圖像即爲灰度圖像
//cv::Mat sourceImage = cv::imread("1.bmp", cv::IMREAD_GRAYSCALE);
cv::Mat sourceImage1 = cv::imread("fruits.bmp",cv::IMREAD_COLOR); //讀取彩色圖像
cv::namedWindow("Source Image 1"); //顯示窗口
cv::imshow("Source Image 1", sourceImage1); //顯示原始圖像
cv::Mat grayImage; //灰度圖像
cv::cvtColor(sourceImage1, grayImage, cv::COLOR_BGR2GRAY); //將BGR圖像轉換爲HSV格式
///定義函數需要的一些變量
int grayImgNum = 1; //圖像數
int grayChannels = 0 ; //需要計算的通道號 單通道只有 通道號爲0
cv::Mat grayHist; //灰度圖輸出直方圖
const int grayHistDim = 1; //直方圖維數
const int grayHistSize = 256 ; //直方圖每一維度bin個數
float grayRanges[2] = { 0, 255 }; //灰度值的統計範圍
const float *grayHistRanges[1] = { grayRanges }; //灰度值統計範圍指針
bool grayUniform = true; //是否均勻
bool grayAccumulate = false; //是否累積
//計算灰度圖像的直方圖
cv::calcHist( &grayImage,
grayImgNum,
&grayChannels,
cv::Mat(),
grayHist,
grayHistDim,
&grayHistSize,
grayHistRanges,
grayUniform,
grayAccumulate );
int grayScale = 2; //控制圖像的寬大小
int histHeight = 400; //直方圖顯示圖像高度
int binHeight = histHeight-50; //繪製時,bin的最大高度
//直方圖的圖片,初始全像素值爲0
cv::Mat grayHistImg(histHeight, grayHistSize* grayScale, CV_8UC1, cv::Scalar(0));
//找到最大值和最小值
double grayMaxValue = 0;
double grayMinValue = 0;
cv::minMaxLoc(grayHist, &grayMinValue, &grayMaxValue, NULL, NULL);
//輸出最大值和最小值
std::cout << "最小值:" << grayMinValue << std::endl;
std::cout << "最大值:" << grayMaxValue << std::endl;
//進行直方圖的繪製
for (size_t i = 0; i < grayHistSize; i++)
{
float bin_val = grayHist.at<float>(i);
//cvRound返回跟參數最接近的整數值,即四捨五入
int intensity = cvRound( bin_val * binHeight / grayMaxValue);
// 繪製直線 這裏用每scale條豎向直線代表一個bin
for (size_t j = 0; j < grayScale; j++)
{
cv::line( grayHistImg,
cv::Point(i*grayScale + j, histHeight - intensity),
cv::Point(i*grayScale + j, histHeight - 1),
255 );
}
}
cv::namedWindow("grayHistImg");
cv::imshow("grayHistImg", grayHistImg);
//cv::waitKey(0);
//cv::destroyAllWindows();
//////////////////////////////////////////////////////////////////////////////////////
// 2.二維直方圖(以HSV空間的 h,s通道爲例)
//////////////////////////////////////////////////////////////////////////////////////
cv::Mat sourceImage2 = cv::imread("flowers.bmp", cv::IMREAD_COLOR); //讀取彩色圖像
cv::namedWindow("Source Image 2"); //顯示窗口
cv::imshow("Source Image 2", sourceImage2); //顯示原始圖像
cv::Mat hsvImage; //hsv圖像
cv::cvtColor(sourceImage2, hsvImage, cv::COLOR_RGB2HSV); //將R、G、B圖像轉換爲HSV格式
int hsvImgNum = 1; //圖像數
int hsvChannels[2] = { 0 , 1 }; //需要計算的通道號 hsv的 0通道和1通道
cv::Mat hsvHist; //hsv圖像的二維直方圖
const int hsvHistDim = 2; //直方圖維數
int hBins = 30, sBins = 30;
const int hsvHistSize[2] = { hBins,sBins }; //存放每個維度直方圖尺寸(bin數量)的數組histSize
float hRanges[2] = { 0,256 }; //hue的值得統計範圍 0-179
float sRanges[2] = { 0,256 }; //saturation的統計範圍 0-255
const float *hsvHistRanges[2] = { hRanges , sRanges }; //hsv統計範圍的指針
bool hsvUniform = true; //是否均勻
bool hsvAccumulate = false; //是否累積
//計算HSV圖像的hst通道的二維直方圖
cv::calcHist( &hsvImage,
hsvImgNum,
hsvChannels,
cv::Mat(),
hsvHist,
hsvHistDim,
hsvHistSize,
hsvHistRanges,
hsvUniform,
hsvAccumulate);
double hsvMaxVal = 0;
double hsvMinVal = 0;
minMaxLoc(hsvHist, &hsvMinVal, &hsvMaxVal, 0, 0); //找到直方圖矩陣hist中的最大值
int hsvScale = 15;
//創建直方圖畫布,畫布矩陣中同行的saturation值相同,同列的hue值相同
cv::Mat hsvHistImage = cv::Mat::zeros(sBins*hsvScale, hBins*hsvScale, CV_8UC3);
//掃描直方圖,填充畫布
for (int i = 0; i<sBins; i++)
{
for (int j = 0; j < hBins; j++)
{
float binValue = hsvHist.at<float>(i, j);
//將直方圖中的值歸一化到0到255
int intensity = cvRound(binValue * 255 / hsvMaxVal);
//畫矩形柱狀圖,Point的座標中x值對應着hue維度,y值對應值saturation維度,這與畫布矩陣必須一致
cv::rectangle( hsvHistImage,
cv::Point(i*hsvScale, j*hsvScale),
cv::Point((i + 1)*hsvScale - 1, (j + 1)*hsvScale - 1),
cv::Scalar::all(intensity),
cv::FILLED);
}
}
cv::namedWindow("H-S Histogram");
cv::imshow("H-S Histogram", hsvHistImage);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
結果圖: