直方图:一种统计报告图,用于展示分布情况。在图像处理中,我们通常用直方图来描述图像的灰度或色彩分布。直方图的两个轴是:值(例如亮度或颜色)和像素数量。优点:一是对于任意一个图像区域,直方图特征的提取简单方便;其二,直方图表征图像区域的统计特征,可以有效表示多模态的特征分布,并且本身具备一定的旋转不变性。
亮度直方图以亮度值为横轴,该像素的数量为纵轴。例如,一个亮度直方图可能会显示图像中有多少像素是完全黑色的(亮度为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里面提供的计算图像直方图的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