2011-12-01 37 views
3

我想對bmp(位圖)文件應用DCT(離散餘弦變換)壓縮。我有一個C文件,我在Turbo C++中運行。這實際上並沒有壓縮,但我試圖實現DCT和IDCT。代碼如下:解壓停止在中間和輸出文件填充零(黑色像素)?

/* 
the image to be compressed is a bmp with 24 bpp and 
with name "college4.bmp" of dimensions 200*160 ie 25*20- 8*8 blocks 
o/p is college2.dat 
format: 8 bit signed integers starting rowwise from 0,0 to 8,8 
the coefficients order is blue,green,red 
for the block no 1 then 2 and soon 
*/ 

#include<stdlib.h> 
#include<stdio.h> 
#include<math.h> 
#define WIDTH 25 
#define HEIGHT 20 

typedef struct { 
    unsigned int type; 
    unsigned long int filesize; 
    unsigned int reserved1,reserved2; 
    unsigned long int offset; 
} BMPHEAD; 

typedef struct { 
    unsigned long int infosize; 
    unsigned long int width,height; 
    unsigned int planes,bitsperpixel; 
    unsigned long int compression; 
    unsigned long int sizeimage; 
    long int xpelspermeter,ypelspermeter; 
    unsigned long int colorused,colorimportant; 
} INFOHEAD; 

typedef struct { 
    char rgbquad[4]; 
} colortable; 

BMPHEAD bmphead; 
INFOHEAD infohead; 
FILE *bmp_fp1,*bmp_fp2; 
int buf[WIDTH][8][8][3],buf1[WIDTH][8][8][3]; 
float pi=3.14159265,DCTcoeff[8][8][8][8]; 

void generatedctcoeff() { 
    int y, i, j, x; 
    for (i = 0; i < 8; i++) { 
     for (j = 0; j < 8; j++) { 
      for (x = 0; x < 8; x++) { 
       for (y = 0; y < 8; y++) { 
        DCTcoeff[i][j][x][y] = cos(((2 * y + 1) * pi * j)/16) 
          * cos(((2 * x + 1) * i * pi)/16); 
       } 
      } 
     } 
    } 
} 

void outputtofile1() {      // Write into college2.dat 
    int i, j, x, y, blockno;    // One block at a time, buf contains pixel 
    int redcoef, greencoef, bluecoef;  // data of one row of blocks 
    float gijred, gijgreen, gijblue, c, ci, cj; 
    c = 1/(sqrt(2)); 
    for (blockno = 0; blockno < WIDTH; blockno++) { 
     for (i = 0; i < 8; i++) { 
      for (j = 0; j < 8; j++) { 
       gijred = 0; 
       gijgreen = 0; 
       gijblue = 0; 
       for (x = 0; x < 8; x++) { 
        for (y = 0; y < 8; y++) { 
         gijblue = gijblue + DCTcoeff[i][j][x][y] 
           * buf[blockno][x][y][0]; 
         gijgreen = gijgreen + DCTcoeff[i][j][x][y] 
           * buf[blockno][x][y][1]; 
         gijred = gijred + DCTcoeff[i][j][x][y] 
           * buf[blockno][x][y][2]; 
        } 
       } 
       ci = cj = 1.0; 
       if (i == 0) 
        ci = c; 
       if (j == 0) 
        cj = c; 
       gijblue = ci * cj * gijblue/4; 
       gijgreen = ci * cj * gijgreen/4; 
       gijred = ci * cj * gijred/4; 
       bluecoef = (int) gijblue; 
       greencoef = (int) gijgreen; 
       redcoef = (int) gijred; 
       fprintf(bmp_fp2, "%d %d %d ", bluecoef, greencoef, redcoef); 
      } 
     } 
    } /* end of one block processing */ 
} 

