抖動算法

抖動,是指當在低分辨率下看較高分辨率的圖像、低色模式下顯示更多色模式(如在VGA16×××形模式下顯示256色及全綵×××像)時出現的顏色和圖像變形的問題。
解決這個問題的算法就是抖動算法。下面是一篇這方面的文字,應該會對你有所幫助。

在16色模式下顯示256色及全綵色
該文描述了在VGA16×××形模式下顯示256色及全綵×××像的抖動算法,並給出了 顯示BitMap圖像的C語言程序。
   關鍵詞 抖動算法 亮度矩陣 顯示
   在編寫有關圖像顯示的軟件時,有時爲了軟件的兼容性和通用性,不得不採用VGA標準的圖形模式,這就涉及到如何在16×××形模式下顯示256色及全綵×××像的問題。解決這一問題有兩種方法。一種是採用色彩近似的方法,即根據須要顯示的所有顏色,通過尋優來選擇16種最具表明性的顏色,每一種顏色都用這16種顏色中最接近的一種來代替。《計算機世界月刊》1994年第1期的《用集羣方法進行顏色選擇》一文詳細描述了該方法。但事實上,該方法僅對於某些理想的狀況適用,而對於更廣泛的狀況,該方法不管從運算速度仍是從處理效果來說,都不可能使人感到滿意,於是不宜在實際中運用。另外一種方法是被衆多商品化軟件所普遍採用的抖動技術,其原理是利用多種可見顏色的組合來模擬一種不可見的顏色。目前,關於彩×××像抖動算法的資料很少。筆者經過對灰度圖像處理算法及Windows環境下一些圖像處理軟件的剖析,得出了抖動算法的通常原理和實現方法.
   1、抖動算法原理
   咱們知道,在256色及全綵×××像中,每一種顏色均由R、G、B三個顏色份量組成,而每個份量又通常由一個字節表示。這樣,每個顏色份量可有256級亮度變化。    本算法的關鍵在於引入亮度矩陣的概念,即採用一個16×16的矩陣來表示每個顏色份量的亮度值,不一樣亮度值對應着矩陣的不一樣排列。矩陣全爲0時對應亮度0,全爲255時對應亮度255。
   當亮度值爲L時,亮度矩陣中將有[L255×256]個255及[(1-L255)×256]個0,此時,矩陣的平均亮度值爲
   L'={[L/255×256]×255+[(1-L/255)×256]×0}/256=L
   這就是說,矩陣的平均亮度正好爲顏色份量的實際亮度。
   假設某一顏色C的R、G、B三個顏色份量的亮度矩陣分別爲: @@01A04600.GIF;公式一@@
   其中rmn、gmn、bmn(0≤m, n≤15)取值爲0或15。
   將上述三個矩陣做疊加運算,得@@01A04601.GIF;公式二@@
   其中的Cmn爲表1中由rmn、gmn、bmn所肯定的顏色值。表1爲VGA16×××形模式下的標準調色板(並不是設置模式後的缺省調色板)。顯然,Cmn只可能爲0及9~15之中的一個。由此方法獲得的矩陣Mc便可視爲顏色C的模擬矩陣。因爲顏色C的R、G、B三個顏色份量與亮度矩陣MR、MG、MB有着相等的亮度值,因此矩陣MC從視覺效果上來說能很好地模擬顏色C。但在顯示時,不可能用整個這樣的矩陣來替代一個像素點,那將致使整幅圖像長寬均變成原圖的16倍。實際的作法是:若該像素點距離圖像原點的座標爲(X,Y),則令:
   m=Y mod 16
   n=X mod 16       (1)
   此時,可用MC中的顏色Cmn來顯示該像素。 @@01A04602.GIF;表1 16×××形模式標準調色板@@
   2、算法實現
   1.亮度矩陣的表示
   算法中要用到257個16×16的亮度矩陣,若是對每個都分別表示的話,將佔用很大的內存空間(大於64K)。因爲亮度矩陣的排列及增加均有必定的規律性,咱們只須要採用一個16×16的矩陣便可。該矩陣中256個元素的取值分別爲0~255,按必定規律排列。令其爲:
