C#中的ushort数组压缩

时间:2014-11-04 22:00:19

标签: c# image-compression

我有一个ushort数组(实际上是来自相机的图像),我希望在持久存储之前进行无损压缩。我正在使用System.IO.Compression.GZipStream中提供的GZipStream函数。据我所知,这种方法要求我将ushort数组转换为字节数组。我的解决方案似乎运行正常,但并不像我想的那么快。图像大小约为2 MB,压缩时间范围(在我的慢速机器上)为200 - 400 msecs,解压缩时间范围为100 - 200 msecs。寻找改善我的表现的建议。

public static class Zip
    {

        public static ushort[] Decompress_ByteToShort(byte[] zippedData)
        {
            byte[] decompressedData = null;            

            using (MemoryStream outputStream = new MemoryStream())
            {
                using (MemoryStream inputStream = new MemoryStream(zippedData))
                {
                    using (GZipStream zip = new GZipStream(inputStream, CompressionMode.Decompress))
                    {
                        zip.CopyTo(outputStream);
                    }
                }
                decompressedData = outputStream.ToArray();
            }

            ushort[] decompressShort = new ushort[decompressedData.Length / sizeof(ushort)];
            Buffer.BlockCopy(decompressedData, 0, decompressShort, 0, decompressedData.Length);

            return decompressShort;
        }



        public static byte[] Compress_ShortToByte(ushort[] plainData)
        {
            byte[] compressesData = null;

            byte[] uncompressedData = new byte[plainData.Length * sizeof(ushort)];
            Buffer.BlockCopy(plainData, 0, uncompressedData, 0, plainData.Length * sizeof(ushort));

            using (MemoryStream outputStream = new MemoryStream())
            {
                using (GZipStream zip = new GZipStream(outputStream, CompressionMode.Compress))
                {
                    zip.Write(uncompressedData, 0, uncompressedData.Length);
                }
                //Dont get the MemoryStream data before the GZipStream is closed 
                //since it doesn’t yet contain complete compressed data.
                //GZipStream writes additional data including footer information when its been disposed
                compressesData = outputStream.ToArray();
            }

            return compressesData;
        }

    }

2 个答案:

答案 0 :(得分:1)

我看到的方法中的第一个问题是你使用字节数组而不是直接加载和写入文件。 使用较小的临时缓冲区并直接以块的形式读取\写入流和文件应该要快得多。

这里我提出了一些函数和重载,可用于从字节数组,字节数组,流,流,文件和文件解压缩。

性能提升应为10%至20%。 尝试根据需要调整常量。 我使用DeflateStream而不是GZipStream,这会稍微提高性能。 如果您愿意,可以返回GZipStream。

我尝试将字节转换为ushort,并尝试使用byte []版本的代码,速度提高了约10%。 直接访问文件而不是将其加载到大缓冲区应该可以进一步提高性能。

警告:这种以这种方式读取和写入图像的方法不是小端/大端不可知 - 这意味着从Intel / AMD机器保存的文件与ARM机器不兼容,例如在某些情况下平板电脑!正如旁注:)

    /// <summary>The average file size, used to preallocate the right amount of memory for compression.</summary>
    private const int AverageFileSize = 100000;

    /// <summary>The default size of the buffer used to convert data. WARNING: Must be a multiple of 2!</summary>
    private const int BufferSize = 32768;


    /// <summary>Decompresses a byte array to unsigned shorts.</summary>
    public static ushort[] Decompress_ByteToShort(byte[] zippedData)
    {
        using (var inputStream = new MemoryStream(zippedData))
            return Decompress_File(inputStream);
    }

    /// <summary>Decompresses a file to unsigned shorts.</summary>
    public static ushort[] Decompress_File(string inputFilePath)
    {
        using (var stream = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read))
            return Decompress_File(stream);
    }

    /// <summary>Decompresses a file stream to unsigned shorts.</summary>
    public static ushort[] Decompress_File(Stream zippedData)
    {
        using (var zip = new DeflateStream(zippedData, CompressionMode.Decompress, true))
        {
            // Our temporary buffer.
            var buffer = new byte[BufferSize];

            // Read the number of bytes, written initially as header in the file.
            zip.Read(buffer, 0, sizeof(int));
            var resultLength = BitConverter.ToInt32(buffer, 0);

            // Creates the result array
            var result = new ushort[resultLength];

            // Decompress the file chunk by chunk
            var resultOffset = 0;
            for (; ; )
            {
                // Read a chunk of data
                var count = zip.Read(buffer, 0, BufferSize);
                if (count <= 0)
                    break;

                // Copy a piece of the decompressed buffer
                Buffer.BlockCopy(buffer, 0, result, resultOffset, count);

                // Advance counter
                resultOffset += count;
            }

            return result;
        }
    }

    /// <summary>Compresses an ushort array to a file array.</summary>
    public static byte[] Compress_ShortToByte(ushort[] plainData)
    {
        using (var outputStream = new MemoryStream(AverageFileSize))
        {
            Compress_File(plainData, outputStream);
            return outputStream.ToArray();
        }
    }

    /// <summary>Compresses an ushort array directly to a file.</summary>
    public static void Compress_File(ushort[] plainData, string outputFilePath)
    {
        using (var stream = new FileStream(outputFilePath, FileMode.OpenOrCreate, FileAccess.Write))
            Compress_File(plainData, stream);
    }

    /// <summary>Compresses an ushort array directly to a file stream.</summary>
    public static void Compress_File(ushort[] plainData, Stream outputStream)
    {
        using (var zip = new DeflateStream(outputStream, CompressionMode.Compress, true))
        {
            // Our temporary buffer.
            var buffer = new byte[BufferSize];

            // Writes the length of the plain data
            zip.Write(BitConverter.GetBytes(plainData.Length), 0, sizeof(int));

            var inputOffset = 0;
            var availableBytes = plainData.Length * sizeof(ushort);
            while (availableBytes > 0)
            {
                // Compute the amount of bytes to copy.
                var bytesCount = Math.Min(BufferSize, availableBytes);

                // Copy a chunk of plain data into the temporary buffer
                Buffer.BlockCopy(plainData, inputOffset, buffer, 0, bytesCount);

                // Write the buffer
                zip.Write(buffer, 0, bytesCount);

                // Advance counters
                inputOffset += bytesCount;
                availableBytes -= bytesCount;
            }
        }
    }

答案 1 :(得分:0)

有GZipStream构造函数(Stream,CompressionLevel),您可以更改CompressionLevel以加快压缩,此枚举中的级别为Fastest

相关文件的链接:
http://msdn.microsoft.com/pl-pl/library/hh137341(v=vs.110).aspx
http://msdn.microsoft.com/pl-pl/library/system.io.compression.compressionlevel(v=vs.110).aspx