我的代码结果不正确,我想实现的就是在只有一个Y向量的情况下解压出图片出来,因为这样比较简单。虽然我基本上都测试了一下各个函数,都是正如我所期望的结果,但结果还是不正确,未知错误原因,希望高手赐教。 //前面查文件头的部分比较简单,我也已经验证过了,所以这里不多说 find(addDC0,Y[0],&num);//num先为0,经过此步读取DC的值之后为1 while(num!=64) find(addAC0,Y[0],&num);//当读取完63的AC之后跳出,详 ///细的介绍在后面 quant(Y[0],0); zigzag(Y[0],B);//zigzag编码 Toggle(Y[0]);//隔行正负矫正 IDCT(B,Y[0]);//反离散余弦变换 for(unsigned char b=0;b<63;b++) Y[0][b>>3][b%8]+=128;//据说需要把所 //有的都加上128 //如此计算一共四个矩阵,即把上面的Y[0],分别变成Y[1]等,得出16*16的图片然后display()出来,display代码如下: unsigned char num,x,y,b=0; for(num=0;num<4;num++)for(y=0;y<8;y++) or(x=0;x<8;x++)// pDC->SetPixelV(500+x+((num%2)<<3),250+y+((num/2)<<3),RGB(Y[num][y][x]+1.4*(128-128),Y[num][y][x]-0.34*(128-128)-0.71*(128-128),Y[num][y][x]+1.77*(128-128)));//其中由于只有一个分量所以在公式中的Cb、Cr都用128代替了,以上便绘了一个16*16的图片出来,可惜不正确
find函数的作用是找出对应的权值并建立矩阵。先把buffer(buffer里面为jpg数据段里的内容)里面高位的每次加一位地取出,即第一次取最高位,第二次取最高位和次高位,放入da变量中,lv储存的是编码最后的值,如果da==lv即找到了编码,读出权值为第几个(qnum),在对应表的地址+16+第几个权值即为对应的权值,不对则qnum++,以表示到下一个权值了,lv也对应地做处理,具体代码如下 find(int addr, unsigned char matr[][8],unsigned char* mnum) {int bnum=1,qnum=1,c,con=1; long lv=0,da; bool fin=1,fst=1; //deb=buf; fseek(fp,addr,SEEK_SET); while(bnum<=16&&fin) {da=buf>>(16-bnum); c=fgetc(fp);//c为读入的对应位数的码字数,bnum表示现在的位数 if(!c) {bnum++;continue;}//0则继续,con保证多个c=0后lv的位数仍无误 if(c&&(!fst))////lv!=0 { if(lv==~(0xffff<<bnum)) {lv++; lv=lv<<(bnum-con);} else { lv++; v=lv<<(bnum-con+1);} qnum++; if(lv==da) {//找到了 buf=shift(bnum,buf);//break;找到的话fin应该等于0,使能fin=0; //////////读取权值 unsigned char Q=GetW(addr,qnum);////之后把它低4位读出数据 mat(Q,matr,mnum);//形成矩阵 buf=shift(Q&0x0f,buf);//该函数把buffer移一定的位,有必要则读入文件的下一个数,在此为减少篇幅,略,我也验证过是正确的, fin=0;//结束循环 continue; } for(--c;c;c--) { lv++; qnum++; if(lv==da) {//找到了 buf=shift(bnum,buf);//break;找到的话fin应该等于0,使能fin=0; //////////读取权值 unsigned char Q=GetW(addr,qnum);////之后把它低4位读出数据 mat(Q,matr,mnum); buf=shift(Q&0x0f,buf); fin=0; break; } } con=++bnum; }//// if(fst&&c) {fst=0; if(lv==da) {//找到了 buf=shift(bnum,buf);//break;找到的话fin应该等于0,使能fin=0; //////////读取权值 unsigned char Q=GetW(addr,qnum);////之后把它低4位读出数据 mat(Q,matr,mnum); buf=shift(Q&0x0f,buf); fin=0; continue; } for(--c;c;c--) { lv++; qnum++; if(lv==da) {//找到了 buf=shift(bnum,buf);//break;找到的话fin应该等于0,使能fin=0; //////////读取权值 unsigned char Q=GetW(addr,qnum);////之后把它低4位读出数据 mat(Q,matr,mnum); buf=shift(Q&0x0f,buf); fin=0; break;//bnum等于1为测试用 } } con=++bnum; } } //停止时bnum等于17 } quant函数分别乘以表中的数据,比较简单,我已验证过了。 zigzag为://把63个分量重排 zigzag(unsigned char o[][8], unsigned char r[][8]) {unsigned char x=0,y=0,i=0; bool add=0,direct=1; while(!(x==7&&y==7)) {r[y][x]=o[i>>3][i%8];//应该是正确的 i++; if(y==0&&!add) {x++;add=1;direct=0;continue;} if(x==0&&y!=7&&!add) {y++;add=1;direct=1;continue;} if(x==7&&!add) {y++;add=1;direct=0;continue;} if(y==7&&!add) {x++;add=1;direct=1;continue;} if(direct) {y--;x++;add=0;} else {x--;y++;add=0;} } r[7][7]=o[7][7]; } :Toggle(unsigned char a[][8]) {unsigned char t=0;//从第一行开始隔行正负纠正 unsigned char i=1; for(;t<8;t+=2) {for(;i<8;i++) {if(a[t]) {if((a[t]&0x80)==0x80) a[t]=a[t]&0x7f; else a[t]=a[t]|0x80; } } } } IDCT(unsigned char p[][8],unsigned char r[][8]) {unsigned int u,v,i,j,f1,f2; float t=0; for(i=0;i<8;i++) for(j=0;j<8;j++) {for(u=0;u<8;u++) for(v=0;v<8;v++) { f1=((i<<2)+1)>>4; f2=((j<<2)+1)>>4; t+=C(u)*C(v)*p[v]*cos(f1*u*3.14)*cos(f2*v*3.14); //C(u)我已经定义了非0为1/2,0时为0.7 } r[j]=(int)t; } } 最后就是display了,display的时候把RGB都按照公式算出来,希望高手指点迷津,可以帮我也测试一下。谢谢。 |