@@01A04603.GIF;公式三@@
   亮度爲L時的矩陣可由H變化而來,其中@@01A04604.GIF;公式四@@
   2.顏色查找表算法中只用到了顏色0及9~15,咱們能夠忽略其餘項並將有用部分表示爲一個三維數組形式的顏色查找表,如表2所示。此時,r, g, b值做爲數組下標,取值爲0或1。與之相應,咱們將(2)式變爲@@01A04605.GIF;公式三@@
   3.每一像素的顯示步驟
   ①對256×××像,由顏色索引值查顏色映射表獲取R、G、B值;對全綵×××像,直接讀取R、G、B值;
   ②根據像素座標(X,Y),由(1)式求得m, n;
   ③根據R、G、B值,由(3)式求得rmn、gmn、bmn;
   ④由rmn、gmn、bmn查表2得顏色值C;
   ⑤將像素以顏色C顯示於(X,Y)處。
   本文所附程序用於在16×××形模式下顯示256色及全綵色BitMap圖像。
   關於BitMap圖像的格式及讀取方法,許多資料均有介紹,這裏再也不贅述。
   該程序由Turbo C 2.0及Borland C 3.1編譯,在386兼容機上運行經過。運行方法爲:   show文件名.BMP
@@01A04606.GIF;公式三表2 顏色查找表@@
   事實證實,採用本文所描述的算法,能夠獲得與許多商品化軟件類似的處理速度和處理效果。
   源程序:
   #include<stdio.h>
   #include<dos.h>
   #include<stdio.h>
   #include<conio.h>
   #define NoError 0
   #define ErrorFileOpen1
   #define ErrorFileType 2
   #define ErrorImageColor 3
   typedef struct tagBITMAPFILEHEADER {
       unsigned int   bfType;
       unsigned longbfSize;
       unsigned intbfReserved1;  unsigned intbfReserved2;
       unsigned longbfoffBits;
   } BITMAPFILEHEADER;
   typedef struct tagBITMAPINFOHEADER {
       unsigned longbiSize;
       unsigned long  biWidth;
       unsigned longbiHeight;
       unsigned intbiPlanes;
       unsigned intbiBitCount;
       unsigned long biCompression;
       unsigned long biSizeImage;
       unsigned long biXPelsPerMeter;
       unsigned long biYPelsPerMeter;
       unsigned long biClrUsed;
       unsigned long biClrImportant;
   } BITMAPINFOHEADER;
   typedef struct tagRGBQUAD {
       unsigned char rgbBlue;
       unsigned char rgbGreen;
       unsigned charrgbRed;
       unsigned char rgbReserved;
   } RGBQUAD;
   void main(int argc,char *argv[]);
   int ShowBmp(char *FileName);
   int GetColor(unsigned char R,unsigned char G, unsigned char B,int X,int Y)
