直方图、直方图均衡化的计算和显示——数字图像处理学习二(C++版)

1、直方图计算

灰度图如上所示,灰度范围为0-3,则

共4*4=16个像素 灰度范围i=[0,3]

灰度0:V0=3/16

灰度1:V1=5/16

灰度2:V2=4/16

灰度3:V3=4/16

直方图为:

2、RGB直方图

与灰度图直方图同理,分别计算每个像素三个分量RGB的256个灰度值,可以绘制成3个直方图

例子:显示2.bmp的rgb直方图

void MyFrame::OnPaint()
{
	CPaintDC dc(this);
	FILE* fp;
	if (fopen_s(&fp, "2.bmp", "rb") != 0) 
    {
			return;
	}
	bmpFileHeader bfHead;
	bmpInfoHeader biHead;
	fread_s(&bfHead, 14, 14, 1, fp);
	fread_s(&biHead, 40, 40, 1, fp);
	unsigned char* p = (unsigned char*)malloc(biHead.biSizeImage * sizeof(unsigned char));
	fseek(fp, bfHead.bfOffBits, SEEK_SET);
	fread_s(p, biHead.biSizeImage * sizeof(unsigned char), biHead.biSizeImage * sizeof(unsigned char), 1, fp);

    //rgb直方图
	unsigned int* Rhists,* Ghists,* Bhists;
	Rhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
	Ghists = (unsigned int*)malloc(256 * sizeof(unsigned int));
	Bhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
	memset(Rhists, 0x0, 256 * sizeof(unsigned int));
	memset(Ghists, 0x0, 256 * sizeof(unsigned int));
	memset(Bhists, 0x0, 256 * sizeof(unsigned int));
	unsigned long x = 0;
	for (int i = 0; i < biHead.biHeight; i++) 
	{
		for (int j = 0; j < biHead.biWidth; j++) 
		{
			Rhists[p[x + 2]]++;
			Ghists[p[x + 1]]++;
			Bhists[p[x]]++;
			x += 3;
		}
	}

	//绘制R直方图坐标轴
	dc.MoveTo(10, 500);
	dc.LineTo(310, 500);
	dc.MoveTo(10, 500);
	dc.LineTo(10, 0);
	//绘制R直方图
	for (int j = 0; j < 256; j++)
	{
		dc.MoveTo(20 + j, 500);
		dc.LineTo(20 + j, 500 - Rhists[j] / 100);
	}

	//绘制G直方图坐标轴
	dc.MoveTo(320, 500);
	dc.LineTo(620, 500);
	dc.MoveTo(320, 500);
	dc.LineTo(320, 0);
	//绘制G直方图
	for (int j = 0; j < 256; j++)
	{
		dc.MoveTo(330 + j, 500);
		dc.LineTo(330 + j, 500 - Ghists[j] / 100);
	}

	//绘制B直方图坐标轴
	dc.MoveTo(630, 500);
	dc.LineTo(930, 500);
	dc.MoveTo(630, 500);
	dc.LineTo(630, 0);
	//绘制B直方图
	for (int j = 0; j < 256; j++)
	{
		dc.MoveTo(640 + j, 500);
		dc.LineTo(640 + j, 500 - Bhists[j] / 100);
	}
}

结果:

3、直方图均衡化

首先通过一个例子来人工进行直方图均衡化:

仍然是这幅图片,共0-3四个灰度级

第一步:统计每个灰度级像素点个数             V[0-3]={3,5,4,4}

第二步:统计灰度频率       V[0-3]={3/16,5/16,4/16,4/16}

第三步:计算累计密度        V[0-3]={3/16,8/16,12/16,16/16}

第四步:均衡化     

                V0=3/16*(灰度级个数-1)=3/16*3≈1(四舍五入)

                V1=8/16*(灰度级个数-1)=8/16*3≈2(四舍五入)

                V2=12/16*(灰度级个数-1)=12/16*3≈2(四舍五入)

                V3=16/16*(灰度级个数-1)=16/16*3≈3(四舍五入)

第五步:则0对应灰度级1,1对应灰度级2,2对应灰度级2,3对应灰度级3

