2011-12-01 4 views
3

bmp (비트 맵) 파일에 DCT (이산 코사인 변환) 압축을 적용하려고합니다. 나는 터보 C++에서 실행중인 c 파일을 가지고있다. 이것은 실제로 압축하지는 않지만 DCT와 IDCT를 구현하려고했습니다. 코드는 다음과 같다 : 여기 감압은 inbetween 및 0으로 채워진 출력 파일에서 멈 춥니 다 (BLACK PIXELS)?

/* 
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

(PNG로 BMP 변환 사이트 srry 메신저 당신은 그것을 사용하는 BMP로 다시 변환 할 수 있습니다.) 다음은 생성 된 이미지 : 작성되는

Output which is incorrect

파일 college3.bmp 크기가 200x160의 93.8 킬로바이트의하지만 이미지의 분기까지입니다 그것은 계수를 정확하게 디코딩했지만 나중에 파일이 검은 색 픽셀로 채워집니다. 업로드하는 동안 유효한 bmp가 아니라고 말하면서 o/p의 스크린 샷을 찍었습니다. 나는 2004 년 2 월 이래이 문제에 앉아있다. 누가 버그가있는 곳에서 나에게 말할 수 있다면 매우 감사 할 것입니다. 출력 파일을 분석하여 픽셀이 검정색으로 시작되는 곳에서 EOF 권한을 발견했습니다. 주제에 대한 다른 질문을 읽고 전환 요소 ci, cj가 부적절하게 사용 된 것으로 나타났습니다. 코딩하는 동안 인덱스 x, y, i 및 j와도 혼동 스러웠습니다. 그래서 나는이 문제가 내가 며칠 후에 풀리길 바란다.

+1

2004 년 2 월 2 일 이래이 문제가 발생했습니다. – Ulterior

+0

[이 답변] (http://stackoverflow.com/a/8553966/968261)에서 DCT/IDCT 코드를 다시 확인할 수 있습니까? 하나의 채널 (파란색 또는 빨간색 또는 녹색 또는 흑백)에 대해 8x8 블록에서 JPEG의 DCT/IDCT를 수행합니다. –

+0

@Alex 나는 buf를 사용하여 픽셀 값을 저장하고 coeff를 계산하고 .dat 파일에 기록하기 때문에 이것이 버퍼 재사용 문제가 아니라고 확신한다. IDCT를 수행하는 동안 buf1에 coeff를 저장하고 (IDCT를 수행하고 픽셀 값을 buf1에 복사하고 마지막으로 bmp 파일에 쓰는) 파일 (.dat)에서 읽는 중입니다. 내가 틀린 것은 DCTcoeff [i] [j] [x] 대신에 outputtofile2에서 buf1 [blocknt] [y] [x] x] [y]와 buf1 [blockno] [x] [y] [0]. 왜 그렇게했는지 기억이 안납니다. 나는 이클립스에서 문제를 재현 할 수 없다. –

답변

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++에서 직접 확인해야하지만 지금은 액세스 할 수 없습니다. 나는이 질문에 대한 백업 코드를 잃어 버렸다. 질문에 게시 된 코드를 복사하고 이클립스에서 컴파일하면 compressimage 함수 내에서 파일 읽기 (fgetc)에 걸릴 수 있습니다. gcc에서 컴파일하고 실행하면 아마도 compressimage 함수 내에서 세그멘테이션 오류가 발생합니다. 사람들이이 사이트에 코드를 더럽게 게시 할 수 있는지 알고 싶습니까? 노력에 감사드립니다. 고맙습니다 –

+0

질문에서 코드를 사용하고 내가 언급 한 수정 만했습니다. 누락 된 것이 없으며 어떤 경고도받지 못했습니다 (이는 코드가 실제로 깨끗하다는 것을 의미하지는 않습니다). –

+0

그것은 jiffy에서 일했습니다 ... 정말 고마워요. –