一维直方图绘制 带纵坐标

直方图

灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像元的个数。确定图像像元的灰度值范围,以适当的灰度间隔为单位将其划分为若干等级,以横轴表示灰度级,以纵轴表示每一灰度级具有的像元数或该像元数占总像元数的比例值,做出的条形统计图即为灰度直方图。

如下图所示,做直方图的过程:

这里写图片描述

直方图的性质:

  1. 直方图反映了图像中的灰度分布规律。它描述每个灰度级具有的像元个数,但不包含这些像元在图像中的位置信息。
  2. 任何一幅特定的图像都有唯一的直方图与之对应,但不同的图像可以有相同的直方图。
  3. 如果一幅图像有两个不相连的区域组成,并且每个区域的直方图已知,则整幅图像的直方图是该两个区域的直方图之和

直方图的应用

  1. 对于每幅图像都可做出其灰度直方图。
  2. 根据直方图的形态可以大致推断图像质量的好坏。由于图像包含有大量的像元,其像元灰度值的分布应符合概率统计分布规律。假定像元的灰度值是随机分布的,那么其直方图应该是正态分布。
  3. 图像的灰度值是离散变量,因此直方图表示的是离散的概率分布。若以各灰度级的像元数占总像元数的比例值为纵坐标轴做出图像的直方图,将直方图中各条形的最高点连成一条外轮廓线,纵坐标的比例值即为某灰度级出现的概率密度,轮廓线可近似看成图像相应的连续函数的概率分布曲线

这里写图片描述

直方图均衡化

直方图均衡化是将原图像的直方图通过变换函数变为均匀的直方图,然后按均匀直方图修改原图像,从而获得一幅灰度分布均匀的新图像。

这里写图片描述

计算过程如下:

  1. 统计原图像每一灰度级的像元数和累积像元数。
  2. 按下图公式计算变换后的值
  3. 四舍五入得到新的灰度值
  4. 统计像元

接下来介绍:一维直方图绘制 带纵坐标
代码如下:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"  
#include <iostream>  
using namespace cv;
using namespace std;
 
int main()
{
	Mat srcImage = imread("C://1.bmp",0);//只读取灰度图
	if (!srcImage.data)
	{
		cout << "fail to load image" << endl;
		return 0;
	}
	imshow("原图", srcImage);
 
	MatND dstHist;//得到的直方图     
	int dims = 1;//得到的直方图的维数 灰度图的维数为1
	float hranges[2] = { 1, 255 };	//直方图统计的灰度值范围
	const float *ranges[1] = { hranges };   // 这里需要为const类型,二维数组用来指出每个区间的范围  
	int bin = 255;//直方图横坐标的区间数 即横坐标被分成多少份
	int channels = 0;//图像得通道 灰度图的通道数为0
	/* 计算图像的直方图 */ 
	calcHist(&srcImage, 1/*输入图像个数*/, &channels, Mat()/*掩码*/, dstHist, dims, &bin, ranges);	
	int height = 150;	//直方图高度
	int scale = 3;	//垂直缩放比
	int horvizon_scale = 3;	//水平缩放比
	//获取最大值和最小值  
	double minValue = 0;
	double maxValue = 0;
	minMaxLoc(dstHist, &minValue, &maxValue, 0, 0); //找到直方图中的最大值和最小值 
 
	int shift_vertical = 13;	//直方图偏移值,偏移用于显示水平坐标
	int shift_horvizon = 30;	//直方图偏移值,偏移用于显示垂直坐标
	//绘制出直方图  
	Mat dstImage(height*scale, bin*horvizon_scale + shift_horvizon, CV_8UC3, Scalar(0, 0, 0));		//创建一个彩色三通道矩阵,大小a*b,填充0
	int hpt = saturate_cast<int>((dstImage.rows - shift_vertical)*0.95); //最大值对应的Y坐标,防止溢出
	for (int i = 0; i < bin; i++)
	{
		float binValue = dstHist.at<float>(i);
		int realValue = saturate_cast<int>(binValue * hpt / maxValue);
		rectangle(dstImage, Point(i*horvizon_scale + shift_horvizon, dstImage.rows - 1 - shift_vertical), Point((i + 1)*horvizon_scale + shift_horvizon - 1, dstImage.rows - realValue - shift_vertical), Scalar(255, 255, 255), 1, 8, 0);
	}
	//绘制垂直刻度
	char string[100];
	CvFont font;
	double font_size = 1;//字体大小
	cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1, 1, 0, 1, 8);//字体结构初始化 
	Size text_size;
	for (int i = hpt; i>=0; )
	{
		_itoa(maxValue*i/hpt, string, 10);//把一个整数转换为字符串  
		//在图像中显示文本字符串  
		text_size = getTextSize(string, CV_FONT_HERSHEY_PLAIN, font_size, 1, NULL);	//获得字体大小
		putText(dstImage, string, cvPoint(0, dstImage.rows - i - shift_vertical + text_size.height/2), cv::FONT_HERSHEY_PLAIN, font_size, Scalar(0, 255, 0), 1, 8, 0);
		i -= hpt / 10;	//只显示10个刻度
	}
	//刻画水平刻度
	for (int i = bin; i >= 0;)
	{
		_itoa(i, string, 10);//把一个整数转换为字符串  
		//在图像中显示文本字符串  
		text_size = getTextSize(string, CV_FONT_HERSHEY_PLAIN, font_size, 1, NULL);	//获得字体大小
		putText(dstImage, string, cvPoint(i*horvizon_scale + shift_horvizon - text_size.width/2, dstImage.rows), cv::FONT_HERSHEY_PLAIN, font_size, Scalar(0, 0, 255), 1, 8, 0);
		i -= bin / 20;	//只显示20个刻度
	}
	//显示统计信息
	sprintf(string, "bin=%d  Ranges from %d to %d", bin, (int)hranges[0], (int)hranges[1]);
	putText(dstImage, string, cvPoint(dstImage.cols/5, 30), cv::FONT_HERSHEY_PLAIN, (double)1.3, Scalar(255, 0, 0), 1, 8, 0);
	imshow("一维直方图", dstImage);
	waitKey(0);
	return 0;

}

测试结果如下:
在这里插入图片描述

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zqx951102

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值