在Java中压缩字节数组并在C中解压缩

在Java中压缩字节数组并在C中解压缩,java,c,embedded,compression,Java,C,Embedded,Compression,我目前在Java程序中有以下数组 byte[] data = new byte[800]; 在通过串行(115200波特)将其发送到微控制器之前,我想对其进行压缩。然后我想用C语言解压微控制器上的阵列。但是,我不太确定最好的方法是什么。性能是一个问题,因为微控制器只是一个arduino,所以它不能太内存/cpu密集。数据或多或少是随机的(edit我想它不是真的随机的,请参见下面的编辑),因为它表示每16位的rgb颜色值 压缩这些数据的最佳方式是什么?你知道我能压缩多少吗 编辑 很抱歉,缺少信息

我目前在Java程序中有以下数组

byte[] data = new byte[800];
在通过串行(115200波特)将其发送到微控制器之前,我想对其进行压缩。然后我想用C语言解压微控制器上的阵列。但是,我不太确定最好的方法是什么。性能是一个问题,因为微控制器只是一个arduino,所以它不能太内存/cpu密集。数据或多或少是随机的(edit我想它不是真的随机的,请参见下面的编辑),因为它表示每16位的rgb颜色值

压缩这些数据的最佳方式是什么?你知道我能压缩多少吗

编辑

很抱歉,缺少信息。我需要的压缩是无损的,我只打算发送800字节的时间。我的问题是,在我使用的115200波特的速率下,800字节的传输速度不够快。我希望我能缩小尺寸以提高速度

每两个字节看起来像:

0RRRRRGGGBBB


其中,RG和B位分别表示红色、绿色和蓝色通道的值。然后,每两个字节是20x20网格上的单个LED。我可以想象,许多两个字节的集合是相同的,因为我经常将相同的颜色代码分配给多个LED。也可能是RGB值通常大于15,因为我通常在可能的情况下使用明亮的颜色(但是,这可能是一个没有意义的问题,因为它们不是一次都大于15)。

使用miniLZO压缩

一种非常简单的压缩/解压算法是游程编码,它在小型嵌入式环境中非常实用,并且很容易“自己滚动”。基本上,这意味着用(计数,值)对替换一系列重复的值。当然,您需要一个sentinel(magic)值来引入该对,然后需要一个机制来允许magic值出现在正常数据中(通常,两个作业都可以使用转义序列)。在您的示例中,最好使用16位值(2字节)

当然,这一切都取决于数据。根据定义,足够随机的数据是不可压缩的。您最好先收集一些示例数据,然后评估压缩选项

发布额外信息后编辑

只是为了好玩,也为了展示运行长度编码是多么容易,我编写了一些东西。恐怕我也用过C进行压缩,因为我不是Java爱好者。为了简单起见,我完全使用了16位数据。优化方法是在(计数,值)对中使用8位计数。我还没有尝试编译或测试这段代码。另请参阅我对您关于损坏LED地址可能带来的好处的问题的评论

#define NBR_16BIT_WORDS 400
typedef unsigned short uint16_t;

// Return number of words written to dst (always
//  less than or equal to NBR_16BIT_WORDS)
uint16_t compress( uint16_t *src, uint16_t *dst )
{
    uint16_t *end = (src+NBR_16BIT_WORDS);
    uint16_t *dst_begin = dst;
    while( src < end )
    {
        uint16_t *temp;
        uint16_t count=1;
        for( temp=src+1; temp<end; temp++ )
        {
            if( *src == *temp )
                count++;
            else
                break;
        }
        if( count < 3 )
            *dst++ = *src++;
        else
        {
            *dst++ = (*src)|0x8000;
            *dst++ = count;
            *src += count;
        }
    }  
    return dst-dst_begin;
}

void decompress( uint16_t *src, uint16_t *dst )
{
    uint16_t *end_src = (src+NBR_16BIT_WORDS);
    uint16_t *end_dst = (dst+NBR_16BIT_WORDS);
    while( src<end_src && dst<end_dst )
    {
        data = *src++;
        if( (data&0x8000) == 0 )
            *dst++ = data;
        else
        {
            data  &= 0x7fff;
            uint16_t count = *src++;
            while( dst<end_dst && count-- )
                *dst++ = data;
        }
    }
}
#定义NBR_16位_字400
typedef无符号短uint16_t;
//返回写入dst的字数(始终
//小于或等于NBR_(16位_字)
uint16\u t压缩(uint16\u t*src、uint16\u t*dst)
{
uint16_t*end=(src+NBR_16位字);
uint16_t*dst_begin=dst;
while(srcfor(temp=src+1;tempLZ77/78)相对容易编写

然而,考虑到您传输的数据量很小,可能根本不值得对其进行压缩。

如果数据“或多或少是随机的”,那么恐怕您压缩它的运气就不好了

更新


根据新的信息,我打赌你的LED显示屏不需要32k颜色。我想1024或256色调色板可能就足够了。因此,你可以通过一个简单的压缩方案(只需通过一个查找表映射每个单词,或者可能只是丢弃每个组件的LSB),即使对于完全不相关的像素值,这也能起作用。

首先要做的事情之一是将RGB转换为YUV,或YCrCb,或类似的顺序。完成后,通常可以将U和V(或Cr/Cb)通道的采样分为半分辨率。这在大多数类型的图像中都很常见(例如,JPEG和MPEG都能做到这一点,大多数数码相机中的传感器也是如此)

实际上,从只有800字节的数据开始,大多数其他形式的压缩都将是浪费时间和精力。在完成很多工作之前,您必须投入大量的工作(并且在Arduino上保持相当快的速度对任何人来说都不是一件小事)

编辑:好的,如果你绝对确定自己根本无法修改数据,事情很快就会变得更加困难。此时真正的问题是你在处理什么类型的输入。其他人已经提到了预测增量压缩的可能性——例如,基于前面的像素,预测他很可能是下一个,然后只编码预测值和实际值之间的差异。然而,要最大限度地利用预测值和实际值,通常需要通过某种基于熵的算法(如香农·范诺或哈夫曼压缩)来运行结果。不幸的是,这些算法通常不是解压最快的

如果您的数据大部分是图表或图形之类的东西,您可以期望有大面积的相同像素,那么运行长度(或运行结束)编码可以很好地工作。它的优点是解压非常简单

不过,我怀疑基于LZ的压缩是否能如此有效。基于LZ的压缩(通常)有效通过构建已看到的字节串字典,以及当/如果再次看到相同的字节串时,传输分配给前一个实例的代码,而不是重新传输整个字符串。问题是,无法传输未压缩的字节——首先发送表示该字节的码字字典。在你的字典里