C语言实现直方图均衡化

 更新时间:2021年10月26日 08:28:43   作者:@leozhang  
这篇文章主要为大家详细介绍了C语言实现直方图均衡化,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

直方图均衡化部分是用c语言写的,最后用opencv显示原图像,处理后图像以及原图和处理后图的灰度直方图。

虽然做出来了,均衡化效果还可以,但不知道为什么处理后图像中有三条白线,真心搞不懂,有看出来问题的大神麻烦留言告诉我,谢谢。

(终于知道哪出问题了,原来是每行字节数求错了,改为LineByte=(width*8/8+3)/4*4;即可。)

下面是代码:

#include "stdafx.h"
#include<stdio.h>
#include<windows.h>
 
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\core\core.hpp>
#include<cv.h>
  
int main(void)
{
 int width;//图像宽度
 int height;//图像高度
 RGBQUAD *pColorTable;
 unsigned char *pBmpBuf,*pBmpBuf1;
 BITMAPFILEHEADER bfhead;
 BITMAPINFOHEADER bihead;
 
 FILE *fp1=fopen("e:\\picture\\dog.bmp","rb");
 if(fp1==0)
  return 0;
 fread(&bfhead,14,1,fp1);
 fread(&bihead,40,1,fp1);
 width=bihead.biWidth;
 height=bihead.biHeight;
 
 pColorTable=new RGBQUAD[256];
 fread(pColorTable,4,256,fp1);
 int LineByte=0;
 LineByte=(width*1/4+1)*4;
<span style="white-space:pre"> </span>//LineByte=(width*8/8+3)/4*4;
 pBmpBuf = new unsigned char[LineByte*height];
 
 fread(pBmpBuf,LineByte*height,1,fp1);
 fclose(fp1);
 
 pBmpBuf1=new unsigned char[LineByte*height]; //用于存储均值化后的图像数据
 //统计每个灰度级像素点的个数
 int N[256]={0};
 for(int i=0;i<height;i++)
  for(int j=0;j<width;j++)
  {
   unsigned char *pb1,*pb2;
   pb1=pBmpBuf+i*LineByte+j;
   N[*pb1]++;
   pb2=pBmpBuf1+i*LineByte+j;
   *pb2=*pb1; 
  }
 /*for(int i=0;i<256;i++ )
  printf("%d  ",N[i]);*/
 
 
  //统计最小与最大灰度值
  int minGrayValue=255;    
  int maxGrayValue=0;
 for(int i=0;i<height;i++)
  for(int j=0;j<width;j++)
  {
   unsigned char *pb;
   pb=pBmpBuf+i*LineByte+j;
   if(*pb>maxGrayValue)
    maxGrayValue=*pb;
   else if(*pb<minGrayValue)
    minGrayValue=*pb;
  }
  printf("%d ,%d\n",minGrayValue,maxGrayValue);//输出最大与最小灰度值
 
  int x=maxGrayValue-minGrayValue+1;
  float *p;
  p=new float[x];
  
  for(int i=0;i<x;i++)
  {
   *(p+i)=(float)N[i]/(float)(width*height);   //*(p+i)中存放的是灰度级为i的像素在整幅图像中出现
                                                  //的概率(即*(p+i)i=0,1,2,3...中存放的就是这幅图像归一化后的直方图) 
  }
  
  
  float *c;
  c=new float[x];      //定义c,用来存放累积的归一化直方图
  for(int i=0;i<x;i++)  //对c进行初始化
  {
   *(c+i)=0;
 
  }
 
  for(int i=0;i<x;i++)
  {
   for(int j=0;j<=i;j++)
   {
    *(c+i)+=*(p+j);
   }
  }




  for(int i=0;i<height;i++)
   for(int j=0;j<width;j++)
   {
    unsigned char *pb;
    pb=pBmpBuf1+i*LineByte+j;
    *pb=*(c+*pb)*(maxGrayValue-minGrayValue)+minGrayValue;
   }
 
  FILE *fp2=fopen("junhenghua.bmp","wb");
  fwrite(&bfhead,14,1,fp2);
  fwrite(&bihead,40,1,fp2);
  fwrite(pColorTable,4,256,fp2);
  fwrite(pBmpBuf1,LineByte*height,1,fp2);
  fclose(fp2);
  
  
//显示原图与处理后的图像
  IplImage *src1=cvLoadImage("e:\\picture\\dog.bmp");
  IplImage *src2=cvLoadImage("junhenghua.bmp");
 
  cvNamedWindow("原图");
  cvNamedWindow("处理后图");
 
  cvShowImage("原图",src1);
  cvShowImage("处理后图",src2);
 
//显示原图像与处理后图像的灰度直方图
 int size=256;
 float range[]={0,255};
 float *ranges[]={range};
 CvHistogram *hist1=cvCreateHist(1,&size, CV_HIST_ARRAY,ranges,1);//创建一维直方图,
 CvHistogram *hist2=cvCreateHist(1,&size, CV_HIST_ARRAY,ranges,1);
 IplImage* gray1=cvCreateImage(cvGetSize(src1),8,1);
 IplImage* gray2=cvCreateImage(cvGetSize(src2),8,1);
 cvCvtColor(src1,gray1,CV_BGR2GRAY); 
 cvCvtColor(src2,gray2,CV_BGR2GRAY);
 //vCvtColor(...),是Opencv里的颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像。
 //参数CV_RGB2GRAY是RGB到gray,
    //参数CV_GRAY2RGB是gray到RGB
 
 cvCalcHist(&gray1,hist1,0,0);//统计图像在[0 255]像素的均匀分布,将统计结果存在结构体中
 cvCalcHist(&gray2,hist2,0,0);
 
 //draw histogram-----
 
 //统计直方图中的最大直方块
 float histMax1=0,histMax2=0;
 cvGetMinMaxHistValue(hist1,0,&histMax1,0);     
 cvGetMinMaxHistValue(hist2,0,&histMax2,0);
 //创建一张一维直方图的“图”,横坐标为灰度级,纵坐标为像素个数  
 IplImage *grayHist1=cvCreateImage(cvSize(256*2,64*2),8,1);
 IplImage *grayHist2=cvCreateImage(cvSize(256*2,64*2),8,1);
 cvZero(grayHist1);
 cvZero(grayHist2);
 
 //分别将每个直方块的值绘制到图中  
 for(int i=0;i<255;i++)
 {
  float histValue=cvQueryHistValue_1D(hist1,i);
  float nextValue=cvQueryHistValue_1D(hist1,i+1);
 
  //计算直方块4个点的值
  CvPoint pt1=cvPoint(i*2,64*2);
  CvPoint pt2=cvPoint((i+1)*2,64*2);
  CvPoint pt3=cvPoint((i+1)*2,(64-(nextValue/histMax1)*64)*2);
  //nextValue/histMax是将i级像素点个数归一到0~1,在*64是使其高对在0~64之间
  //由于opencv图像是以左上角为坐标原点,向右为x轴,向下时y轴,而显示的直方图是向上增长的,所以用64减,将其倒过来显示
  CvPoint pt4=cvPoint(i*2,   (64-(histValue/histMax1)*64)*2);
 
  int ptNum=5;
  CvPoint pt[5];
  pt[0]=pt1;
  pt[1]=pt2;
  pt[2]=pt3;
  pt[3]=pt4;
  pt[4]=pt1;
 
        cvFillConvexPoly(grayHist1,pt,ptNum,cvScalar(255)); //填充直方块
     
 
 }
 
 for(int i=0;i<255;i++)
 {
  float histValue=cvQueryHistValue_1D(hist2,i);
  float nextValue=cvQueryHistValue_1D(hist2,i+1);
 
  //计算直方块4个点的值
  CvPoint pt1=cvPoint(i*2,64*2);
  CvPoint pt2=cvPoint((i+1)*2,64*2);
  CvPoint pt3=cvPoint((i+1)*2,(64-(nextValue/histMax2)*64)*2);
  //nextValue/histMax是将i级像素点个数归一到0~1,在*64是使其高对在0~64之间
  //由于opencv图像是以左上角为坐标原点,向右为x轴,向下时y轴,而显示的直方图是向上增长的,所以用64减,将其倒过来显示
  CvPoint pt4=cvPoint(i*2,   (64-(histValue/histMax2)*64)*2);
 
  int ptNum=5;
  CvPoint pt[5];
  pt[0]=pt1;
  pt[1]=pt2;
  pt[2]=pt3;
  pt[3]=pt4;
  pt[4]=pt1;
 
        cvFillConvexPoly(grayHist2,pt,ptNum,cvScalar(255)); //填充直方块
     
 
 }
 
 cvNamedWindow("grayHistogram1");
 cvNamedWindow("grayHistogram2");
 cvShowImage("grayHistogram1",grayHist1);
 cvShowImage("grayHistogram2",grayHist2);
 
 
  cvWaitKey(0);
 
 system("pause");
 
return 0;  
}

