图像直方图的解释
图像直方图是图像像素值的统计学特征,计算代价小,具有图像平移,旋转,缩放不变性的众多优点,广泛的应用于图像处理的各个领域,特别是灰度图像的阈值风格,基于颜色的图像检索以及图像分类,反向投影跟踪,常见的分文
-灰度直方图
-颜色直方图
Bins是指直方图的大小范围,对于像素值取值在0-255之间的,最少有256个bin,此外还有16,32,48,128除以bin的大小的整数倍
Opencv中的相关API
calHist(&bgr------plane[0],1,0,Mat(),bin_hist,1,bins,ranges);
cv.calcHist([image],[i],None,[256],[0,256])
(两个相同的直方图图像不一定为同一个图像,缺少对于空间向量的信息,只是图像的特征值)
思路
1. 首先通过split函数将输入图像分离成三个通道,存储在bgr_plane中。
2. 接着定义了计算直方图所需的参数,包括通道索引channels、区间数量bins和取值范围ranges。
3. 然后分别对蓝色、绿色和红色通道调用calcHist函数计算直方图,结果存储在b_hist、g_hist和r_hist中。
4. 之后对直方图数据进行归一化处理,并使用line函数在histImage上绘制直方图曲线。
5. 最后创建窗口并显示包含直方图的图像histImage。
LINE
在 OpenCV 中,line函数用于在图像上绘制一条直线段。
其函数原型为:
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
各个参数的作用如下:
• img:要在其上绘制直线的图像。
• pt1:直线的起点坐标,类型为Point,通常由两个整数(x 和 y 坐标)组成。
• pt2:直线的终点坐标,类型也为Point。
• color:直线的颜色,以Scalar对象表示,在 BGR 颜色空间中,例如Scalar(255, 0, 0)表示蓝色。
• thickness:直线的宽度(以像素为单位),默认值为 1。
• lineType:线条的类型,可以是LINE_4(4 连接的线条)、LINE_8(8 连接的线条)或LINE_AA(抗锯齿线条)等,默认值为LINE_8。
• shift:坐标点的小数位数的位数,默认值为 0。
通过这个函数,可以在图像上绘制各种直线,用于标记、装饰或可视化特定的图形特征。
POINT
在 OpenCV 中,Point类用于表示二维坐标系中的一个点。
它通常作为参数在很多函数中使用,比如在图形绘制函数(如line、rectangle、circle等)中指定起点、终点、中心等位置坐标。
例如,在line(img, Point(x1,y1), Point(x2,y2), color, thickness);中,Point(x1,y1)和Point(x2,y2)分别代表直线的起点和终点坐标。
Point类使得在 OpenCV 中处理图像上的特定位置变得更加方便和直观。它提供了一些基本的操作,如访问点的坐标值、进行坐标的加法和减法等。
void QUickdemo::histogram_demo(Mat& image)
{
//三通道分离
std::vector<Mat>bgr_plane;--声明了一个名为 bgr_plane 的 std::vector容器,容器中的元素类型是 cv::Mat(OpenCV 中的矩阵类型)。
这个容器通常用于存储图像的不同颜色通道(Blue、Green、Red)。例如,在图像处理中,可以使用 split 函数将一个彩色图像分离成三个通道,然后将这些通道存储在这个 vector 中,以便后续对每个通道进行单独的处理。
具体来说,这个容器可以动态地调整大小,方便存储不同数量的图像通道。它提供了一些方便的方法,如 push_back(添加元素)、size(获取元素数量)、operator[](通过索引访问元素)等,使得对图像通道的管理更加灵活和方便。
split(image, bgr_plane);--1. 三通道分离:使用 split 函数将输入图像 image 分离成三个通道,存储在 bgr_plane 向量中。
//定义直方图所需要的参数,通道索引,区间数量和取值范围
-
const int channels[1] = { 0 };:这里定义了一个常量整数数组channels,其值被初始化为包含一个元素0,表示后续计算直方图时针对的通道索引为 0,即蓝色通道,这个数组的值在定义后不能被修改。
-
const int bins[2] = { 256 };:定义了一个常量整数数组bins,初始化为包含两个元素,其中第一个元素值为 256,表示直方图的区间数量为 256,这个数组的值在定义后不能被修改。
-
float hranges[2] = { 0,255 };:这里虽然没有用const修饰,但如果加上const,表示这个数组存储的直方图取值范围0和255在定义后不能被修改。
-
const float* ranges[1] = { hranges };:定义了一个指向常量float类型的指针数组ranges,初始化为指向hranges数组,意味着这个指针数组指向的内容不能通过这个指针被修改。
const int channels[1] = { 0 }; --channels[1]指定要计算直方图的通道索引,这里为 0,表示第一个通道(蓝色通道)。
const int bins[2] = { 256 };--指定直方图的区间数量为 256。
float hranges[2] = { 0,255 };--直方图的区间取值范围为 256
const float* ranges[1] = { hranges };--直方图取值范围0和255
Mat b_hist;
Mat g_hist;
Mat r_hist;
//计算blue,red,green的直方图
calcHist是 OpenCV 中用于计算图像直方图的函数。
其函数原型如下:
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 );
以下是各个参数的说明:
• const Mat* images:输入图像的数组,可以是单个图像或多个图像的数组。
• int nimages:输入图像的数量。
• const int* channels:需要计算直方图的通道索引数组。例如,对于彩色图像,如果要计算蓝色通道的直方图,可以传入0。如果要同时计算蓝色、绿色和红色通道的直方图,可以传入{0,1,2}。
• InputArray mask:可选的掩码图像,如果提供了掩码图像,只有掩码图像中对应位置为非零值的像素才会被用于计算直方图。
• OutputArray hist:输出的直方图数组。
• int dims:直方图的维度。对于单通道图像,维度为 1;对于多通道图像,维度等于通道数。
• const int* histSize:每个维度的直方图区间数量数组。例如,对于单通道图像,如果要将像素值范围分为 256 个区间,可以传入256。
• const float** ranges:每个维度的取值范围数组。例如,对于单通道图像
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
• &bgr_plane[0]:这通常是指向图像数据的指针。假设bgr_plane是存储图像数据的数组,这里取其首地址作为输入图像数据源。
• 1:表示要计算直方图的图像数量为 1。
• 0:指定要计算直方图的通道索引。这里表示对第一个通道进行计算。
• Mat():通常是用作掩码,如果传入一个空的Mat对象,则表示不对图像进行掩码处理,即计算整个图像的直方图。
• b_hist:用于存储计算得到的直方图结果的对象。
• 1:表示直方图的维度为 1。
• bins:在这里是一个整数数组,如前面提到的int bins[2]={257},指定了直方图的区间数量等参数。
• ranges:通常是一个数组,指定了每个维度的取值范围,比如前面提到的float hranges[2]={0,255}可能作为取值范围参数传入。
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
//显示直方图(512,400尺寸优化)
int hist_w = 512;
int hist_h = 400;
int bin_w = cvRound((double)hist_w / bins[0]);
cvRound((double)hist_w / bins[0])这部分的作用是将hist_w除以bins[0(
在图像处理等相关场景中,hist_w除以bins[0]通常有以下作用:
假设 hist_w 代表直方图的总宽度,而 bins[0] 代表直方图的区间数量。
将总宽度除以区间数量可以得到每个区间在横坐标上所占据的宽度。这样可以确定在绘制直方图或者进行其他与直方图相关的操作时,每个区间在图形上的具体尺寸,以便准确地将数据分布展示在一定的宽度范围内,帮助直观地理解数据在不同区间的分布情况。
)]的结果进行四舍五入取整。
首先,将hist_w强制转换为双精度浮点数(double)hist_w,然后除以bins[0],这个除法运算可能得到一个浮点数结果。接着使用cvRound函数对这个浮点数结果进行四舍五入取整操作,得到一个整数结果。
最后,将这个取整后的结果赋值给变量bin_w。这个变量可能代表着某种与直方图宽度和区间数量相关的步长或者尺寸参数。
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
//归一直方图数据
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
• b_hist:这是输入的直方图数据,同时也是输出经过归一化后的直方图数据。即这个函数会直接修改b_hist中的值。
• 0和histImage.rows:分别指定了归一化的范围下限和上限。在这里,下限为 0,上限为histImage图像的行数。这意味着归一化后的值将被映射到这个范围内。
• NORM_MINMAX:指定了归一化的类型为将数据映射到指定的最小-最大范围。在这种情况下,将输入数据根据给定的范围进行线性映射,使得最小值映射到 0,最大值映射到histImage.rows。
• -1:这个参数通常用于指定数据的深度(数据类型)。在这里,-1 表示与输入数据相同的深度。
• Mat():通常是用作掩码参数,如果传入一个空的Mat对象,则表示不对数据进行掩码处理,即对整个输入数据进行归一化操作。
总体来说,这个函数调用的作用是对输入的直方图数据b_hist进行归一化处理,将其值映射到 0 到histImage.rows这个范围内,以便更好地进行后续的可视化或其他处理。
normalize(g_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(r_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
//绘制直方图曲线
for (int i = 1; i < bins[0]; i++) {
for (int i = 1; i < bins[0]; i++) {
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
}
• for (int i = 1; i < bins[0]; i++):这是一个循环,从 i = 1 开始,一直循环到 i 小于 bins[0]。bins[0] 代表直方图的区间数量等含义。这个循环遍历直方图的各个区间。
• line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))), Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0):
• histImage:是要在其上绘制线条的图像。
• Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))):表示线条的起点坐标。其中 bin_w * (i - 1) 确定了横坐标位置,它是根据区间宽度 bin_w 和当前区间索引 i 计算得到的。hist_h - cvRound(b_hist.at<float>(i - 1)) 确定了纵坐标位置,hist_h 是图像的高度,减去对直方图数据 b_hist 中对应区间的值进行处理后的结果(通过 cvRound 四舍五入取整)。
• Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))):表示线条的终点坐标,计算方式与起点类似,只是索引变为 i。
• Scalar(255, 0, 0):指定线条的颜色为蓝色(BGR 颜色空间中,255 表示蓝色通道的值最大,红色和绿色通道的值为 0)。
• 2:表示线条的宽度为 2 个像素。
• 8:表示连接类型为 8 连接。
• 0:表示位移参数,通常为 0。
总体来说,这段代码的作用是在图像 histImage 上绘制一系列线段,以可视化直方图数据 b_hist,每个线段代表直方图的一个区间,线段的长度和位置根据直方图的值和图像的尺寸等参数确定,颜色为蓝色,线条宽度为 2,连接类型为 8 连接。
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
}
namedWindow("Histogram_demo", WINDOW_AUTOSIZE);
imshow("Histogram_demo", histImage);
}