C語言實現(xiàn)直方圖均衡化
更新時間:2021年10月26日 08:28:43 作者:@leozhang
這篇文章主要為大家詳細介紹了C語言實現(xiàn)直方圖均衡化,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
直方圖均衡化部分是用c語言寫的,最后用opencv顯示原圖像,處理后圖像以及原圖和處理后圖的灰度直方圖。
雖然做出來了,均衡化效果還可以,但不知道為什么處理后圖像中有三條白線,真心搞不懂,有看出來問題的大神麻煩留言告訴我,謝謝。
(終于知道哪出問題了,原來是每行字節(jié)數(shù)求錯了,改為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]; //用于存儲均值化后的圖像數(shù)據(jù)
//統(tǒng)計每個灰度級像素點的個數(shù)
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]);*/
//統(tǒng)計最小與最大灰度值
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的像素在整幅圖像中出現(xiàn)
//的概率(即*(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);//創(chuàng)建一維直方圖,
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里的顏色空間轉(zhuǎn)換函數(shù),可以實現(xiàn)RGB顏色向HSV,HSI等顏色空間的轉(zhuǎn)換,也可以轉(zhuǎn)換為灰度圖像。
//參數(shù)CV_RGB2GRAY是RGB到gray,
//參數(shù)CV_GRAY2RGB是gray到RGB
cvCalcHist(&gray1,hist1,0,0);//統(tǒng)計圖像在[0 255]像素的均勻分布,將統(tǒng)計結果存在結構體中
cvCalcHist(&gray2,hist2,0,0);
//draw histogram-----
//統(tǒng)計直方圖中的最大直方塊
float histMax1=0,histMax2=0;
cvGetMinMaxHistValue(hist1,0,&histMax1,0);
cvGetMinMaxHistValue(hist2,0,&histMax2,0);
//創(chuàng)建一張一維直方圖的“圖”,橫坐標為灰度級,縱坐標為像素個數(shù)
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級像素點個數(shù)歸一到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級像素點個數(shù)歸一到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;
}
原圖:

處理后圖:

原圖直方圖:

均衡化后直方圖:

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
C++數(shù)組模擬之單鏈表與雙鏈表和棧和隊列的實現(xiàn)過程
這篇文章主要介紹了C++數(shù)組模擬之單鏈表與雙鏈表和棧和隊列的實現(xiàn)過程,了解內(nèi)部原理是為了幫助我們做擴展,同時也是驗證了一個人的學習能力,如果你想讓自己的職業(yè)道路更上一層樓,這些底層的東西你是必須要會的,跟隨下文來具體了解吧2023-02-02

