预测编码
最好MFC做,对图片和字符串进行编码\解码.并界输出平均码长、压缩比、熵、与熵的接近程度、编码位流、码表. 
我有个就是编码后文件比原文件更大. 
各位高手能帮个忙吗?
应该怎么修改,然后怎样计算平均码长、压缩比、熵、与熵的接近程度、编码位流、码表并输出. 代码部分(编码解码部分,其他具体程序可与我联系或者留下邮箱地址):
#include "stdafx.h"
#include "GlobalApi.h"
#include "Cdib.h"#include <io.h>
#include <errno.h>#include <math.h>
#include <direct.h>
//using namespace std;// FOURBYTES就是用来计算离4最近的整倍数
#define FOURBYTES(bits)    (((bits) + 31) / 32 * 4)/**************************************************************************
 *  文件名:ImageCoding.cpp
 *
 *  正交变换API函数库:
 *
 *  WRITE2IMG() - 256色图象保存为256色IMG文件
 *  LOADIMG() - 读取指定的256色IMG文件 
 *  DIBBITPLANE() - 图像位平面分解
 *
 ************************************************************************
*/// PCX文件头结构
typedef struct{
 BYTE bManufacturer;
 BYTE bVersion;
 BYTE bEncoding;
 BYTE bBpp;
 WORD wLeft;
 WORD wTop;
 WORD wRight;
 WORD wBottom;
 WORD wXResolution;
 WORD wYResolution;
 BYTE bPalette[48];
 BYTE bReserved;
 BYTE bPlanes;
 WORD wLineBytes;
 WORD wPaletteType;
 WORD wSrcWidth;
 WORD wSrcDepth;
 BYTE bFiller[54];
} PCXHEADER;typedef struct{
 BYTE bBpp;
 WORD wLeft;
 WORD wTop;
 WORD wRight;
 WORD wBottom;
 WORD wXResolution;
 WORD wYResolution;
} IMGHEADER;/*************************************************************************
 *
 * 函数名称:
 *   WRITE2IMG()
 *
 * 参数:
 *   CDib * pDib        - 指向CDib对象的指针
 *   CFile& file        - 要保存的文件
 *
 * 返回值:
 *   BOOL               - 成功返回True,否则返回False。
 *
 * 说明:
 *   该函数将指定的图象保存为IMG文件。
 *
 *************************************************************************/
