缺点:高频段有阴影
/*
Auto folder version [1]
Name [imcp.cpp]
Branch [image_process]
File type [cpp]
Direction [灰度图像压缩,支持分辨率:120*160,240*320,480*640,960*1280]
*/
#include "stdafx.h"
#include
#include
const int dct_f88[8][8] = //JPEG亮度分量量化矩阵
{
16,11,10,16,24,40,51,61, //[0][0]:16
12,12,14,19,26,58,60,55,
14,13,16,24,40,57,69,56,
14,17,22,29,51,87,80,62,
18,22,37,56,68,109,103,77,
24,35,55,64,81,104,113,92,
49,64,78,87,103,121,120,101,
72,92,95,98,112,100,103,99
};
/*行程编码顺序
{
<0>0, <1>1, <2>5, <3>6, <4>14, <5>15, <6>27, <7>28,
<8>2, <9>4, <10>7, <11>13, <12>16, <13>26, <14>29, <15>42,
<16>3, <17>8, <18>12, <19>17, <20>25, <21>30, <22>41, <23>43,
<24>9, <25>11, <26>18, <27>24, <28>31, <29>40, <30>44, <31>53,
<32>10, <33>19, <34>23, <35>32, <36>39, <37>45, <38>52, <39>54,
<40>20, <41>22, <42>33, <43>38, <44>46, <45>51, <46>55, <47>60,
<48>21, <49>34, <50>37, <51>47, <52>50, <53>56, <54>59, <55>61,
<56>35, <57>36, <58>48, <59>49, <60>57, <61>58, <62>62, <63>63
};*/
const int jpeg_natural_order[64+16] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63,
63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
63, 63, 63, 63, 63, 63, 63, 63
};
float dct_mat[8][8];//用于存储DCT矩阵
float dct_mat_temp[8][8];//用于存储临时计算量
signed char dct_mat_out[8][8];//dct计算得到的数据
static int is_imcp_first_use = 0;
int dct_inpt[8][8];
float dcXmap_table[64][256];//高速查找表
//初始化DCT变换矩阵到dct_mat
void init_dct_mat() //初始化DCT矩阵
{
int i, j, t;
for (i = 0; i < 8; i++) dct_mat[0][i] = sqrt(2.0 / 8)*sqrt(1.0 / 2);
for (i = 1; i<8; i++)
{
t = 0;
for (j = 0; j<8; j++)
{
dct_mat[i][j] = sqrt(2.0 / 8)*cos(3.14159265354 / (2.0 * 8)*(i + t));
t += 2 * i;
}
}
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
for (t = 0; t < 256; t++)
{
dcXmap_table[i * 8 + j][t] = dct_mat[i][j] * t;
}
}
}
}
//img_ori为输入8*8区域左上角的指针,width为图像宽度,buffer为输出压缩数据所存储的首地址,返回使用了多少字节buffer
int dct_rle_encoder(const unsigned char *img_ori, int width, unsigned char *buffer)
{
float t;
int i, j, k, ct;
signed char *pDct = (signed char*)dct_mat_out;
signed char left, right;
signed int res;
//Temp=dct_mat*MAP_IN
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
t = 0;
ct = i * 8;
for (k = 0; k < 8; k++)
//t += dct_mat[i][k] * img_ori[k*width + j];
t += dcXmap_table[ct + k][img_ori[k*width + j]];
dct_mat_temp[i][j] = t;
}
}
//DCT=Temp*T(dct_mat)
for (i = 0; i<8; i++) {
for (j = 0; j<8; j++) {
t = 0;
for (k = 0; k < 8; k++)
{
t += dct_mat_temp[i][k] * dct_mat[j][k];
}
dct_mat_out[i][j] = (signed char)(t / dct_f88[i][j] + (t > 0 ? 0.5 : -0.5)); //归一化
}
}
//对DCT进行RLE编码,第一个直流分量不参与编码
k = 0;
buffer[k++] = pDct[0];//直流分量不参与编码
//下面是RLE编码
i = 1; //i始终跟着right
left = pDct[jpeg_natural_order[i]]; //left从下标1开始
while (i < 64)
{
ct = i;
do{
right = pDct[jpeg_natural_order[++i]];//更新right
} while ((left == right) && (i < 64));
ct = i - ct;
if (ct == 1)
{
res = left + 64; //转化为移码
res = res > 127 ? 127 : res;
res = res < 0 ? 0 : res; //限定存储最高位为1
buffer[k++] = (unsigned char)res; //存储left
left = right;
}
else
{
//存储
res = left + 64; //转化为移码
res = res > 127 ? 127 : res;
res = res < 0 ? 0 : res; //限定存储最高位为1
buffer[k++] = (ct & 0x7F) | 0x80; //先存储个数(标记为1XXXXXXX)
buffer[k++] = (unsigned char)res; //在存储值
//==
left = right;
}
}
return k;
}
//buffer为需要解压的首地址(一次性仅解压8*8区域),width为图像宽度,img_out为输出8*8区域的左上角指针,返回使用了多少字节buffer
int dct_rle_decoder(const unsigned char *buffer, int width, unsigned char *img_out)
{
float t = 0;
int i, j, k, ct_in, ct_cp;
int *pInt = (int*)dct_inpt;
int temp;
ct_in = 0;
ct_cp = 0;
pInt[jpeg_natural_order[ct_in++]] = buffer[ct_cp++];//DC
while (ct_in < 64)//AC采集63个
{
temp = (int)buffer[ct_cp++];
if (temp > 127)
{
k = (int)(temp & 0x7f);
temp = (int)buffer[ct_cp] - 64;
for (i = 0; i < k; i++)
{
pInt[jpeg_natural_order[ct_in++]] = temp;
}
ct_cp += 1;
}
else
{
pInt[jpeg_natural_order[ct_in++]] = temp - 64;
}
}
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
dct_inpt[i][j] *= dct_f88[i][j]; //还原DCT结果
//Temp=T(dct_mat)*DCT
for (i = 0; i<8; i++) {
for (j = 0; j<8; j++) {
t = 0;
for (k = 0; k<8; k++)
t += dct_mat[k][i] * dct_inpt[k][j];
dct_mat_temp[i][j] = t;
}
}
//MAP_IN=Temp*dct_mat
for (i = 0; i<8; i++) {
for (j = 0; j<8; j++) {
t = 0;
for (k = 0; k<8; k++)
t += dct_mat_temp[i][k] * dct_mat[k][j];
if (t > 255) t = 255;
if (t < 0) t = 0;
img_out[i*width + j] = (unsigned char)(t);
}
}
return ct_cp;
}
int imcp_encoder(const unsigned char *bmp_gray_in, int height, int width, unsigned char *buffer)
{
int ct = 0, i, j;
int coder_ct;
unsigned char *ori_now = (unsigned char*)bmp_gray_in;
unsigned char *buf_now = (unsigned char*)buffer;
/*if (!is_imcp_first_use)
{
init_dct_mat();
is_imcp_first_use = 1;
}*/
for (i = 0; i < height / 8; i++)
{
for (j = 0; j < width / 8; j++)
{
coder_ct = dct_rle_encoder(ori_now + j * 8, width, buf_now);
buf_now += coder_ct;
ct += coder_ct;
}
ori_now += 8 * width;
}
return ct;
}
int imcp_decoder(const unsigned char *buffer, int buffer_len, int height, int width, unsigned char *bmp_gray_out)
{
int ct = 0, i, j;
int coder_ct;
unsigned char *ori_now = (unsigned char*)bmp_gray_out;
unsigned char *buf_now = (unsigned char*)buffer;
/*if (!is_imcp_first_use)
{
init_dct_mat();
is_imcp_first_use = 1;
}*/
for (i = 0; i < height / 8; i++)
{
for (j = 0; j < width / 8; j++)
{
coder_ct = dct_rle_decoder(buf_now, width, ori_now + j * 8);
buf_now += coder_ct;
ct += coder_ct;
if (ct > buffer_len) return 0;
}
ori_now += 8 * width;
}
return 1;
}