原图:

处理后图:

原图直方图:

均衡化后直方图:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • C++中const与#define的利弊分析

    C++中const与#define的利弊分析

    C++中不但可以用define定义常量还可以用const定义常量,下面这篇文章主要给大家分析介绍了关于C++中const与#define的利弊,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2018-05-05
  • C语言二维数组几种常用的表示方法

    C语言二维数组几种常用的表示方法

    今天小编就为大家分享一篇关于C语言二维数组几种常用的表示方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • C++实现查找二叉树中和为某一值的所有路径的示例

    C++实现查找二叉树中和为某一值的所有路径的示例

    这篇文章主要介绍了C++实现查找二叉树中和为某一值的所有路径的示例,文中的方法是根据数组生成二叉排序树并进行遍历,需要的朋友可以参考下
    2016-02-02
  • C语言实现通讯录系统

    C语言实现通讯录系统

    这篇文章主要为大家详细介绍了C语言实现通讯录系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 浅谈C++中replace()方法

    浅谈C++中replace()方法

    C++编程语言中的string应用方式多样化,每一种应用方式都能帮助我们提实现特定的功能需求。在这里我们将会为大家详细介绍一下其中一个比较重要的用法,有关C++ replace()函数的应用方式,需要的朋友可以参考下
    2015-11-11
  • C语言:代码宏详解

    C语言:代码宏详解

    这篇文章主要介绍了 C语言宏定义使用实例详解的相关资料,需要的朋友可以参考下,希望能够给你带来帮助
    2021-09-09
  • C语言多维数组数据结构的实现详解

    C语言多维数组数据结构的实现详解

    对于数组想必大家都不陌生首先得要知道的是对于数组元素在内存存储是连续性的,下面这篇文章主要给大家介绍了关于C语言多维数组数据结构的相关资料,需要的朋友可以参考下
    2021-12-12
  • C++ 中CloseHandle 函数--关闭一个句柄

    C++ 中CloseHandle 函数--关闭一个句柄

    这篇文章主要介绍了C++ 中CloseHandle 函数--关闭一个句柄的相关资料,需要的朋友可以参考下
    2017-05-05
  • C++封装IATHOOK类实例

    C++封装IATHOOK类实例

    这篇文章主要介绍了C++封装IATHOOK类的实现方法,对IAT的HOOK实例进行了封装,非常具有实用价值,需要的朋友可以参考下
    2014-10-10
  • 贪心算法的C语言实现与运用详解

    贪心算法的C语言实现与运用详解

    这篇文章主要介绍了贪心算法的C语言实现与运用详解,运用么,就是文中所附的ACM练习题,哈哈:D需要的朋友可以参考下
    2015-08-08

最新评论