BOOL WINAPI WRITE2IMG(CDib * pDib, CFile& file)
{

// 指向源图像的指针
unsigned char* lpSrc; //图象的宽度和高度
LONG    lWidth;
LONG    lHeight; // 图像每行的字节数
LONG lLineBytes;

// 循环变量
LONG i;
LONG j;

// 参与预测的象素和当前编码的象素
BYTE bCharA;
BYTE bCharB;
BYTE bCharC;
BYTE bCharD;
    
// 预测值
int nTemp;

// 预测后的残差
int nDpcm;

// 指向编码后图像数据的指针
BYTE * lpDst;

//得到图象的宽度和高度
CSize   SizeDim;
SizeDim = pDib->GetDimensions();
lWidth  = SizeDim.cx;
lHeight = SizeDim.cy;

//得到实际的Dib图象存储大小
CSize   SizeRealDim;
SizeRealDim = pDib->GetDibSaveDim(); // 计算图像每行的字节数
lLineBytes = SizeRealDim.cx;

//图像数据的指针
LPBYTE  lpDIBBits = pDib->m_lpImage;

/**********************************************************************
*写入IMG文件头信息
***********************************************************************
*/
IMGHEADER Header4IMG;

// 给文件头赋值

// 像素位数(256色为8位)
Header4IMG.bBpp = 8;

// 图像相对于屏幕的左上角X坐标(以像素为单位)
Header4IMG.wLeft = 0;

// 图像相对于屏幕的左上角Y坐标(以像素为单位)
Header4IMG.wTop = 0;

// 图像相对于屏幕的右下角X坐标(以像素为单位)
Header4IMG.wRight = lWidth - 1;

// 图像相对于屏幕的右下角Y坐标(以像素为单位)
Header4IMG.wBottom = lHeight - 1;

// 图像的水平分辨率
Header4IMG.wXResolution = lWidth;

// 图像的垂直分辨率
Header4IMG.wYResolution = lHeight; // 写入文件头
file.Write((LPSTR)&Header4IMG, sizeof(IMGHEADER));

// 编码第0行
i = 0;
for ( j = 0; j < lWidth; j++)
{
// 指向图象0行j列象素的指针
lpSrc = (BYTE *)lpDIBBits + lLineBytes * (lHeight - 1 - i) +j ;

// 给bCharD赋值
bCharD = *lpSrc; // 如果是第0行0列,直接将象素值写入
if(j == 0)
nDpcm = (int)bCharD;
// 利用 Dpcm =D - A 计算残差 
else
{
bCharA = *(lpSrc - 1);
nDpcm  = (int)bCharD - (int)bCharA;
} // 将残差写入文件
file.Write(&nDpcm , sizeof(int));
}

// 编码第1行到lHeight-1行
for ( i=1;i<lHeight; i++)
{
for ( j = 0; j < lWidth; j++)
{
// 指向当前编码元素的指针
lpSrc = (BYTE *)lpDIBBits + j + lLineBytes * (lHeight - 1 - i);

// 赋值
bCharD = *lpSrc;
bCharB = *(lpSrc + lLineBytes); // 如果是第一列,利用 残差=D -B 进行预测
if(j == 0)
nDpcm = (int)bCharD - (int)bCharB;
else
{
// 利用(B-C)/2+A计算预测值
bCharA = *(lpSrc - 1);
bCharC = *(lpSrc + lLineBytes - 1);
nTemp  =  (int)((bCharB-bCharC) / 2 + bCharA);

// 如果预测值小于0,直接赋零
if(nTemp < 0)
nTemp = 0;
// 如果预测值大于255,直接赋值255
else if(nTemp > 255)
nTemp = 255;
else
nTemp = nTemp; // 得到残差
nDpcm = (int)bCharD - nTemp;
} // 将残差写入文件
file.Write(&nDpcm , sizeof(int));
}
}

// 开辟一片缓冲区以保存调色板
lpDst = new BYTE[769];

// 调色板起始字节
* lpDst = 0x0C; // 得到图象的调色板
LPRGBQUAD lpbmc = (LPRGBQUAD)pDib->m_lpvColorTable;

// 读取当前图象的调色板
for (i = 0; i < 256; i ++)
{

// 读取DIB调色板红色分量
lpDst[i * 3 + 1] = lpbmc[i].rgbRed;

// 读取DIB调色板绿色分量
lpDst[i * 3 + 2] = lpbmc[i].rgbGreen;

// 读取DIB调色板蓝色分量
lpDst[i * 3 + 3] = lpbmc[i].rgbBlue;
}

// 写入调色板信息
file.Write((LPSTR)lpDst, 769); // 返回值
return TRUE;
}

