Opencv学习-calcHist()、normalize()函数

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; 
}

4. 测试结果

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用C++实现OpenCV中的calcHist函数的示例代码: ```c++ #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main() { Mat image = imread("test.jpg", IMREAD_GRAYSCALE); //读入灰度图像 if (image.empty()) //判断图像是否为空 { cerr << "Failed to load image!" << endl; return -1; } int histSize = 256; //直方图中bin的数量 float range[] = { 0, 256 }; //像素值范围 const float* histRange = { range }; bool uniform = true, accumulate = false; Mat hist; //用于保存直方图的Mat calcHist(&image, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate); //计算直方图 int hist_w = 512, hist_h = 400; //直方图的宽和高 int bin_w = cvRound((double)hist_w / histSize); //每个bin的宽度 Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(0)); //用于绘制直方图的Mat normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); //将直方图归一化到[0, histImage.rows]范围内 for (int i = 1; i < histSize; i++) { line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(hist.at<float>(i - 1))), Point(i * bin_w, hist_h - cvRound(hist.at<float>(i))), Scalar(255), 2, LINE_AA); //在直方图上绘制每个bin的高度 } imshow("Image", image); imshow("Histogram", histImage); waitKey(0); return 0; } ``` 首先,使用`imread`函数读入灰度图像。然后,定义直方图的bin数量、像素值范围、是否均匀化、是否累加等参数,并创建一个用于保存直方图的Mat。接着,调用`calcHist`函数计算直方图。 计算完直方图后,定义用于绘制直方图的Mat,并将直方图归一化到[0, histImage.rows]范围内。最后,在直方图上绘制每个bin的高度,然后显示原始图像和直方图,等待用户按下任意键后程序结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值