1.1 cv.calcHist()函数,函数原型如下:
void cv::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 )
参数解释:
images:需要计算直方图的源图像阵列集;注意:它们都应该具有相同的深度、CV_8U、CV_16U或CV_32F以及相同的大小。它们中的每一个都可以具有任意数量的通道。
nimages:这个图像阵列中,图像的个数
channels:用于计算直方图中的每个维度的每个通道的列表,需要统计的图像的通道集合(是一个整型数组,且数组值不可变)。
mask:掩膜,如果掩膜非空, 那么这个掩膜必须是和源图像阵列中的图像同样大小的8位图像数组。
hist:存放经过直方图计算后的图像
dims:直方图的维度,直方图维度必须为正且不大于CV_MAX_DIMS(在当前OpenCV版本中等于32)
histSize:每个维度上直方图的尺寸大小
ranges:每个维度上直方图二进制边界的维度数组的数组,是一个二位数组。当直方图是均匀的(uniform=true)时,对于每个维度,只需指定第0个直方图的下(含)边界和最后一个直方图的上(不含)边界即可,即,在均匀直方图的情况下,每个范围是2个元素的阵列。当直方图不一致(uniform=false)时,则每个范围i中包含histSize[i]+1个元素:L0,U0=L1,U1=L2,....... ,UhistSize[i]−2=LhistSize[i]−1,UhistSize[i]−1。不在L0和UhistSize[i]−1之间的数组元素不计入直方图中。
uniform:直方图是否进行归一化处理,true为是,false为否
accumulate:累计,是否累计,如果已设置,则分配直方图时不会在开始时清除直方图。此功能使您能够从多组数组中计算单个直方图,或及时更新直方图。
实例代码
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>using namespace std;
using namespace cv;int main(int argc, char** argv)
{Mat src, dst;String imageName( "demo.jpg" ); //图像名src = imread( imageName ); // 读取这个路径下的图片放在这个src容器当中if( src.empty() ) //图片是否为空{ return -1; }vector<Mat> bgr_planes; // 创建源图像的图像容器vectorsplit( src, bgr_planes );//将这个图像在RGB三个通道分别分离出来。记得到三个通道的三张图片存放在bgr_planes中int histSize = 256; //设置直方图大小float range[] = { 0, 256 } ; // 指定饱和度范围在0~255中。const float* histRange = { range };bool uniform = true; bool accumulate = false;Mat b_hist, g_hist, r_hist;calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate ); //上边是计算三个通道三张图片的直方图。//下边是画出这三条折线图(过点划线),当然你也可以使用rectangle去绘制条形图。当然如果是Python,则可以借助三方库matlab中的方法直接完成绘图。int hist_w = 512; int hist_h = 400; //直方图宽和高int bin_w = cvRound( (double) hist_w/histSize );//得到二进制边界为直方图宽度除以直方图大小之后的结果转换为双精度浮点数之后再取最近的整数得到额结果。Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
//利用Mat的重写的构造函数构造一个histImage图像对象
//用于存储均质化(规范化一个数组的标准范围或者数组中元素值的范围)的结果。
//这个图像的大小和直方图一样大。//标准化处理:normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );for( int i = 1; i < histSize; i++ )//下边就是采点划线的过程了。{line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),Scalar( 255, 0, 0), 2, 8, 0 );line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),Scalar( 0, 255, 0), 2, 8, 0 );line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),Scalar( 0, 0, 255), 2, 8, 0 );}namedWindow("calcHist Demo", WINDOW_AUTOSIZE );imshow("calcHist Demo", histImage );waitKey(0);return 0;