图像直方图是反映图像像素分布的统计表,横坐标代表像素值的取值区间,纵坐标代表每一像素值在图像中的像素总数或者所占的百分比。 灰度直方图是图像灰度级的函数,用来描述每个灰度级在图像矩阵中的像素个数。
灰度直方图反映了图像中的灰度分布规律,直观地表现了图像中各灰度级的占比,很好地体现出图像的亮度和对比度信息:灰度图分布居中说明亮度正常,偏左说明亮度较暗,偏右表明亮度较高;狭窄陡峭表明对比度降低,宽泛平缓表明对比度较高。
根据直方图的形态可以判断图像的质量,通过调控直方图的形态可以改善图像的质量。
直方图和addWeight方法都可以改善图像亮度和对比度。
直方图比较可以判断图像的相似度。
OpenCV 提供了函数 cv2.calcHist 可以计算直方图,Numpy 中的函数 np.bincount 也可以实现同样的功能。
CV_EXPORTS 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 );
函数 cv2.calcHist 可以计算一维直方图或二维直方图,函数的参数 images, channels, histSize, ranges 在计算一维直方图时也要带 [] 号。
参数说明:
images:输入图像,用 [] 括号表示数组
channels: 直方图计算的通道,用 [] 括号表示
mask:掩模图像,一般置为 None
histSize:直方柱的数量,一般取 256
ranges:像素值的取值范围,一般为 [0,256]
返回值 hist:返回每一像素值在图像中的像素总数,形状为 (histSize,1)
注意:
1.参数 images, channels, histSize, ranges 都要带 [] 号。
2.mask 是与 images 大小相同的掩模图像,掩模为 0 的区域不作处理。不使用掩模时设为 None。
3. channels 设置对彩色图像的指定通道计算直方图,灰度图像时设为 0。
4. Numpy 中的函数 np.bincount 也可以实现同样的功能,但该函数返回值的形状为 (histSize,)
1,图像直方图概念
那么,对于我们的图像直方图统计来说,对于 RGB 彩色图,像素值的范围是0~255,那么像素等级就有256个等级,也就是bin的个数是256,当然bin的个数也可以根据需要进行设置,例如设置16个bin,那么每个bin的范围是0-15
2,统计并绘制直方图:
对与 RGB 彩色图像我们通过通道分离,对每一个图像通道进行直方图统计,并绘制统计直方图,绘制通过直线实现,其中前后两个点分别是相邻两个bin
Mat src = imread("F:/code/images/yuan_test.png");
if (src.empty()) {
printf("fail to read");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
//通道分离
vector<Mat> mv;
split(src, mv);
//直方图计算
//设定像素取值范围
int histSize = 256;//像素等级数,也就是bin的个数
float range[] = { 0,255 };//需要统计的像素值范围
const float* histRanges = { range };
//三个通道分别计算直方图
Mat b_hist, g_hist, r_hist;//统计后输出的 Mat
calcHist(&mv[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
calcHist(&mv[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
calcHist(&mv[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);
//创建直方图画布并归一化处理
Mat histImage = Mat::zeros(Size(600, 400), CV_8UC3);
int margin = 50;
int nm = histImage.rows - 2*margin;//像素直方图统计值显示的最大值
float bh = (float)(histImage.cols - 2*margin) / (float)histSize;//每个 bin 的宽度
normalize(b_hist, b_hist, 0, nm, NORM_MINMAX, -1, Mat());//使用最小值和最大值进行归一化处理,最小值是0,最大值是nm
normalize(g_hist, g_hist, 0, nm, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, nm, NORM_MINMAX, -1, Mat());
//绘制前后两个统计点
for (int i = 0; i < histSize - 1; i++) {
line(histImage, Point( i * bh + margin, nm - b_hist.at<float>(i) + margin ),
Point((i + 2) * bh + margin, nm - b_hist.at<float>(i+1) + margin), Scalar(255,0,0), 1, LINE_AA);
line(histImage, Point(i * bh + margin, nm - g_hist.at<float>(i) + margin),
Point((i + 2) * bh + margin, nm - g_hist.at<float>(i + 1) + margin), Scalar(0, 255, 0), 1, LINE_AA);
line(histImage, Point(i * bh + margin, nm - r_hist.at<float>(i) + margin),
Point((i + 2) * bh + margin, nm - r_hist.at<float>(i + 1) + margin), Scalar(0, 0, 255), 1, LINE_AA);
}
namedWindow("histImage", WINDOW_AUTOSIZE);
imshow("histImage", histImage);
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/182017.html