打印

我的jpeg解码的代码

[复制链接]
1823|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
四叶草|  楼主 | 2007-12-12 20:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我的代码结果不正确,我想实现的就是在只有一个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都按照公式算出来,希望高手指点迷津,可以帮我也测试一下。谢谢。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

71

主题

109

帖子

0

粉丝