目录
参数意义
1维直方图
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 )
const Mat* images:输入图像
int nimages:输入图像的个数
const int* channels:需要统计直方图的第几通道 ->(索引从0开始)
InputArray mask:掩膜,,计算掩膜内的直方图 ...Mat() ->(不使用掩膜时,输入Mat())
OutputArray hist:输出的直方图数组
int dims:需要统计直方图通道的个数
const int* histSize:指的是直方图分成多少个区间,,,就是 bin的个数 ->(将横纵坐标均分成bin份)
const float** ranges: 统计像素值得区间 ->(1维直方图代表横坐标范围,2维直方图代表横轴坐标范围)
bool uniform=true::是否对得到的直方图数组进行归一化处理
bool accumulate=false:在多个图像时,是否累计计算像素值得个数
opencv代码
void histogram_demo(Mat image)
{
std::vector bgr;
split(image, bgr);
//定义参数变量
const int channels[1] = { 0 };
const int bins[1] = { 256 }; //每个直方图的灰度范围,将横坐标均分为256份
float hranges[2] = { 0,255 }; //直方图取值范围
const float* ranges[1] = { hranges };
Mat b_hist;
Mat g_hist;
Mat r_hist; //分别存储bgr三通道的灰度值对应的像素点个数 256*1 256行1列
//计算bgr通道的直方图
calcHist(&bgr[0], 1, 0,Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
//显示直方图
int hist_w = image.cols;
int hist_h = image.rows; //直方图尺寸
int bin_w = cvRound((double)hist_w / bins[0]); //直方图横坐标均分成256份 每份的值
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
//归一化直方图数据 (范围归一化 直方图纵坐标取值范围是(0, histImage.rows))
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());
//绘制直方图曲线 图像坐标=画布高度-直方图值(范围是(0,hist_h))
for (int i = 1; i < bins[0]; i++)
{
line(histImage, Point(bin_w * (i - 1), hist_h-cvRound(b_hist.at(i-1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at(i))),
Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), hist_h-cvRound(g_hist.at(i-1))),
Point(bin_w * (i), hist_h - cvRound(g_hist.at(i))),
Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), hist_h-cvRound(r_hist.at(i-1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at(i))),
Scalar(0, 0, 255), 2, 8, 0);
}
namedWindow("histogram", WINDOW_AUTOSIZE);
imshow("histogram", histImage);
}
代码中涉及到的归一化函数:
void normalize(InputArray src,OutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )
参数意义:
src:输入数组
dst:输出数组,支持原地运算
alpha:range normalization模式的最小值,当alpha取1时代表范数归一化模式,此时beta为0。
beta:range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
normType:归一化的类型,可以有以下的取值:
NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
NORM_INF: 此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)
NORM_L1 :归一化数组的L1-范数(绝对值的和)
NORM_L2:归一化数组的(欧几里德)L2-范数
dtype:dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是 通道数相同,而tpye=CV_MAT_DEPTH(dtype).
mask:操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。
opencv代码
void histogram_2d_demo(Mat image)
{
Mat hsv, hs_hist; //hs_hist是存储h通道s通道的灰度值分布数组,2*30*32
//将图像转化为hsv空间,绘制hs通道的直方图
cvtColor(image, hsv, COLOR_BGR2HSV);
int hbins = 30, sbins = 32; //h通道范围(0,180),将其分成30份,
s通道范围(0,255),将其分成32份
int hist_bins[] = { hbins,sbins };
float h_range[] = { 0, 180 };
float s_range[] = { 0, 256 };
const float* hs_ranges[] = { h_range,s_range };
int hs_channels[] = { 0,1 };
calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);
double maxVal = 0;
minMaxLoc(hs_hist, 0, &maxVal, 0, 0);
int scale = 10;
Mat hist2d_image = Mat::zeros(sbins * scale, hbins * scale, CV_8UC3);
for (int h = 0; h < hbins; h++)
{
for (int s = 0; s < sbins; s++)
{
float binVal = hs_hist.at(h, s);
int intensity = cvRound(binVal * 255 / maxVal);
rectangle(hist2d_image,Point(h*scale, s*scale),
Point((h+1)*scale-1,(s+1)*scale-1),
Scalar::all(intensity), -1);
}
}
applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);
imshow("H-S Histogram", hist2d_image);
}