多媒体技术与应用实验——BMP图像Huffman(霍夫曼)编解码

编译器是CLion,代码是C的,但是保存为.c的时候没能通过,保存为.cpp才能运行。

//Bmp图像的哈夫曼编码代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct{
    unsigned int weight;
    unsigned int parent,lchild,rchild;
}HTNode, *huffmantree;// 动态分配数组存储赫夫曼树

typedef char **huffmancode;// 动态分配数组存储赫夫曼编码表

int power(int i)
{
    int j,result=1;
    for(j=0;j0;i--)
    {
        if(temp[8-i]!='0')
        {
            result+=power(i-1);
        }
    }
    strcpy(temp,temp+8);
}

void select1(huffmantree HT, unsigned int i, unsigned int *s1, unsigned int *s2)
{// s1为最小的两个值中序号小的那个

    unsigned int j,temp;
    for(j=1;j<=i;j++)
    {
        if(HT[j].parent==0)
        {
            *s2=j;
            break;
        }
    }
    for(;j<=i;j++)
    {
        if(HT[j].parent==0 && j!=*s2)
        {
            *s1=j;
            break;
        }
    }
    for(j=1;j<=i;j++)
    {
        if(HT[j].parent==0 && HT[j].weight < HT[*s1].weight && *s2!=j)
        {
            *s1=j;
        }
    }
    for(j=1;j<=i;j++)
    {
        if(HT[j].parent==0 && HT[j].weight < HT[*s2].weight && *s1!=j)
        {
            *s2=j;
        }
    }
    if(*s1>*s2)
    {
        temp=*s1;
        *s1=*s2;
        *s2=temp;
    }
}


void huffmancoding(huffmantree &HT, huffmancode &HC,unsigned long int *w, unsigned int n)
{
// w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC

    unsigned int s1,s2,start,c,f,i,m;// 0号单元未用
    huffmantree p;
    char *cd;
    if (n<=1)
    {
        return;
    }
    m=2*n-1;
    HT=(huffmantree)malloc((m+1)*sizeof(HTNode));//malloc 向系统申请分配指定size个字节的内存空间。
    for(p=HT+1,i=1; i<=n; ++i,++p,++w)
    {
        p->weight=*w;
        p->parent=0;
        p->lchild=0;
        p->rchild=0;
    }

    for(; i<=m; ++i,++p)
    {
        p->weight=0;
        p->parent=0;
        p->lchild=0;
        p->rchild=0;
    }

    for(i=n+1; i<=m; ++i)// 建哈夫曼树

    { // 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
        select1(HT,i-1,&s1,&s2);
        HT[s1].parent=i;  HT[s2].parent=i;
        HT[i].lchild=s1;  HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
// 从叶子到根逆向求每个字符的赫夫曼编码
    HC=(huffmancode)malloc((n+1)*sizeof(char *));// 分配n个字符编码的头指针向量([0]不用
    cd=(char *)malloc(n*sizeof(char));

    cd[n-1]='\0';// 编码结束符

    for(i=1; i<=n; ++i)
    {// 逐个字符求赫夫曼编码

        start=n-1;// 编码结束符位置

        for(c=i,f=HT[i].parent; f!=0; c=f,f=HT[f].parent)
        {// 从叶子到根逆向求编码
            if(HT[f].lchild==c)
            {
                cd[--start]='0';
            }
            else
            {
                cd[--start]='1';
            }
        }
        HC[i]=(char *)malloc((n-start)*sizeof(char)); // 为第i个字符编码分配空间

        strcpy(HC[i],&cd[start]);// 从cd复制编码(串)到HC
    }
    free(cd);// 释放工作空间
}


int main()
{
    char w[256]="\0";
    char temp[40]="\0";
    unsigned char len;
    unsigned long int count[256]={0},weight[256]={0},n=0,i=0;
    unsigned int q=0;
    unsigned long int *p;
    char filename[260]="\0",filename2[260]="\0",houzui[8]="\0";
    char *point;
    char colorplat[1024];
    FILE *fp,*fp2;
    huffmantree HT;
    huffmancode HC;

    BITMAPFILEHEADER bf;	//BMP文件头结构体
    BITMAPINFOHEADER bi;	//BMP信息头结构体
    //	打开文件
    printf("input the file name :");
    gets(filename);//从stdin流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在str指针所指向的字符数组中。
    strcpy(filename2,filename);

    for(point=filename2+strlen(filename2); *point!='.'; point--);//文件名修改

    strcpy(houzui,point);
    strcpy(point,".shq");
    if((fp=fopen(filename,"rb"))==NULL)//fopen函数用来打开一个文件
    {
        printf("error on open\n");
        exit(1);
    }
    //读取信息头、文件头
    fread( &bf,sizeof(BITMAPFILEHEADER), 1, fp ); //把指针fp所指向的文件的头信息写入bf(地址)
    fread( &bi,sizeof(BITMAPINFOHEADER), 1, fp );
    if(bf.bfType != 0x4d42)           //校验图片类型
    {
        printf("文件非bmp格式 \n");
        exit(1);
    }
    if(bi.biBitCount<24)
    {
        int tm;
        (int)tm==pow(2.,bi.biBitCount);
        fread(colorplat,4*tm,1,fp);
    }
    while(fread(&q,1,1,fp))
    {
        count[q]++;
    }
    fclose(fp);
    for(p=count;i<256;p++,i++)
    {
        weight[n++]=*p;
    }

    huffmancoding(HT,HC,weight,n);

    for(i=0,n=1;i<256;i++)
    {
        if(count[i]!=0)
        {
            printf("%d:  ",i);
            printf("%s\n",HC[n++]);
        }
    }
    if((fp=fopen(filename,"rb"))==NULL)
    { //只读打开或建立一个二进制文件,只允许读数据
        printf("error\n");
        exit(1);
    }
    if((fp2=fopen(filename2,"wb"))==NULL)
    { //只写打开或建立一个二进制文件,只允许写数据
        printf("error\n");
        exit(1);
    }
    fwrite( &bf,sizeof(BITMAPFILEHEADER), 1 ,fp2 );
    fwrite( &bi,sizeof(BITMAPINFOHEADER), 1, fp2 );
    if(bi.biBitCount<24)//调用套色板
    {
        fwrite(colorplat,4*(int)pow(2.,bi.biBitCount),1,fp2);
    }
    fwrite(houzui,8,1,fp2);

    for(i=1;i<=256;i++)
    {
        len=strlen(HC[i]);
        fwrite(&len,1,1,fp2);
        fwrite(HC[i],len,1,fp2);
    }
    fseek(fp,54L,0);//跳过文件头
    while(fread(&q,1,1,fp))
    {
        strcat(temp,HC[q+1]);
        while(strlen(temp)>=8)
        {
            write_file(temp,fp2);
        }
    }
    for(i=strlen(temp);i<8;i++)//编码长度<8的编码后面补‘1’
    {
        temp[i]='1';
    }
    temp[i]='\0';
    write_file(temp,fp2);
    fclose(fp);
    fclose(fp2);

    system("read");
}

如图为编译结果:

要将需要处理的图片放在代码所在的文件夹,不然读取不出来。

然后再把图片地址复制上去,比如我就是"C:\Users\Uni\CLionProjects\BMP1\lena.bmp"。

运行结果如图:

多媒体技术与应用实验——BMP图像Huffman(霍夫曼)编解码_第1张图片

从0到255,但是验收的时候老师不是很满意因为没有算压缩比那些的=.=

你可能感兴趣的:(多媒体技术与应用实验——BMP图像Huffman(霍夫曼)编解码)