OpenCV 【九】——calcHist ——图像直方图统计

calcHist() 计算直方图实现(C++、opencv)

1.作用:

       图像直方图是对数据集合的一种统计方法,将统计结果分布于一系列预定义的bin中,bin是直方图中经常用到的一个概念,其数值是从数据中计算出的特征统计量,这些数据不仅仅指的灰度值,统计数据可能是任何能有效描述图像的特征包括梯度、方向、色彩或任何其他特征。直方图获得的是数据分布的统计图,通常直方图的维数要低于原始数据。
图像直方图是用以表示数字图像中亮度分布的直方图,标绘了图像中亮度值的像素数。可以借助观察该直方图调整亮度分布,这种直方图中横坐标的左侧为纯黑或较暗区域,右侧为较亮纯白的区域。可用于实现图像的二值化
假设有一个矩阵包含一张图像信息(灰度值0-255),如下:

2.函数原型 

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.累加标志

参数详解:

 images:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U or CV_32F)。同时一副图像可以有多个channes。

nimages:输入图像的个数

 channels:需要统计直方图的第几通道。用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。

mask:掩膜,如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算掩膜内的直方图  ...Mat()

hist:输出的直方图数组

dims:需要统计直方图通道的个数

histSize:指的是直方图分成多少个区间,就是 bin的个数。在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。

const float** ranges: 统计像素值得区间。比如: 

        float rang1[] = {0, 20};

        float rang2[] = {30, 40};

        const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。

uniform=true::是否对得到的直方图数组进行归一化处理

accumulate=false:在多个图像时,是否累计计算像素值得个数

1.图像数组              2.图像数组个数      3.图像的通道数    4.图像掩码       5.计算得到的直方图

6.直方图的维度(灰度直方图为1维)      7.直方图每一维度上的数组个数(bin 的个数)

8.每一维进行直方图统计的数组的范围  范围如 0~256 表示统计 0~255的数组 这里注意 (0,256) 包含0而不包含256 包含的是256-1

9.是否均匀的统计

10.累加标志   在多幅图像输入时,对其中数据进行累加,单幅图像不进行累计所以例子中为false

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: 将数组归一化范围的最大值,有默认值1
. beta: 归一化的最小值,有默认值0
. norm_type: 归一化方式,可以查看NormTypes()函数查看详细信息,有默认值NORM_L2
. dtype: 当该值取负数时,输出数组与src有相同类型,否则,与src有相同的通道并且深度为CV_MAT_DEPTH(dtype)
. mask: 可选的掩膜版

3.实现:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat srcImage;
    srcImage = imread("E:\\workspace\\opencv_study\\example\\1.jpg");
    if (srcImage.empty())
    {
        cout << "图像加载失败!" << endl;
        return -1;
    }
    else
        cout << "图像加载成功!" << endl << endl;
    //分割成三通道图像
    vector<Mat> channels;
    split(srcImage, channels);

    Mat gray_color;
    cvtColor(srcImage, gray_color, COLOR_RGB2GRAY);

    //设定bin数目
    int histBinNum = 255;

    //设定取值范围
    float range[] = { 0, 255 };
    const float* histRange = { range };

    bool uniform = true;
    bool accumulate = false;

    //声明三个通道的hist数组
    Mat red_hist, green_hist, blue_hist,gray_hist;

    //计算直方图
    calcHist(&channels[0], 1, 0, Mat(), red_hist, 1, &histBinNum, &histRange, uniform, accumulate);
    calcHist(&channels[1], 1, 0, Mat(), green_hist, 1, &histBinNum, &histRange, uniform, accumulate);
    calcHist(&channels[2], 1, 0, Mat(), blue_hist, 1, &histBinNum, &histRange, uniform, accumulate);
    calcHist(&gray_color, 1, 0, Mat(), gray_hist, 1, &histBinNum, &histRange, uniform, accumulate);

    //创建直方图窗口
    int hist_w = 400;
    int hist_h = 400;
    int bin_w = cvRound((double)srcImage.cols / histBinNum);

    Mat histImage(srcImage.cols, srcImage.rows, CV_8UC3, Scalar(0, 0, 0));

    //将直方图归一化到范围[0, histImage.rows]
    normalize(red_hist, red_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(green_hist, green_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(blue_hist, blue_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(gray_hist, gray_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

    //循环绘制直方图
    for (int i = 1; i < histBinNum+1; i++)
    {
        line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(red_hist.at<float>(i - 1))),
            Point(bin_w * (i), srcImage.rows - cvRound(red_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
        line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(green_hist.at<float>(i - 1))),
            Point(bin_w * (i), srcImage.rows - cvRound(green_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
        line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(blue_hist.at<float>(i - 1))),
            Point(bin_w * (i), srcImage.rows - cvRound(blue_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
        line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(blue_hist.at<float>(i - 1))),
            Point(bin_w * (i), srcImage.rows - cvRound(gray_hist.at<float>(i))), Scalar(255, 255, 255), 2, 8, 0);
    }

   /* namedWindow("原图像", WINDOW_AUTOSIZE);
    imshow("原图像", srcImage);*/

    namedWindow("图像直方图", WINDOW_AUTOSIZE);
    imshow("图像直方图", histImage);

    waitKey(0);

    return 0;
}
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/background_segm.hpp>
#include "opencv2/calib3d/calib3d.hpp"
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(int argc, char** argv) {
	cv::Mat temp_thin = cv::imread("../example/2.jpg", CV_LOAD_IMAGE_UNCHANGED);
	//cv::imshow("temp_thin",temp_thin);
	cv::Mat gray_image, dst, temp_thin_image, binary_image, edge_image;
	
	cvtColor(temp_thin, gray_image, CV_RGB2GRAY);

	GaussianBlur(gray_image, edge_image, Size(3, 3), 0, 0);
	//blur(gray, edge, Size(3, 3));
	Canny(edge_image, edge_image, 10, 150, 3, false);
	cv::imshow("edge_image", edge_image);

	std:; string anme_pic = "..\\example\\edge_image.bmp";
	cv::imwrite(anme_pic, edge_image);

	cv::waitKey(0);
	return 0;
}

4.效果

 

 

5.原理


  •  

6.参考

【1】 https://blog.csdn.net/nanguazhuo/article/details/53509695

【2】https://blog.csdn.net/wolfcsharp/article/details/85945491?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2

【3】https://blog.csdn.net/keith_bb/article/details/56680997

【4】https://blog.csdn.net/keith_bb/article/details/56680997

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大江东去浪淘尽千古风流人物

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值