# 图像的基本有损压缩和无损压缩及解压

5 篇文章 2 订阅

### 背景

English Version:http://jiangxh.top/articles/2016-10/compressionEN

### 有损量化5-5-5和5-6-5

5-5-5指的是只使用低15位，剩下的一位弃用，这样每个通道一致的都压缩为5位；

5-6-5则是充分使用了16位，其中G通道占6位，另外两通道各占5位。

5-6-6和5-5-5同理，只是G通道的二进制数右移2两位（除以4），将剩下的6位和其他两通道的10位一同放入16位二进制数中。解压时同样是低位补0还原为8位。

5-5-5：

unsigned char *CAppQuantize::Quantize555(int &qDataSize) {

int i, j ;
unsigned int r, g, b ;
unsigned short rgb16 ;

qDataSize = width * height * 2 ;

unsigned char *quantizedImageData = new unsigned char[width * height * 2] ;

for(j = 0; j < height; j++) {
for(i = 0; i < width; i++) {
b = pInput[(i + j * width) * 3 + 0] ;   // Blue Color Component
g = pInput[(i + j * width) * 3 + 1] ;   // Red Color Component
r = pInput[(i + j * width) * 3 + 2] ;   // Green COlor Component
rgb16 = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) ;
quantizedImageData[(i + j * width) * 2 + 0] = rgb16 & 0xFF ;
quantizedImageData[(i + j * width) * 2 + 1] = (rgb16 >> 8) & 0xFF ;
}
}

return quantizedImageData ;
}
void CAppQuantize::Dequantize555(unsigned char *quantizedImageData, unsigned char *unquantizedImageData) {

int i, j ;
unsigned int r, g, b ;
unsigned short rgb16 ;

for(j = 0; j < height; j++) {
for(i = 0; i < width; i++) {
rgb16 = quantizedImageData[(i + j * width) * 2 + 0] | (((unsigned short) quantizedImageData[(i + j * width) * 2 + 1]) << 8) ;
b = rgb16 & 0x1F;
g = (rgb16 >> 5) & 0x1F ;
r = (rgb16 >> 10) & 0x1F ;
unquantizedImageData[(i + j * width) * 3 + 0] = (b << 3) ;
unquantizedImageData[(i + j * width) * 3 + 1] = (g << 3) ;
unquantizedImageData[(i + j * width) * 3 + 2] = (r << 3) ;
}
}
}

5-6-5:

unsigned char *CAppQuantize::Quantize565(int &qDataSize) {

int i, j;
unsigned int r, g, b;
unsigned short rgb16;

qDataSize = width * height * 2 ;
unsigned char *quantizedImageData = new unsigned char[width * height * 2] ;

for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
b = pInput[(i + j * width) * 3 + 0];    // Blue Color Component
g = pInput[(i + j * width) * 3 + 1];    // Green Color Component
r = pInput[(i + j * width) * 3 + 2];    // Red Color Component
rgb16 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); // r分量和b分量右移3位，g分量右移2位

quantizedImageData[(i + j * width) * 2 + 0] = rgb16 & 0xFF; // 高8位
quantizedImageData[(i + j * width) * 2 + 1] = (rgb16 >> 8) & 0xFF;// 低8位
}
}

return quantizedImageData ;
}
void CAppQuantize::Dequantize565(unsigned char *quantizedImageData, unsigned char *unquantizedImageData) {

int i, j;
unsigned int r, g, b;
unsigned short rgb16;

for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
rgb16 = quantizedImageData[(i + j * width) * 2 + 0] | (((unsigned short)quantizedImageData[(i + j * width) * 2 + 1]) << 8);
b = rgb16 & 0x1F;   // 保留高5位
g = (rgb16 >> 5) & 0x3F;// 右移5位后保留高6位
r = (rgb16 >> 11) & 0x1F;// 右移11位后保留高5位
unquantizedImageData[(i + j * width) * 3 + 0] = (b << 3); // 左移3位，高位补0
unquantizedImageData[(i + j * width) * 3 + 1] = (g << 2); // 左移2位，高位补0
unquantizedImageData[(i + j * width) * 3 + 2] = (r << 3); // 左移3位，高位补0
}
}
}

### 通道游长编码无损压缩