void compressimage() { 
    int rowcount,x,y; 
    bmp_fp1=fopen("college4.bmp","r"); 
    bmp_fp2=fopen("college2.dat","w"); 
    printf("generating coefficients...\n"); 
    generatedctcoeff(); 
    if(bmp_fp1==NULL) { 
     printf("can't open"); 
     return; 
    } 
    printf("compressing....\n"); 
    fread(&bmphead,1,sizeof(bmphead),bmp_fp1); 
    fread(&infohead,1,sizeof(infohead),bmp_fp1); 
    fseek(bmp_fp1,bmphead.offset,SEEK_SET); 
    for(rowcount=0;rowcount<HEIGHT;rowcount++) { 
     for(y=0;y<8;y++) { 
      for(x=0;x<infohead.width;x++) { 
       buf[x/8][x%8][y][0]=(int)fgetc(bmp_fp1); 
       buf[x/8][x%8][y][1]=(int)fgetc(bmp_fp1); 
       buf[x/8][x%8][y][2]=(int)fgetc(bmp_fp1); 
      } 
     } 
     outputtofile1();   //output contents of buf after dct to file 
    } 
    fclose(bmp_fp1); 
    fclose(bmp_fp2); 
} 

void outputtofile2() {         //output buf to college3.bmp 
    int i, j, x, y, blockno;      // buf now contains coefficients 
    float pxyred, pxygreen, pxyblue, c, ci, cj;  // a temp buffer buf1 used to 
    c = 1/(sqrt(2));        // store one row of block of 
    for (blockno = 0; blockno < WIDTH; blockno++) { // decoded pixel values 
     for (x = 0; x < 8; x++) 
      for (y = 0; y < 8; y++) { 
       pxyred = 0; 
       pxygreen = 0; 
       pxyblue = 0; 
       for (j = 0; j < 8; j++) { 
        cj = 1.0; 
        if (j == 0) 
         cj = c; 
        for (i = 0; i < 8; i++) { 
         ci = 1.0; 
         if (i == 0) 
          ci = c; 
         pxyblue = pxyblue + ci * cj * DCTcoeff[i][j][y][x] * buf[blockno][i][j][0]; 
         pxygreen = pxygreen + ci * cj 
         * DCTcoeff[i][j][y][x] * buf[blockno][i][j][1]; 
         pxyred = pxyred + ci * cj * DCTcoeff[i][j][y][x] * buf[blockno][i][j][2]; 
        } 
       } 
       pxyblue /= 4; 
       pxygreen /= 4; 
       pxyred /= 4; 
       buf1[blockno][y][x][0] = pxyblue; 
       buf1[blockno][y][x][1] = pxygreen; 
       buf1[blockno][y][x][2] = pxyred; 
      } 
    } 
    for (y = 0; y < 8; y++) { 
     for (blockno = 0; blockno < WIDTH; blockno++) 
      for (x = 0; x < 8; x++) { 
       fprintf(bmp_fp2, "%c%c%c", (char) buf1[blockno][x][y][0], 
         (char) buf1[blockno][x][y][1], 
         (char) buf1[blockno][x][y][2]); 
      } 
    } 
} 

void uncompressimage() { 
    int blue,green,red,rowcount,colcount,i,j; 
    bmp_fp1=fopen("college2.dat","r"); 
    bmp_fp2=fopen("college3.bmp","w"); 
    printf("generating coefficients...\n"); 
    generatedctcoeff(); 
    if (bmp_fp1==NULL) { 
     printf("open failed"); 
     return; 
    } 
    printf("uncompressing....\n"); 
    bmphead.type=0x4d42; 
    bmphead.filesize=30518; 
    bmphead.reserved1=0; 
    bmphead.reserved2=0; 
    bmphead.offset=sizeof(bmphead)+sizeof(infohead); 
    infohead.infosize=sizeof(infohead); 
    infohead.width=200; 
    infohead.height=160; 
    infohead.planes=1; 
    infohead.bitsperpixel=24; 
    infohead.compression=0; 
    infohead.sizeimage=0; 
    infohead.xpelspermeter=3780; 
    infohead.ypelspermeter=3780; 
    infohead.colorused=0; 
    infohead.colorimportant=0; 
    fwrite(&bmphead,sizeof(BMPHEAD),1,bmp_fp2); 
    fwrite(&infohead,sizeof(INFOHEAD),1,bmp_fp2); 
    for(rowcount=0;rowcount<HEIGHT;rowcount++) { 
     for(colcount=0;colcount<WIDTH;colcount++) { 
      for(i=0;i<8;i++) { 
       for(j=0;j<8;j++) { 
        fscanf(bmp_fp1,"%d",&blue); 
        fscanf(bmp_fp1,"%d",&green); 
        fscanf(bmp_fp1,"%d",&red); 
        buf[colcount][i][j][0]=blue; 
        buf[colcount][i][j][1]=green; 
        buf[colcount][i][j][2]=red; 
       } 
      } 
     } 
     outputtofile2(); 
    } 
    fclose(bmp_fp1); 
    fclose(bmp_fp2); 
} 