;
   void SetVideoMode(unsigned char Mode);
   void SetPalReg(unsigned char *palReg);
   void SetDacReg(unsigned char *DacReg, int Color, int Count);
   void PutPixel(int X, int Y,unsigned char Color);
   unsigned char PalReg[17]= {  0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
   unsigned char StandardPal[48]= {
   0, 0, 0, 32, 0, 0, 0,32, 0, 32,32, 0,   0, 0,32, 32, 0,32, 0,32,32, 32,32,
32,  48,48,48, 63, 0, 0, 0,63, 0, 63,63, 0,   0, 0,63, 63, 0,63, 0,63,63, 63,6
3,63,};
   unsigned char LightnessMatrix [16][16]= {
   { 0,235,59,219,15,231,55,215,2,232,56,217,12,229,52,213},
   {128,64,187,123,143,79,183,119,130,66,184,120,140,76,180,116},
   {33,192,16,251,47,207,31,247,34,194,18,248,44,204,28,244},
   {161,97,144,80,175,111,159,95,162,98,146,82,172,108,156,92},
   {8,225,48,208,5,239,63,223,10,226,50,210,6,236,60,220},
   {136,72,176,112,133,69,191,127,138,74,178,114,134,70,188,124},
   {41,200,24,240,36,197,20,255,42,202,26,242,38,198,22,252},
   {169,105,152,88,164,100,148,84,170,106,154,90,166,102,150,86},
   {3,233,57,216,13,228,53,212,1,234,58,218,14,230,54,214},
   {131,67,185,121,141,77,181,117,129,65,186,122,142,78,182,118},
   {35,195,19,249,45,205,29,245,32,193,17,250,46,206,30,246},
   {163,99,147,83,173,109,157,93,160,96,145,81,174,110,158,94},
   {11,227,51,211,7,237,61,221,9,224,49,209,4,238,62,222},
   {139,75,179,115,135,71,189,125,137,73,177,113,132,68,190,126},
   {43,203,27,243,39,199,23,253,40,201,25,241,37,196,21,254},
   {171,107,155,91,167,103,151,87,168,104,153,89,165,101,149,85},
   };
   unsigned char ColorTable[2][2][2]= {
   {{0,12},{10,14}},{{9,13},{11,15}}};
   unsigned char ColorMap[256][3];
   void main (int argc, char *argv[])
   {
       if(argc!=2) {
               printf("Usage:\n\tSHOW Filename.BMP\n");
               exit(1);
       }
       ShowBmp(argv[1]);
   }
   int ShowBmp(char *FileName)
   {
       FILE *Fp;
       BITMAPFILEHEADER FileHead;
       BITMAPINFOHEADER InfoHead;
       RGBQUAD RGB;
       int N, W,Y,X,C,Color;
       unsigned char Buffer[4096];
       if (!(Fp=fopen(FileName,"rb")))
               return(ErrorFileOpen);
       fread(&FileHead,siazeof(BITMAPFILEHEADER),1,Fp);
       if(FileHead.bfType!='BM')
               return(ErrorFileType);
       fread(&InfoHead,sizeof(BITMAPFILEHEADER),1,Fp);
       if(InfoHead.biBitcount!=8 && InfoHead.biBitCount!=24) {
               fclose(Fp);
               return(ErrorImageColor);
       }
       SetVideoMode(0x12);
       SetPalReg(PalReg);
       SetDacReg(StandardPa1,0,16);
       if(InfoHead.biBitcount==8) {
               for (N=0;N<256;N++) {
                       fread(&RGB, sizeof(RGBQUAD),1,Fp);
                       ColorMap[N][0]=RGB.rgbRed;
                       ColorMap[N][1]=RGB.rgbGreen;
                       ColorMap[N][2]=RGB.rgbBlue;
               }
               W=(InfoHead.biwidth+3)/4*4;
               for(Y=InfoHead.biHeight-1;Y>=480;Y--)
                       fread(Buffer,sizeof(unsigned char),W,Fp);
               for(;Y>0;Y--) {
                       fread(Buffer, sizeof(unsigned char),w,FP);
                       for (X=0;X<InfoHead.biWidth && X<640;X++) {
                               C=Buffer[X];
                               Color=GetColor(ColorMap[C][0],ColorMap[C][1],C
olorMap[C][2],X,Y);
                               PutPixel (X,Y,color);
                       }
               }
       }
       else {
               W=(infoHead.biWidth*3+3)/4*4;
               for(Y=InfoHead.biHeight-1;Y>639;Y--)
                       fread(Buffer,sizeof(unsigned char),W,Fp);
               for(;Y>=0;Y--) {
                       fread(Buffer,sizeof(unsigned char),W,Fp);
                       for (X=0;X<InfoHead.biWidth && X<640;X++) {
                               C=X*3;
                               Color=GetColor(Buffer[C+2],Buffer[C+1],Buffer[
C],X,Y);
                               PutPixel(X,Y,color);
                       }
               }
       }
       getch();
       fclose(Fp);
       SetVideoMode(0x03);
       return(NoError);
       }
       int GetColor(unsigned char R, unsigned char G,unsigned char B, int X,
int Y){
       unsigned int L=LightnessMatrix[Y & 0x0F][X & 0x0F];
       return(colorTable[(
                       unsigned int)R*256/255>L][(
                       unsigned int)G*256/255>L][(
                       unsigned int)B*256/255>L]);}
       void SetVideoMode(unsigned char Mode){
               -H=0x00;
               -AL=Mode;
               geninterrupt(0x10);
       }
       voidSetPalReg(unsigned char *PalReg){
               -ES=FP-SEG((unsigned char far*)PalReg);
               -DX=FP-OFF((unsigned char far*)PalReg;
               -AX=0x1002;
               geninterrupt(0x10);
       }
       void SetDacReg(unsigned char *DacReg,int Color,int Count){
               -ES=FP-SEG((unsigned char far*)DacReg);
               -DX=FP-OFF((unsigned char far*)DacReg);
               -AX=0x1012;
               -BX=Color;
               -CX=Count;
               geninterrupt(0x10);
       }
       void PutPixel(int X, int Y, unsigned charColor){
               -AH=0x0C;
               -AL=Color;
               -CX=X;
               -DX=Y;
               geninterrupt(0x10);
       }
   }
算法

相關文章
相關標籤/搜索