unsigned char *CAppCompress::Compress(int &cDataSize) {

unsigned char *compressedData ;
cDataSize = width * height * 3 ;

// 存储压缩后的数据,最差的情况尺寸也不会到大于cDataSize * 2
compressedData = new unsigned char[cDataSize * 2];
// 实际压缩字符长度
int compressedSize = 0;

// 采用分通道游离的方法，按照每个通道相邻像素的重复性进行压缩
// 1.b通道
unsigned short curB = pInput[0];// 第一个像素的b
unsigned short repeat = 1;// 重复次数
for (int i = 1; i < cDataSize / 3; i++)
{
unsigned short nextB = pInput[i * 3 + 0];// 下一个像素的b
if (nextB == curB && repeat < 127)
{
++repeat;
// 如果是最后一个则存储
if (i == cDataSize / 3 - 1)
{
// 存储最后一个b值组
compressedData[compressedSize] = repeat;
compressedData[compressedSize + 1] = curB;
// 增加编码数据长度
compressedSize += 2;
}
}
else
{
// 存储上一个b值组
compressedData[compressedSize] = repeat;
compressedData[compressedSize + 1] = curB;
// 增加编码数据长度
compressedSize += 2;
// 换下一种b值
curB = nextB;
repeat = 1;
// 如果是最后一个
if (i == cDataSize / 3 - 1)
{
// 存储最后一个b值
compressedData[compressedSize] = 1;
compressedData[compressedSize + 1] = curB;
// 增加编码数据长度
compressedSize += 2;
}
}
}

// 2.g通道
unsigned short curG = pInput[1];// 第一个像素的g
repeat = 1;// 重复次数
for (int i = 1; i < cDataSize / 3; i++)
{
unsigned short nextG = pInput[i * 3 + 1];// 下一个像素的g
if (nextG == curG && repeat <= 127)
{
++repeat;
// 如果是最后一个则存储
if (i == cDataSize / 3 - 1)
{
// 存储最后一个g值组
compressedData[compressedSize] = repeat;
compressedData[compressedSize + 1] = curG;
// 增加编码数据长度
compressedSize += 2;
}
}
else
{
// 存储上一个g值组
compressedData[compressedSize] = repeat;
compressedData[compressedSize + 1] = curG;
// 增加编码数据长度
compressedSize += 2;
// 换下一种g值
curG = nextG;
repeat = 1;
// 如果是最后一个
if (i == cDataSize / 3 - 1)
{
// 存储最后一个g值
compressedData[compressedSize] = 1;
compressedData[compressedSize + 1] = curB;
// 增加编码数据长度
compressedSize += 2;
}
}
}

// 3.r通道
unsigned short curR = pInput[2];// 第一个像素的r
repeat = 1;// 重复次数
for (int i = 1; i < cDataSize / 3; i++)
{
unsigned short nextR = pInput[i * 3 + 2];// 下一个像素的r
if (nextR == curR && repeat <= 127)
{
++repeat;
// 如果是最后一个则存储
if (i == cDataSize / 3 - 1)
{
// 存储最后一个g值组
compressedData[compressedSize] = repeat;
compressedData[compressedSize + 1] = curR;
// 增加编码数据长度
compressedSize += 2;
}
}
else
{
// 存储上一个g值组
compressedData[compressedSize] = repeat;
compressedData[compressedSize + 1] = curR;
// 增加编码数据长度
compressedSize += 2;
// 换下一种r值
curR = nextR;
repeat = 1;
// 如果是最后一个
if (i == cDataSize / 3 - 1)
{
// 存储最后一个r值
compressedData[compressedSize] = 1;
compressedData[compressedSize + 1] = curR;
// 增加编码数据长度
compressedSize += 2;
}
}
}

// 取出压缩后的纯数据
cDataSize = compressedSize;
unsigned char *finalData = new unsigned char[cDataSize];
for (int i = 0; i < cDataSize; i++)
{
unsigned char temp = compressedData[i];
finalData[i] = temp;
}
delete compressedData;
compressedData = finalData;

return compressedData;
}

void CAppCompress::Decompress(unsigned char *compressedData, int cDataSize, unsigned char *uncompressedData) {

// 寻找g通道和r通道在压缩数据数组中的偏移坐标
int offset_r = 0, offset_g = 0;
int pixelCount = 0;
for (int i = 0; i < cDataSize;)
{
int curRpeat = compressedData[i];
pixelCount += curRpeat;
i += 2;
if (pixelCount == width*height)
{
offset_g = i;// g通道的开始坐标
}
if (pixelCount == width*height * 2)
{
offset_r = i;// r通道的开始坐标
}
}

unsigned int b, g, r;
int repeat;
// 1.还原b通道
for (int i = 0, j = 0; i < width*height, j < offset_g; j += 2)
{
// 恢复一组重复的b值
repeat = compressedData[j];
for (int p = 0; p < repeat; p++)
{
int d = compressedData[j + 1];
uncompressedData[i * 3 + p*3 + 0] = compressedData[j + 1];
}
i += repeat;
}

// 2.还原g通道
for (int i = 0, j = offset_g; i < width*height, j < offset_r; j += 2)
{
repeat = compressedData[j];
for (int p = 0; p < repeat; p++)
{
int d = compressedData[j + 1];
uncompressedData[i * 3 + p * 3 + 1] = compressedData[j + 1];
}
i += repeat;
}

// 3.还原r通道
for (int i = 0, j = offset_r; i < width*height, j < cDataSize; j += 2)
{
repeat = compressedData[j];
for (int p = 0; p < repeat; p++)
{
int d = compressedData[j + 1];
uncompressedData[i * 3 + p * 3 + 2] = compressedData[j + 1];
}
i += repeat;
}
}

### 空间分割优化

type cpp


。。。

。。。

• 13
点赞
• 46
收藏
• 打赏
• 6
评论
12-22 7938
11-12 3243
10-20 662
12-12 7916
03-31
10-25 4万+
11-13
11-01
12-02
09-13 256
11-22
04-19 373
09-15 60

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

©️2022 CSDN 皮肤主题：Age of Ai 设计师：meimeiellie

Mr_厚厚

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。