代码实现(RGB图

void hist()
{
  CPaintDC dc(this);
  FILE* fp1;
  if (fopen_s(&fp1, "C:\\Users\\Administrator\\Desktop\\BMP1\\BMP1\\1.bmp", "rb") != 0) 
  {
    return;
  }
  bmpFileHeader bfHead1;
  bmpInfoHeader biHead1;
  fread_s(&bfHead1, 14, 14, 1, fp1);
  fread_s(&biHead1, 40, 40, 1, fp1);
  uchar* p1 = (uchar*)malloc(biHead1.biSizeImage * sizeof(uchar));
  fseek(fp1, bfHead1.bfOffBits, SEEK_SET);
  fread_s(p1, biHead1.biSizeImage * sizeof(uchar), biHead1.biSizeImage * sizeof(uchar), 1, fp1);

  //统计每个分量下的像素个数
  unsigned int* Rhists, * Ghists, * Bhists;
  Rhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
  Ghists = (unsigned int*)malloc(256 * sizeof(unsigned int));
  Bhists = (unsigned int*)malloc(256 * sizeof(unsigned int));
  memset(Rhists, 0x0, 256 * sizeof(unsigned int));
  memset(Ghists, 0x0, 256 * sizeof(unsigned int));
  memset(Bhists, 0x0, 256 * sizeof(unsigned int));
  unsigned long x = 0;
  for (int i = 0; i < biHead1.biHeight; i++)
  {
    for (int j = 0; j < biHead1.biWidth; j++)
    {
      Rhists[p1[x + 2]]++;
      Ghists[p1[x + 1]]++;
      Bhists[p1[x]]++;
      x += 3;
    }
  }
  //统计灰度频率
  double Rhists_prob[256] = { 0 };
  double Ghists_prob[256] = { 0 };
  double Bhists_prob[256] = { 0 };
  for (int i = 0; i < 256; i++)
  {
    Rhists_prob[i] = (double)Rhists[i] / (biHead1.biHeight * biHead1.biWidth);
    Ghists_prob[i] = (double)Ghists[i] / (biHead1.biHeight * biHead1.biWidth);
    Bhists_prob[i] = (double)Bhists[i] / (biHead1.biHeight * biHead1.biWidth);
  }
  //计算累计密度
  double Rhists_distribution[256] = { 0 };
  double Ghists_distribution[256] = { 0 };
  double Bhists_distribution[256] = { 0 };
  Rhists_distribution[0] = Rhists_prob[0];
  Ghists_distribution[0] = Ghists_prob[0];
  Bhists_distribution[0] = Bhists_prob[0];
  for (int i = 1; i < 256; i++)
  {
    Rhists_distribution[i] = Rhists_distribution[i - 1] + Rhists_prob[i];
    Ghists_distribution[i] = Ghists_distribution[i - 1] + Ghists_prob[i];
    Bhists_distribution[i] = Bhists_distribution[i - 1] + Bhists_prob[i];
  }
  //重新计算均衡化后的灰度值,四舍五入。参考公式:(N-1)*T+0.5
  int Rhists_equal[256] = { 0 };
  int Ghists_equal[256] = { 0 };
  int Bhists_equal[256] = { 0 };
  for (int i = 0; i < 256; i++)
  {
    Rhists_equal[i] = (unsigned char)(255 * Rhists_distribution[i] + 0.5);
    Ghists_equal[i] = (unsigned char)(255 * Ghists_distribution[i] + 0.5);
    Bhists_equal[i] = (unsigned char)(255 * Bhists_distribution[i] + 0.5);
  }
  //展示直方图均衡化后的图片
  x = 0;
  for (int i = 0; i < biHead1.biHeight; i++) 
  {
    for (int j = 0; j < biHead1.biWidth; j++) 
    {
      dc.SetPixel(j, (biHead1.biHeight - i), RGB(Rhists_equal[p1[x + 2]], Ghists_equal[p1[x + 1]], Bhists_equal[p1[x]]));
      x += 3;
    }
  }
    
  //重新统计每个分量下的像素个数
  unsigned int* Rhistsnew, * Ghistsnew, * Bhistsnew;
  Rhistsnew = (unsigned int*)malloc(256 * sizeof(unsigned int));
  Ghistsnew = (unsigned int*)malloc(256 * sizeof(unsigned int));
  Bhistsnew = (unsigned int*)malloc(256 * sizeof(unsigned int));
  memset(Rhistsnew, 0x0, 256 * sizeof(unsigned int));
  memset(Ghistsnew, 0x0, 256 * sizeof(unsigned int));
  memset(Bhistsnew, 0x0, 256 * sizeof(unsigned int));
  x = 0;
  for (int i = 0; i < biHead1.biHeight; i++)
  {
    for (int j = 0; j < biHead1.biWidth; j++)
    {
      Rhistsnew[Rhists_equal[p1[x + 2]]]++;
      Ghistsnew[Ghists_equal[p1[x + 1]]]++;
      Bhistsnew[Bhists_equal[p1[x]]]++;
      x += 3;
    }
  }
  //绘制R分量直方图
  //绘制R直方图坐标轴
  dc.MoveTo(10, 500);
  dc.LineTo(310, 500);
  dc.MoveTo(10, 500);
  dc.LineTo(10, 0);
  //绘制R直方图
  for (int j = 0; j < 256; j++)
  {
  dc.MoveTo(20 + j, 500);
  dc.LineTo(20 + j, 500 - Rhistsnew[j] / 100);
  }
}

左原图,右均衡化后图:

均衡化后直方图:

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值