解决方案 »

  1.   


    /*************************************************************************
     *
     * 函数名称:
     *   LOADIMG()
     *
     * 参数:
     *   CDib * pDib        - 指向CDib类的指针
     *   CFile& file        - 要读取的文件
     *
     * 返回值:
     *   BOOL               - 成功返回TRUE
     *
     * 说明:
     *   该函数将读取指定的IMG文件
     *
     *************************************************************************/
    BOOL WINAPI LOADIMG(CDib * pDib, CFile& file)
    {
    // 循环变量
    LONG i;
    LONG j;

    // 图象高度
    LONG lHeight;

    // 图象宽度
    LONG lWidth;

    // 图像每行的字节数
    LONG lLineBytes;

    // 中间变量
    BYTE bChar;
    int     nTemp;

    // 指向源图像象素的指针
    int * lpSrc;

    // 指向编码后图像数据的指针
    BYTE * lpDst;

    // 临时指针
    int * lpTemp; // 用来参与预测的三个象素和当前编码象素
    BYTE bCharA;
    BYTE bCharB;
    BYTE bCharC; // IMG头文件
    IMGHEADER Header4IMG;

    /**********************************************************************
    *读出IMG文件头信息
    ***********************************************************************
    */

    // 尝试读取文件头
    if (file.Read((LPSTR)&Header4IMG, sizeof(IMGHEADER)) 
    != sizeof(IMGHEADER))
    {
    // 大小不对,返回NULL。
    return NULL;
    }

    // 获取图像高度
    lHeight = Header4IMG.wBottom - Header4IMG.wTop + 1;

    // 获取图像宽度
    lWidth  = Header4IMG.wRight - Header4IMG.wLeft + 1;

    // 计算图像每行的字节数
    lLineBytes = FOURBYTES(lWidth * 8);

    // 获得显示图象的头文件
    LPBITMAPINFOHEADER lpBI=pDib->m_lpBMIH;

    // 给图象头文件成员赋值
    lpBI->biSize = 40;
    lpBI->biWidth = lWidth;
    lpBI->biHeight = lHeight;
    lpBI->biPlanes = 1;
    lpBI->biBitCount = 8;
    lpBI->biCompression = BI_RGB;
    lpBI->biSizeImage = lHeight * lLineBytes;
    lpBI->biXPelsPerMeter = Header4IMG.wXResolution;
    lpBI->biYPelsPerMeter = Header4IMG.wYResolution;
    lpBI->biClrUsed = 0;
    lpBI->biClrImportant = 0;

    // 分配内存以读取编码后的象素
    lpSrc = new int[(file.GetLength() - sizeof(IMGHEADER)-769) ];

    lpTemp = lpSrc;

    // 读取编码后的象素
    if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(IMGHEADER)-769) 
    != file.GetLength() - sizeof(IMGHEADER)-769 )
    {

    return FALSE;
    }

    // 重新分配内存,以适应新的图象大小
    delete  pDib->m_lpImage;
    pDib->m_lpImage = new unsigned char[lHeight * lLineBytes]; // CDib类中像素位置
    lpDst = pDib->m_lpImage;

    // 解码第0行
    i = 0;
    for(j = 0; j < lWidth; j++)
    {
    if(j==0)
    {
    // 如果是0行0列,编码值就是真实值
    lpDst[j + lLineBytes * (lHeight - 1 - i)] = (BYTE)(*lpTemp);
    lpTemp ++;
    }
    else
    {
    // 利用 D=A+残差 得到原来的象素
    lpDst[j+ lLineBytes * (lHeight - 1 - i)]
    = (BYTE)(*lpTemp) + lpDst[j + lLineBytes * (lHeight - 1 - i) - 1];
    lpTemp++;
    }
    } // 解码第1行到第lHeight-1行
    for (i = 1; i < lHeight; i++)
        {
    for (j = 0; j < lWidth; j++)
    {
    // 得到象素B的值
    bCharB = lpDst[j + lLineBytes * (lHeight  - i)];

    // 解码第一列
    if(j==0)
    {
    // 利用 D=B+残差 得到原来的象素值
    lpDst[j+ lLineBytes * (lHeight - 1 - i)] = (BYTE)((*lpTemp) + bCharB);
    lpTemp++;
    }

    // 解码剩下的列
    else
    {
    // 利用 D=(B-C)/2 + A + 残差 得到原来的象素值
    bCharA=lpDst[j - 1 + lLineBytes * (lHeight - 1 - i)];
    bCharC=lpDst[j - 1 + lLineBytes * (lHeight - i)];

    // 解码时的预测
    nTemp=(int)((bCharB - bCharC) / 2  +bCharA);

    // 预测值小于0,直接赋0
    if(nTemp<0)
    nTemp = 0;
    // 预测值大于255,直接赋值255
    else if(nTemp>255)
    nTemp = 255;  
    else
    nTemp = nTemp; // 预测值+残差
    lpDst[j + lLineBytes * (lHeight - 1 - i)] 
    = (BYTE)(*lpTemp + (BYTE)nTemp);
    lpTemp++;
    }
    }
    } // 释放内存
    delete lpSrc;
    lpDst  = NULL;

    // 读调色板标志位
    file.Read(&bChar, 1);
    if (bChar != 0x0C)
    {
    // 返回NULL。
    return FALSE;
    }

    // 分配内存以读取编码后的象素
    lpDst = new BYTE[768];

    // 图象中调色板的位置
    LPRGBQUAD lpbmc = (LPRGBQUAD)pDib->m_lpvColorTable;

    // 读取调色板
    if (file.Read(lpDst, 768) != 768)
    {
    return FALSE;
    }

    // 给调色板赋值
    for (i = 0; i < 256; i++)
    {
    lpbmc[i].rgbRed   = lpDst[i * 3 + 2];
    lpbmc[i].rgbGreen = lpDst[i * 3 + 1];
    lpbmc[i].rgbBlue  = lpDst[i * 3];
    lpbmc[i].rgbReserved = 0;
    }

    // 返回值
    return TRUE;
    }
    /*************************************************************************
     *
     * 函数名称:
     *   DIBBITPLANE()
     *
     * 参数:
     *   CDib * pDib        - 指向CDib类的指针
     *   CFile& file        - 要读取的文件
     *
     * 返回值:
     *   BOOL               - 成功返回TRUE
     *
     * 说明:
     *   该函数将制定的图象进行位平面分解
     *
     *************************************************************************/
    BOOL WINAPI DIBBITPLANE(CDib *pDib,BYTE bBitNum)
    {
    // 如果输入的数不符合要求,不进行分解
    if(bBitNum <1 || bBitNum >8)
    return FALSE;

    // 指向源图像的指针
    BYTE * lpSrc; //图象的宽度和高度
    LONG    lWidth;
    LONG    lHeight; // 图像每行的字节数
    LONG lLineBytes;

    // 循环变量
    LONG i;
    LONG j; // 中间变量
    BYTE bTemp;
    BYTE bA; // 二进制第i位对应的十进制值
    BYTE bCount;

    //得到图象的宽度和高度
    CSize   SizeDim;
    SizeDim = pDib->GetDimensions();
    lWidth  = SizeDim.cx;
    lHeight = SizeDim.cy;

    //得到实际的Dib图象存储大小
    CSize   SizeRealDim;
    SizeRealDim = pDib->GetDibSaveDim(); // 计算图像每行的字节数
    lLineBytes = SizeRealDim.cx;

    //图像数据的指针
    LPBYTE  lpDIBBits = pDib->m_lpImage;

    bCount = 1<<(bBitNum - 1);

    for (i = 0; i<lHeight; i++)
    {
    for ( j = 0; j < lWidth; j++)
    {
    // 指向位图i行j列的指针
    lpSrc = (BYTE *)lpDIBBits + j+lLineBytes * (lHeight - 1 - i); // 对位图按灰度码进行分解
    if(bBitNum == 8)
    {
    // 如果求的是位图8,直接取二值的第8位
    bTemp = (*(lpSrc) & bCount) / bCount;
    bTemp = bTemp * 255;
    }
    else
    {
    // 否则进行异或,求得灰度码
    bTemp = (*(lpSrc) & bCount) / bCount;
    bA    = bCount * 2; // 第i+1位图的象素值
    bA = (*(lpSrc) & bA) / bA; // 异或
    bTemp = (bTemp ^ bA) * 255;
    } // 更新源图象
    *(lpSrc) = bTemp;
    }
    } // 返回值
    return TRUE;
    }