【數字圖像處理】五.MFC圖像點運算之灰度線性變化、灰度非線性變化、閾值化和均衡化處理具體解釋


        本文主要講述基於VC++6.0 MFC圖像處理的應用知識,主要結合自己大三所學課程《數字圖像處理》及課件進行解說。主要通過MFC單文檔視圖實現顯示BMP圖片點運算處理。包含圖像灰度線性變換、灰度非線性變換、圖像閾值化處理、圖像均衡化處理等知識,並結合前一篇論文灰度直方圖進行展示 。同一時候文章比較具體基礎,希望該篇文章對你有所幫助,尤其是剛開始學習的人和學習圖像處理的學生。


       【數字圖像處理】一.MFC具體解釋顯示BMP格式圖片
       【數字圖像處理】二.MFC單文檔切割窗體顯示圖片
       【數字圖像處理】三.MFC實現圖像灰度、採樣和量化功能具體解釋
       【數字圖像處理】四.MFC對話框繪制灰度直方圖
        免費資源下載地址:
        http://download.csdn.net/detail/eastmount/8764373


一. 點運算與初始操作

        圖像的點運算是圖像處理中很基礎的技術,它主要用於改變一篇圖像的灰度分布范圍,通過一定的變換函數將圖像的像素進行轉換,終於生成一幅新的圖像。點運算的最大特點就是輸出像素值僅僅與當前輸入像素值相關。定義例如以下。
        點運算(Point Operation)指對於一幅輸入圖像,將產生一幅輸出圖像,輸出圖像的每一個像素點的灰度值由輸入像素點決定。
        點運算由灰度變換函數(Grap Scale Transformation,GST)確定:B(x,y)=F[A(x,y)]

        須要注意一下幾點:
        (1).與局部或鄰域運算的區別。輸入像素和輸出像素是一一相應的;(2).與幾何運算的區別,不改變圖像的空間關系;(3).又稱為對照增強。對照拉伸或灰度變換。


        在前面第四篇博客的基礎上添加點運算處理。


        第一步:在資源視圖中Menu中加入“圖像點運算”菜單條例如以下所看到的:


        相應的ID值為:
        線性變換 ID_DYS_XXYD(點運算 線性移動) ID_DYS_XXZQ( 點運算 線性增強)
                       ID_DYS_XXJX(點運算 線性減小)  ID_DYS_XXQB(點運算 線性求補)
        非線性變換 ID_DYS_FXXPF(點運算 非線性平方) ID_DYS_FXXHS(非線性函數)
        閾值變換 ID_DYS_YZBH(點運算 閾值變換) 圖像均衡化 ID_DYS_JHH

        第二步:打開類向導(Ctrl+W),為點運算每一個ID菜單加入對應的功能處理函數,例如以下圖所看到的:選擇類CImageProcessingView,在選擇IDs為ID_DYS_...(點運算)加入函數OnDysXxqb()線性求補。


二. 線性變換

        圖像線性變換是通過建立灰度映射來調整資源圖像的灰度。從而達到圖像增強的目的。當中GST函數f(D)為線性的。即:


        若a=1,b=0圖像像素不發生變化
        若a=1,b!=0圖像全部灰度值上移或下移
        若a>1輸出圖像對照度增強
        若0<a<1輸出圖像對照度減小
        若a<0暗區域變亮,亮區域變暗。圖像求補


        1.D(B)=D(A)+50
        首先是圖像移動。代碼例如以下:
/**********************************************************************/
/* 圖像點運算 4種線性變化直方圖:                                                
/* ID_DYS_XXYD:表示線性灰度變化移動 D(B)=D(A)+50  灰度值上移下移        
/* ID_DYS_XXZQ:表示線性灰度變化增強 D(B)=1.5*D(A) 圖像對照度增強       
/* ID_DYS_XXJX:表示線性灰度變化減小 D(B)=0.8*D(A) 圖像對照度減小       
/* ID_DYS_XXQB:表示線性灰度求補 D(B)=-1*D(A)+255  圖像暗區變亮,亮區變暗 
/**********************************************************************/

