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;  
}

原圖:

處理後圖:

原圖直方圖:

均衡化後直方圖:

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: