颜色直方图

前言

直方图:一种统计报告图,用于展示分布情况。在图像处理中,我们通常用直方图来描述图像的灰度或色彩分布。直方图的两个轴是:值(例如亮度或颜色)和像素数量。优点:一是对于任意一个图像区域,直方图特征的提取简单方便;其二,直方图表征图像区域的统计特征,可以有效表示多模态的特征分布,并且本身具备一定的旋转不变性。

亮度直方图以亮度值为横轴,该像素的数量为纵轴。例如,一个亮度直方图可能会显示图像中有多少像素是完全黑色的(亮度为0),有多少像素是完全白色的(亮度为255,如果你用一个8位的值来描述亮度的话),等等。

颜色直方图类似,但更复杂一些,因为色彩有多个维度(例如,红色、绿色和蓝色以RGB, 或者色调、饱和度和亮度以HSV)。 颜色特征:描述了图像或图像区域所对应的景物的表面性质。一般颜色特征是基于像素点的特征,此时所有图像或图像区域的像素都有各自的贡献。。一个颜色直方图可能会有一个单独的直方图来描述每个维度,或者可能会有一个三维直方图来同时描述所有的维度。

RGB和HSV是两种常见的色彩空间,它们表示颜色的方式不同,各有其特定的应用场景。

RGB色彩空间: RGB是一种基于硬件的颜色模型,广泛应用在显示器,电视,手机屏幕等电子设备中。在RGB模型中,颜色是由红(Red)、绿(Green)、蓝(Blue)三种基础色以不同的比例组合而成。值范围通常是0-255,当三种颜色的分量都为0时表示黑色,都为255时表示白色。

HSV色彩空间: HSV则是更接近人类对颜色认知的一种色彩模型,HSV分别代表色调(Hue), 饱和度(Saturation), 明度(Value)。在HSV模型中,色调用角度值表示(一般是在0 ~ 360之间),饱和度和明度则用0~100的百分比表示。HSV的优势是能更直观地表达人对颜色的感知,因此在图像编辑和分析中广泛使用。

基于opencv的颜色直方图实现

OpenCV里面提供的计算图像直方图的API函数calcHist,用法:

void calcHist(const Mat* arrays,    // 源输入(图像)数组,必须是深度和大小均相同的CV_8U或者CV_32F;
              int narrays, 	// 源输入数组中的图片个数; 
              const int* channels, 	// 用来计算直方图的通道维数的数组,第一张图片的通道由0到arrays[0].channels()-1列出,第二张图片的通道从arrays[0].channels()到arrays[0].channels()+arrays[1].channels()-1
              InputArray mask,	// 可选的掩模,如果该矩阵不是空的,则必须是8位的并且与arrays[i]的大小相等
              OutputArray hist, 	// 输出直方图,是一个稠密或者稀疏的dims维的数组
              int dims, 	// 直方图的维数,必须为正,并且不大于CV_MAX_DIMS
              const int* histSize, 	// 用于指出直方图数组每一维的大小的数组,即指出每一维的bin的个数的数组; 
              const float** ranges, 	// 用于指出直方图每一维的每个bin的上下界范围(数组)的数组,当直方图是均匀的(uniform =true)时,对每一维i指定直方图的第0个bin的下界和最后一个即第histSize[i]-1个bin的上界,也就是说对均匀直方图来说,每一个ranges[i]都是一个两个元素的数组【指出该维的上下界】。当直方图不是均匀的时,每一个ranges[i]数组都包含histSize[i]+1个元素; 
              bool uniform=true, 	// 直方图是否均匀的标志
              bool accumulate=false 	// 累加标志
              )

代码实战

在OpenCV中,如果你想要计算的是在HSV色彩空间中的图像的直方图,你可以按照如下的方式进行操作:

#include 

int main()
{
    // 载入图像
    cv::Mat src = cv::imread("path/to/your/image.jpg");

    if(src.empty())
    {
        std::cout << "Error : Image cannot be loaded..!!" << std::endl;
        return -1;
    }

    // 将图像从BGR色彩空间转换到HSV色彩空间
    cv::Mat hsv;
    cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV);

    // 设置直方图的参数
    int hBins = 180, sBins = 256; // H通道180个bins,S通道256个bins
    int histSize[] = {hBins, sBins};
    // hue varies from 0 to 179, saturation from 0 to 255
    float hRanges[] = {0, 180}; // H的取值范围是[0, 180)
    float sRanges[] = {0, 256}; // S的取值范围是[0, 256)
    const float* ranges[] = {hRanges, sRanges};
    int channels[] = {0, 1}; // H和S通道

    // 计算直方图
    cv::Mat hist;
    cv::calcHist(&hsv, 1, channels, cv::Mat(), hist, 2, histSize, ranges, true, false);

    return 0;
}

在上述代码中,首先从BGR色彩空间将图片转换到HSV色彩空间。然后,我们定义了计算直方图需要的参数。注意到这里我们只考虑了H和S两个通道,忽略了V通道。为什么可以忽略V(亮度)通道?因为在许多应用中,我们并不关心颜色的亮度,色调和饱和度的组合通常已经足够反应颜色的识别。然后我们调用cv::calcHist方法来计算直方图。注意这里的直方图是二维的(H和S),它的每个bin代表特定色调和饱和度的颜色在图像中出现的频率。

在OpenCV中,如果你想要计算的是在RGB色彩空间中的图像的直方图,你可以按照如下的方式进行操作:

#include 

int main()
{
    cv::Mat src = cv::imread("path/to/your/image.jpg");
    if(src.empty())
    {
        std::cout << "Error : Image cannot be loaded..!!" << std::endl;
        return -1;
    }

    // 设置直方图的参数
    int histSize[] = {256, 256, 256}; // 对于每一个通道,使用256个bins
    float range[] = {0, 256} ; // 像素强度的范围是[0, 256)
    const float* ranges[] = { range, range, range }; // 范围一致
    int channels[] = {0, 1, 2}; // 三个通道

    // 计算直方图,需要注意,此处产生的hist将会是一个三维的cv::Mat
    cv::Mat hist;
    cv::calcHist(&src, 1, channels, cv::Mat(), hist, 3, histSize, ranges,
                 true, // 直方图是均匀的
                 false); // 压累累加  

    return 0;
}

在上述代码,calcHist函数的参数被设置为创建一个均匀,非累积的三维直方图hist。每一个独立的颜色通道被独立处理,并且它们的bins的数量和范围都是一样的,都是从0到255。地址传给cv::calcHist函数的channels数组中的数值表示将会处理的通道的索引。对于一个彩色图像,0, 1, 2 分别代表 B,G,R。非累积的参数false意味着每个像素将会只在它各自的bin中被计数,而不是在所有更暗的bin中的计数。最后的结果将会是一个三维的数组,其中每一个元素对应一个特定的像素强度的组合的出现频率。

参考链接:https://blog.csdn.net/zhu_hongji/article/details/80443585

你可能感兴趣的:(重识别,颜色直方图,opencv)