// 1.點運算 線性灰度變化移動 D(B)=D(A)+50
void CImageProcessingView::OnDysXxyd() 
{
	// TODO: Add your command handler code here
	if(numPicture==0) {
		AfxMessageBox("加載圖片后才干線性灰度運算!",MB_OK,0);
		return;
	}
	AfxMessageBox("線性灰度直方圖-灰度變化移動 D(B)=D(A)+50!",MB_OK,0);
	int i;
	//打開暫時的圖片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	//讀取文件
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	//灰度圖像
	unsigned char color;
	unsigned char red,green,blue;
	for( i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		if( (int)red+50 >255 )
			red=255;
		else
			red=(int)red+50;

		if( (int)green+50>255 )
			green=255;
		else
			green=(int)green+50;  

		if( (int)blue+50>255 )
			blue=255;
		else
			blue=(int)blue+50;

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=101;       //賦值101在ShowBitmap中調用顯示處理后的圖片
	Invalidate();
}

        同一時候改動void CImageProcessingView::ShowBitmap(CDC *pDC, 
CString BmpName)函數中的代碼:

else        //圖像點運算 線性變化
if(level=101)
{
	m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,
		LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
}
        執行效果例如以下圖所看到的。同一時候我截取了直方圖(RGB同樣僅僅顯示一種)。

        能夠發現圖像的灰度上移了50,圖像更白了(黑0-255白)。

        2.D(B)=1.5*D(A)
// 2.點運算 線性灰度變化增強 D(B)=1.5*D(A)
void CImageProcessingView::OnDysXxzq() 
{
	if(numPicture==0) {
		AfxMessageBox("加載圖片后才干線性灰度運算!",MB_OK,0);
		return;
	}
	AfxMessageBox("線性灰度直方圖-灰度變化增強 D(B)=1.5*D(A)!",MB_OK,0);
	int i;
	//打開暫時的圖片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	//灰度圖像
	unsigned char color;
	unsigned char red,green,blue;
	for( i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		if( (int)red*1.5 >255 )
			red=255;
		else
			red=(int)red*1.5;

		if( (int)green*1.5>255 )
			green=255;
		else
			green=(int)green*1.5;  
		
		if( (int)blue*1.5>255 )
			blue=255;
		else
			blue=(int)blue*1.5;

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=101;      //線性變化 ShowBitmap中調用
	Invalidate();
}
        執行效果例如以下圖所看到的,圖像對照度增強,平均灰度122*1.5=181

        3.D(B)=0.8*D(A)
// 3.點運算 線性灰度變化減小D(B)=0.8*D(A)
void CImageProcessingView::OnDysXxjx() 
{
	if(numPicture==0) {
		AfxMessageBox("加載圖片后才干線性灰度處理!",MB_OK,0);
		return;
	}
	AfxMessageBox("線性灰度直方圖-灰度減小 D(B)=0.8*D(A)!",MB_OK,0);
	int i;
	//打開暫時的圖片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	//灰度圖像
	unsigned char color;
	unsigned char red,green,blue;
	for( i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		red=(int)red*0.8;
		green=(int)green*0.8;  
		blue=(int)blue*0.8;

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=101;
	Invalidate();
}
        執行例如以下圖所看到的,圖像減弱。





        4.D(B)=-1*D(A)+255
// 4.點運算 線性灰度求補 D(B)=-1*D(A)+255
void CImageProcessingView::OnDysXxqb() 
{
	if(numPicture==0) {
		AfxMessageBox("加載圖片后才干線性灰度處理!",MB_OK,0);
		return;
	}
	AfxMessageBox("線性灰度直方圖-灰度求補 D(B)=-1*D(A)+255!",MB_OK,0);
	int i;
	//打開暫時的圖片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	//灰度圖像
	unsigned char color;
	unsigned char red,green,blue;
	for( i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		red=(int)red*(-1)+255;
		green=(int)green*(-1)+255;  
		blue=(int)blue*(-1)+255;

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=101;
	Invalidate();
}
        執行效果例如以下圖所看到的,它是圖像的求補。發現直方圖是互補的。

        PS:注意圖片以下的直方圖應該另一個處理后的直方圖,但原理都一樣,我不想反復工作,你自己能夠去簡單實現下,參考第四篇文章。

同一時候這些圖片制作還挺麻煩的,僅僅是為了給你更好的呈現它們的變化,希望對你實用和尊重作者,不喜勿噴~


三. 非線性變換

        灰度非線性變換主要包含對數變換、冪次變換、指數變換、分段函數變換,通過非線性關系對圖像進行灰度處理。以下主要解說課件中的兩個函數對其進行處理。當中對數變換實現了擴展低灰度值而壓縮高灰度值的效果,圖像灰度分布更符合而你的視覺特征。


        1.D(B)=D(A)*D(A)/252
/************************************************************************/
/* 2種非線性變化直方圖:                                                
/* ID_DYS_FXXPF:表示非線性平方灰度變化,D(B)=D(A)*D(A)/255                
/* ID_DYS_FXXHS:表示非線性函數灰度變化,D(B)=D(A)+0.8*D(A)*(255-D(A))/255 
/************************************************************************/

// 非線性平方灰度變化 D(B)=D(A)*D(A)/252
void CImageProcessingView::OnDysFxxpf() 
{
	if(numPicture==0)
	{
		AfxMessageBox("加載圖片后才干非線性灰度處理!",MB_OK,0);
		return;
	}
	AfxMessageBox("非線性灰度變化 D(B)=D(A)*D(A)/255!",MB_OK,0);
	int i;
	//打開暫時的圖片
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	//讀取文件
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	//灰度圖像
	unsigned char color;
	unsigned char red,green,blue;
	for( i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		red=(int)red*(int)red/255;
		green=(int)green*(int)green/255;
		blue=(int)blue*(int)blue/255;

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=101;
	Invalidate();
}
        執行效果例如以下圖所看到的:

        2.D(B)=D(A)+0.8*D(A)*(255-D(A))/255
// 非線性函數灰度變化 D(B)=D(A)+0.8*D(A)*(255-D(A))/255
void CImageProcessingView::OnDysFxxhs() 
{
	if(numPicture==0)
	{
		AfxMessageBox("加載圖片后才干非線性灰度處理!",MB_OK,0);
		return;
	}
	AfxMessageBox("線性灰度直方圖-灰度變化增強 D(B)=D(A)+0.8*D(A)*(255-D(A))/255!",MB_OK,0);
	int i;

	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);	
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

	unsigned char color;
	unsigned char red,green,blue;
	for( i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		if( ((int)red+0.8*(int)red*(255-(int)red)/255) > 255 )
			red=255;
		else
			red=(int)red+0.8*(int)red*(255-(int)red)/255;

		if( ((int)green+0.8*(int)green*(255-(int)green)/255) > 255 )
			green=255;
		else
			green=(int)green+0.8*(int)green*(255-(int)green)/255;  
		
		if( ((int)blue+0.8*(int)blue*(255-(int)blue)/255) > 255 )
			blue=255;
		else
			blue=(int)blue+0.8*(int)blue*(255-(int)blue)/255;

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=101;
	Invalidate();
}
        執行效果例如以下圖所看到的:


        寫到此處你會發現圖像灰度的線性變換和非線性變換是很easy的,主要是通過下面步驟完畢:
        第一步:賦值處理后圖像的BMP頭信息
            FILE *fpo = fopen(BmpName,"rb");
            FILE *fpw = fopen(BmpNameLin,"wb+");
            fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
            fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
            fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
            fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

        第二步:通過循環和線性變換或非線性便函函數處理每個像素
            for( i=0; i<m_nImage/3; i++ )
            {
                 fread(&red,sizeof(char),1,fpo);
                 處理像素RBG 如:red=(int)red*(int)red/255;
                 fwrite(&red,sizeof(char),1,fpw);
            }

         第三步:調用ShowBitmap自己定義函數並重畫圖像
            numPicture = 2;
            level=101;
            Invalidate();
       
而它的主要應用包含:光度學標定,希望數字圖像的灰度可以真實反映圖像的物理特性。對照度增強和對照度擴展;顯示標定和輪廓線確定(閾值化)。

四. 灰度閾值化

        閾值又稱為臨界值,它的目的是確定出一個范圍,然后這個范圍內的部分使用同一種方法處理,而閾值之外的部分則使用還有一種處理方法或保持原樣。經常使用的包含產生二值圖:當x<T時y=0,當x>=T時y=255(當中T是閾值)。閾值變換在生物學上的應用比較廣泛,經常使用語細胞圖像切割等。
        打開類向導(Ctrl+W)生成選擇ImageProcessingView類,IDs選擇ID_DYS_YZBH后加入對應的函數。代碼例如以下:

/**************************************************************/
/* ID_DYS_YZBH:表示點運算閾值變換 也看做灰度拉伸                   
/* 此處的拉伸是:閾值化(thresholding)能夠看作是削波的一個特例 
/* 僅僅要令削波中的g1old=g2old就實現了閾值化。                  
/* 閾值就象個門檻,比它大就是白,比它小就是黑,二值            
/**************************************************************/

void CImageProcessingView::OnDysYzbh() 
{
	if(numPicture==0)
	{
		AfxMessageBox("加載圖片后才干點運算閾值化處理!",MB_OK,0);
		return;
	}
	AfxMessageBox("圖像點運算閾值化處理!",MB_OK,0);
	//讀寫文件
	FILE *fpo = fopen(BmpName,"rb");
	FILE *fpw = fopen(BmpNameLin,"wb+");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
	//處理
	unsigned char color;
	unsigned char red,green,blue;
	for(int i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		if( (int)red > 128 )
			red=255;
		else
			red=0;

		if( (int)green > 128 )
			green=255;
		else
			green=0;  
		
		if( (int)blue > 128 )
			blue=255;
		else
			blue=0;

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpo);
	fclose(fpw);
	numPicture = 2;
	level=101;
	Invalidate();
}
        執行效果例如以下圖所看到的。感覺還挺好看的,顯然此時的直方圖就是0和255兩條直線。


五. 灰度均衡化

        灰度均衡化的目的是使一輸入圖像轉換為在每一灰度級上都有同樣的像素點(即輸出的直方圖是平的),它能夠產生一幅灰度級分布概率均衡的圖像。
        換句話說。經過均衡化后的圖像在每一級灰度上像素點的數量相差不大。相應的灰度直方圖的每一級高度也相差不大。

它是增強圖像的有效手段之中的一個。


        研究思路是通過直方圖變換公式實現:


        它的過程例如以下圖所看到的:

        例:有一幅圖象,共同擁有16級灰度,其直方圖分布為Pi, i=0,1,…,15。求經直方圖均衡化后,量化級別為10級的灰度圖象的直方圖分布Qi。當中Pi和Qi為分布的概率,即灰度i出現的次數與總的點數之比。


        Pi:0.03, 0, 0.06, 0.10, 0.20, 0.11, 0, 0, 0, 0.03, 0, 0.06, 0.10, 0.20, 0.11, 0

        步驟1:用一個數組s記錄Pi,即s[0]=0.03,s[1]=0,s[2]=0.06,…,s[14]=0.11,s[15]=0
        步驟2:i從1開始,令s[i]=s[i]+s[i-1],得到的結果是s: 0.03,  0.03, 0.09,  0.19,  0.39, 0.50,  0.50,  0.50, 0.50,  0.53,  0.53, 0.59,  0.69,  0.89, 1.0,  1.0
        步驟3:用一個數組L記錄新的調色板索引值,即令L[i]=s[i]×(10-1),得到的結果是L:0,0,1,2,4,5,5,5,5,5,5,5,6,8,9,9
        這樣就找到了原來的調色板索引值和新的調色板索引值之間的相應關系。即
        0→0,  1→0, 2→1,  3→2,  4→4, 5→5,  6→5,  7→5, 8→5,  9→5,  10→5, 11→5,  12→6,  13→8, 14→9,  15→9。
       步驟4:將老的索引值相應的概率合並,作為相應的新的索引值的概率。

比如。原來的索引值0,1都相應了新的索引值0。則灰度索引值為0的概率為P0+P1=0.03;新的索引值3和7找不到老的索引值與之相應,所以令Q3和Q7為0。最后得到的結果是Qi:0.03,  0.06, 0.10,  0,  0.20, 0.20,  0.10,  0, 0.20,  0.11 


        代碼中有具體凝視例如以下:
// ID_DYS_JHH:表示圖像均衡化 相見算法
void CImageProcessingView::OnDysJhh() 
{
	if(numPicture==0) {
		AfxMessageBox("加載圖片后才干圖像均衡化!",MB_OK,0);
		return;
	}
	AfxMessageBox("圖像均衡化!",MB_OK,0);

    //第一步:獲取圖像的數據信息
	//此操作能夠在打開圖片時就進行 在直方圖採樣(ZFTCY)中也有該代碼
	FILE *fpo = fopen(BmpName,"rb");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

	int i,j,k;
	for(j=0;j<256;j++) { //定義數組並清零
		Red[j]=0;
		Green[j]=0;
		Blue[j]=0;
	}
	
	//計算4個數據
	unsigned char red,green,blue;
	int IntRed,IntGreen,IntBlue;                  //強制轉換
	double sumRedHD=0,sumGreenHD=0,sumBlueHD=0;   //記錄像素總的灰度值和
	for(i=0; i<m_nImage/3; i++ )
	{
		fread(&red,sizeof(char),1,fpo);
		IntRed=int(red);
		sumRedHD=sumRedHD+IntRed;
		if( IntRed>=0 && IntRed<256 ) Red[IntRed]++;
		
		fread(&green,sizeof(char),1,fpo);
		IntGreen=int(green);
		sumGreenHD=sumGreenHD+IntGreen;
		if( IntGreen>=0 && IntGreen<256 ) Green[IntGreen]++;
		
		fread(&blue,sizeof(char),1,fpo);
		IntBlue=int(blue);
		sumBlueHD=sumBlueHD+IntBlue;
		if( IntBlue>=0 && IntBlue<256 ) Blue[IntBlue]++;
	}
	fclose(fpo);

	/*****************************************************************/
	/* 圖像均衡化處理                                                
	/* 利用全局變量 Red[256] Blue[256] Green[256]                    
	/* 第一步:用3個數組Count..記錄0-255灰度出現的概率,即            
	/*        概率=該灰度出現次數*3/總得像素 (由於分成3部分RGB)      
	/* 第二步:i從1開始。令s[i]=s[i]+s[i-1] 記錄新概率數              
	/* 第三步:用一個數組L記錄新的調色板索引值,即                    
	/*        L[i]=s[i]×(256-1)結果四舍五入2.8即為3                 
	/* 第四步:將老的索引值相應的概率合並,作為相應的新的索引值的概率 
	/*   1.原來的索引值0,1都相應了新的索引值0,則灰度索引值為0的概率 
	/*     為P0+P1=0.03                                              
	/*   2.新的索引值3和7找不到老的索引值與之相應。所以令Q3和Q7為0   
	/*****************************************************************/

	//記錄出現的概率,會加到1 用於相加到調色板
	float CountRed[256],CountGreen[256],CountBlue[256];      
	//記錄原始數據,不會相加到1 用於計算新灰度概率
	float CountRedLin[256],CountGreenLin[256],CountBlueLin[256];   

	for( k=0 ; k<256 ; k++ )
	{
		CountRed[k]=(float)(Red[k])*3/m_nImage;
		CountRedLin[k]=CountRed[k];
		CountGreen[k]=(float)(Green[k])*3/m_nImage;
		CountGreenLin[k]=CountGreen[k];
		CountBlue[k]=(float)(Blue[k])*3/m_nImage;
		CountBlueLin[k]=CountBlue[k];
	}
	
	for( k=1 ; k<256 ; k++ )
	{ 
		CountRed[k]=CountRed[k]+CountRed[k-1];
		CountGreen[k]=CountGreen[k]+CountGreen[k-1];
		CountBlue[k]=CountBlue[k]+CountBlue[k-1];
	}

	/****************************************************/
	/* 此處百度到一個四舍五入浮點型的算法:              
	/* float a=3.456;   保留到小數點后兩位              
	/* float b=(int)((a * 100) + 0.5) / 100.0;          
	/* output b=3.46                                    
	/****************************************************/

	int LRed[256],LGreen[256],LBlue[256];   //記錄調色板
	for( k=0 ; k<256 ; k++ )
	{
		LRed[k]=(int)(CountRed[k]*(256-1)+0.5);
		LGreen[k]=(int)(CountGreen[k]*(256-1)+0.5);
		LBlue[k]=(int)(CountBlue[k]*(256-1)+0.5);
	}

	//第三步:處理均衡化圖像寫入 打開暫時的圖片
	fpo = fopen(BmpName,"rb");
	fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
	fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

	FILE *fpw = fopen(BmpNameLin,"wb+");
	fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
	fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

	//m_nWidth*m_nHeight 讀取圖片最后一行不為m_nWidth時會報錯 改為m_nImage/3
	for( i=0; i<m_nImage/3 ; i++ )
	{	
		fread(&red,sizeof(char),1,fpo);
		fread(&green,sizeof(char),1,fpo);
		fread(&blue,sizeof(char),1,fpo);

		red=LRed[int(red)];
		green=LGreen[int(green)];
		blue=LBlue[int(blue)];

		fwrite(&red,sizeof(char),1,fpw);
		fwrite(&green,sizeof(char),1,fpw);
		fwrite(&blue,sizeof(char),1,fpw);
	}
	fclose(fpw);
	numPicture = 2;
	level=101;
	Invalidate();	
}
        執行結果例如以下圖所看到的。圖像增強並且異常清晰:


        最后介紹下圖像對照度拉伸,它就是把你感興趣的灰度范圍拉開。使得該范圍內像素,亮的更亮,暗的更暗。從而達到增強對照度的目的。
        例如以下圖所看到的,a、b、c為三段直線的斜率。g1old和g2old表示途中要進行對照度擴展的范圍,g1new和g2new表示相應的新值。當g1old=g2old就是二值圖像閾值化處理。
 
           因為灰度界別也是255這個約束,所以滿足

       當中g1old=100。g2old=150。b=3.0的執行效果例如以下所看到的:


        最后還是希望文章對你有所幫助,假設文章有不足或錯誤之處。請海涵。近期挺忙的,寫這些古老的文章有人說在浪費青春,但我還是准備把這個系列講完。很高興曾經的代碼凝視和風格都不錯,回顧起來挺好的。希望你也能養成好的代碼和凝視風格~

      (By:Eastmount 2015-06-02 下午4點   http://blog.csdn.net/eastmount/




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM