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;
}
结果图:
参考:http://blog.youkuaiyun.com/sydnash/article/details/7451039