int main() { 
    printf("opening files...\n"); 
    compressimage(); 
    printf("opening files...again\n"); 
    uncompressimage(); 
    printf("successful decompression\nenter any key\n"); 
    return 0; 
} 

這裏是我作爲輸入圖像 Input image

(IM srry網站轉換的BMP成PNG你可以把它轉換回BMP使用它。) 這裏是生成的圖像:

Output which is incorrect

文件college3.bmp時生成的大小爲200x160和93.8 KB,但直到圖像季度它已經正確解碼了係數,但後來該文件被黑色像素填充。我截取了o/p的截圖,因爲它是在上傳時不是有效的bmp。自2004年2月以來,我一直在關注這個問題。如果有人能說我哪裏有錯誤,我會非常感激。我已經分析了輸出文件,並在像素開始變黑的地方找到了EOF。我閱讀了有關該主題的其他一些問題,發現轉換因子ci,cj已被錯誤地使用。雖然編碼我也與指數x,y,i和j混淆。所以我希望這個問題我會在幾天內解決。

+1

+1對於坐在這個問題自2004年二月以來 – Ulterior

+0

你可以仔細檢查你的DCT/IDCT代碼與[這個答案](http://stackoverflow.com/a/8553966/968261)?它爲一個通道(藍色或紅色或綠色或黑白)的8x8塊執行JPEG的DCT/IDCT。 –

+0

@Alex我相信這不是緩衝區重用問題,因爲我使用buf來保存像素值並計算coeff並寫入.dat文件。在做IDCT時,我正在從文件(.dat)中讀取buf中存儲的coeff,然後執行IDCT並將像素值複製到buf1中,最後寫入到bmp文件中。我懷疑是錯的就是我爲什麼refered到DCTcoeff [i] [j] [Y] [x]和BUF1 [塊編號] [Y] [X] [0] outputtofile2代替DCTcoeff [i] [j] [ x] [y]和buf1 [blockno] [x] [y] [0]。我不記得我爲什麼那樣做。我無法在eclipse中重新創建問題。 –

回答

1

顯然,在上面的代碼的問題是你如何打開文件。

這應該是你的代碼是什麼(請注意明確指定的開放模式,二進制和文本):

void compressimage() { 
... 
    bmp_fp1=fopen("college4.bmp","rb"); 
    bmp_fp2=fopen("college2.dat","wt"); 
... 
} 

void uncompressimage() { 
... 
    bmp_fp1=fopen("college2.dat","rt"); 
    bmp_fp2=fopen("college3.bmp","wb"); 
... 
} 

有了這一點,稍微改變結構定義:

#pragma pack(push,1) 

typedef struct { 
    unsigned short int type; 
    unsigned long int filesize; 
    unsigned short int reserved1,reserved2; 
    unsigned long int offset; 
} BMPHEAD; 

typedef struct { 
    unsigned long int infosize; 
    unsigned long int width,height; 
    unsigned short int planes,bitsperpixel; 
    unsigned long int compression; 
    unsigned long int sizeimage; 
    long int xpelspermeter,ypelspermeter; 
    unsigned long int colorused,colorimportant; 
} INFOHEAD; 

typedef struct { 
    char rgbquad[4]; 
} colortable; 

#pragma pack(pop) 

我能夠使用3種不同的編譯器(Turbo C++,Open Watcom,gcc)成功編譯程序並獲得所需的輸出圖像。

+0

我需要在Tourbo C++中自己驗證,但現在無法訪問它。我丟失了我對這個問題的備份代碼。當我複製問題中發佈的代碼並在eclipse中編譯時,它會在compressimage函數中卡住文件讀取(fgetc)。在gcc中編譯並運行它可能會在compressimage函數中出現分段錯誤。只是想知道,如果人們可以使代碼發佈在這個網站髒?我非常感謝這一努力。 Thanx –

+0

我使用了問題中的代碼,只做了我提到的那些修改。沒有什麼缺失,我甚至沒有得到任何警告(這並不意味着代碼真的很乾淨,但:)。 –

+0

它在jiffy中工作...非常感謝 –