1. calcHist函数
1.1 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 这 3 种中的一种,但是不同图像的通道数可以不同。
- nimages:输入的图像数量。
- channels:需要统计的通道索引数组,第一个图像的通道索引从 0 到 images[0].channels()−1,第二个图像通道索引从 images[0].channels()到 images[0].channels()+ images[1].channels()−1,依此类推。
- mask:可选的操作掩码。如果是空矩阵,那么表示图像中所有位置的像素都计入直方图中;如果矩阵不为空,那么必须与输入图像尺寸相同且数据类型为 CV_8U。
- hist:输出的统计直方图结果,是一个 dims 维度的数组。
- dims:需要计算直方图的维度,必须是整数,并且不能大于 CV_MAX_DIMS,在 OpenCV 4.0 和 OpenCV 4.1 版中为 32。
- histSize:存放每个维度直方图的数组的尺寸。
- ranges:每个图像通道中灰度值的取值范围。
- uniform:直方图是否均匀的标志符,默认状态下为均匀(true)。
- accumulate:是否累积统计直方图的标志,如果累积(true),那么,在统计新图像的直方图时,之前图像的统计结果不会被清除,该参数主要用于统计多个图像整体的直方图。
该函数用于统计图像中每个灰度值像素的个数,例如统计一幅 CV_8UC1 的图像,需要统计灰度值从 0 至 255 中每一个灰度值在图像中的像素个数,如果某个灰度值在图像中没有,那么该灰度值的统计结果就是 0 。由于该函数具有较多的参数,并且每个参数都较为复杂,因此作者建议在使用该函数时只统计单通道图像的灰度值分布,对于多通道图像,可以将图像每个通道分离后再进行统计。
为了使读者更加了解函数的使用方法,代码清单 4-2 中提供了绘制灰度图像的图像直方图的示例程序。在该程序中,首先使用 calcHist() 函数统计灰度图像中每个灰度值的数目,之后通过不断绘制矩形的方式实现直方图的绘制。由于图像中部分灰度值像素数目较多,因此将每个灰度值数目缩小为原来的 1/20 后再进行绘制,绘制的直方图如图 4-1 所示。在该程序中,使用了 OpenCV 4 提供的四舍五入的取整函数 cvRound() ,该函数输入参数为 double 类型的变量,返回值为对该变量四舍五入后的 int 型数值。
2. normalize()函数
2.1 normalize()函数原型
void cv::normalize(InputArray src,
InputOutputArray dst,
double alpha = 1,
double beta = 0,
int norm_type = NORM_L2,
int dtype = -1,
InputArray mask = noArray()
)
- src:输入数组矩阵。
- dst:输入与 src 相同大小的数组矩阵。
- alpha:在范围归一化的情况下,归一化到下限边界的标准值。
- beta:范围归一化时的上限范围,它不用于标准规范化。
- norm_type:归一化过程中数据范数种类标志,常用的可选择参数在表 4-1 中给出。
- dtype:输出数据类型选择标志。如果其为负数,那么输出数据与 src 拥有相同的类型,否则与 src 具有相同的通道数,但是数据类型不同。
- mask:掩码矩阵。
该函数输入一个存放数据的矩阵,通过参数 alpha 设置将数据缩放到最大范围,然后通过norm_type 参数选择计算范数的种类,之后将输入矩阵中的每个数据分别除以求取的范数数值,最 后得到缩放的结果。输出结果是一个 CV_32F 类型的矩阵,可以将输入矩阵作为输出矩阵,或者重新定义一个新的矩阵用于存放输出结果。该函数的第 5 个参数用于选择计算数据范数的种类,常用的可选择参数以及计算范数的公式在表 4-1 中给出。计算不同的范数,最后的结果也不相同,例如选择 NORM_L1 标志,输出结果为每个灰度值所占的比例;选择 NORM_INF 参数,输出结果为除以数据中最大值,将所有的数据归一化为 0 ~ 1 。
normalize()函数归一化常用标志参数
3. 代码示例
#include <opencv2/opencv.hpp>
#include <iostream> using namespace cv;
using namespace std; int main()
{ vector<double> positiveData = { 2.0, 8.0, 10.0 }; vector<double> normalized_L1, normalized_L2, normalized_Inf, normalized_L2SQR,normalized_MINMAX; //测试不同归一化方法normalize(positiveData, normalized_L1, 1.0, 0.0, NORM_L1); //绝对值求和归一化cout <<"normalized_L1=["<< normalized_L1[0]<<", " << normalized_L1[1]<<", "<< normalized_L1[2] <<"]"<< endl; normalize(positiveData, normalized_L2, 1.0, 0.0, NORM_L2); //模长归一化cout << "normalized_L2=[" << normalized_L2[0] << ", " << normalized_L2[1] << ", " << normalized_L2[2] << "]" << endl; normalize(positiveData, normalized_Inf, 1.0, 0.0, NORM_INF); //最大值归一化cout << "normalized_Inf=[" << normalized_Inf[0] << ", " << normalized_Inf[1] << ", " << normalized_Inf[2] << "]" << endl; normalize(positiveData, normalized_MINMAX, 1.0, 0.0, NORM_MINMAX); //偏移归一化cout << "normalized_MINMAX=[" << normalized_MINMAX[0] << ", " << normalized_MINMAX[1] << ", " << normalized_MINMAX[2] << "]" << endl;Mat img = imread("../pic/gril.jpg"); if (img.empty()) { cout << "请确认图像文件名称是否正确" << endl; return -1; } Mat gray; //cvtColor(img, gray, COLOR_BGR2GRAY); Mat imgs[3],imgs0,imgs1,imgs2; split(img, imgs); imgs0 = imgs[0]; imgs1 = imgs[1]; imgs2 = imgs[2];//设置提取直方图的相关变量Mat b_hist,g_hist,r_hist; //用于存放直方图计算结果const int channels[1] = { 0 }; //通道索引float inRanges[2] = { 0,255 }; const float* ranges[1] = { inRanges }; //像素灰度值范围const int bins[1] = { 256 }; //直方图的维度,其实就是像素灰度值的最大值calcHist(&imgs[0], 1, 0, Mat(), b_hist, 1, bins, ranges, true, false); //计算图像直方图calcHist(&imgs[1], 1, 0, Mat(), g_hist, 1, bins, ranges, true, false); //计算图像直方图calcHist(&imgs[2], 1, 0, Mat(), r_hist, 1, bins, ranges, true, false); //计算图像直方图//准备绘制直方图int hist_w = 500; int hist_h = 400; int width = 2; Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);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 <= 255; i++) { line(histImage, Point(width*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),Point(width*(i), hist_h - cvRound(b_hist.at<float>(i)/2)), Scalar(255, 0, 0),2);line(histImage, Point(width*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),Point(width*(i), hist_h - cvRound(g_hist.at<float>(i)/2)), Scalar(0, 255, 0),2);line(histImage, Point(width*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),Point(width*(i), hist_h - cvRound(r_hist.at<float>(i)/2)), Scalar(0, 0, 255),2);} namedWindow("histImage", WINDOW_AUTOSIZE); imshow("histImage", histImage); imshow("img", img); waitKey(0); return 0;
}