将 2 个连续字节转换为一个 int 值在 C# 中提高速度

Posted

技术标签:

【中文标题】将 2 个连续字节转换为一个 int 值在 C# 中提高速度【英文标题】:Convert 2 successive Bytes to one int value Increase speed in C# 【发布时间】:2015-11-11 11:56:44 【问题描述】:

我需要将两个 Bytes 组合成一个 int 值。

我从我的相机收到一个 16 位图像,两个连续的字节具有一个像素的强度值。我的目标是将这两个字节组合成一个“int”值。

我设法使用以下代码做到这一点:

for (int i = 0; i < VectorLength * 2; i = i + 2)

  NewImageVector[ImagePointer] = ((int)(buffer.Array[i + 1]) << 8) | ((int)(buffer.Array[i]));      
  ImagePointer++;

我的图像是 1280*960 所以 VectorLength==1228800 并且传入的缓冲区大小是 2*1228800=2457600 个元素...

有什么办法可以加快速度吗? 也许还有另一种方法,所以我不需要使用 for 循环。

谢谢

【问题讨论】:

.NET 4.5 有一个可能有用的 BitConverter 类 -> msdn.microsoft.com/en-us/library/system.bitconverter.aspx @nevada_scout BitConverter 做同样的事情,但需要额外的检查,这可能会使其变慢。 -- 但是它确实使用不安全的指针来访问数组元素,这是 OP 可以在这里做的优化。 当我说您想将每两个字节对转换为一个短字节(不是整数)时,我说得对吗?所以缓冲区[0]和缓冲区[1]应该进入NewImageVector[0],缓冲区[2]和缓冲区[3]进入NewImageVector[1](等等)?如果是这样,Buffer.BlockCopy 可能是你的朋友。 威廉 是的,你是对的。我知道 Buffer.BlockCopy 做了什么,但我怎样才能编辑它来做我想要的呢?有什么建议吗? @Spyros:我会写一个答案。 【参考方案1】:

你可以使用与 c 并集的等价物。我不确定是否更快,但更优雅:

[StructLayout(LayoutKind.Explicit)]
struct byte_array

  [FieldOffset(0)]
  public byte byte1;

  [FieldOffset(1)]
  public byte byte2;

  [FieldOffset(0)]
  public short int0;

像这样使用它:

byte_array ba = new byte_array();

//insert the two bytes
ba.byte1 = (byte)(buffer.Array[i]);
ba.byte2 = (byte)(buffer.Array[i + 1]);

//get the integer
NewImageVector[ImagePointer] = ba.int1;

您可以填充两个字节并使用 int。要找到更快的方法,请使用 StopWatch-Class 并像这样比较两种方法:

Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();

//The code

stopWatch.Stop();
MessageBox.Show(stopWatch.ElapsedTicks.ToString()); //Or milliseconds ,...

【讨论】:

感谢您的回答。但是我的 c# 水平不是很高,所以我不知道如何使用你的建议:(你能给我更多关于如何实现你的建议的信息吗?谢谢! 感谢您提供这个详细的示例。我会尽力让你知道。 :) 好的,事实证明,在我的机器上,我的代码运行时间约为 31 毫秒,而您的代码运行时间约为 19 毫秒。所以你建议让它更胖。非常感谢您的帮助!!!【参考方案2】:

假设您可以(重新)将NewImageVector 定义为short[],并且Buffer 中的每两个连续字节应转换为short(这基本上是您现在正在做的事情,只有您施放到int之后),你可以使用Buffer.BlockCopy为你做。

正如文档所述,您 Buffer.BlockCopy 将字节从一个数组复制到另一个数组,因此要将字节复制到缓冲区中,您需要执行以下操作:

Buffer.BlockCopy(Buffer, 0, NewImageVector, 0, [NumberOfExpectedShorts] * 2)

这告诉BlockCopy,你想从Buffer开始复制字节,从索引0开始,到NewImageVector,从索引0开始,你想复制[NumberOfExpectedShorts] * 2字节(因为每个短都是两个字节长)。

没有循环,但它确实取决于使用short[] 数组而不是int[] 数组的能力(实际上,首先要使用数组)。

请注意,这还要求Buffer 中的字节按little-endian 顺序排列(即Buffer[index] 包含低字节,buffer[index + 1] 包含高字节)。

【讨论】:

感谢您的建议,但这不会再次给我一个包含 2457600 个元素的短 [] 数组吗?我的意思是我想把 2457600 元素数组变成 1228800 元素数组... 这是迄今为止最快的选项。 @Spyros:不。 BlockCopy 复制字节。具有 1228800 个元素的 short[] 数组包含 2457600 个字节。这正是将被复制的内容。然后你最终得到 1228800 个短裤(每个 2 个字节,2457600 个字节)。 FWIW:它的调试版本在我的机器上运行 2ms ;) / 4200 ticks 在发布版本中。 这假定您的缓冲区包含小端顺序的字节。根据您提供的代码示例,它们已经是:您使用 ((buffer[index + 1]) 【参考方案3】:

您可以通过使用不安全的指针来迭代数组来实现小幅性能提升。以下代码假定 source 是输入字节数组(在您的情况下为 buffer.Array)。它还假设source 有偶数个元素。在生产代码中,您显然必须检查这些内容。

int[] output = new int[source.Length / 2];
fixed (byte* pSource = source)
fixed (int* pDestination = output)

    byte* sourceIterator = pSource;
    int* destIterator = pDestination;
    for (int i = 0; i < output.Length; i++)
    
        (*destIterator) = ((*sourceIterator) | (*(sourceIterator + 1) << 8));
        destIterator++;
        sourceIterator += 2;
    

return output;

【讨论】:

感谢您的回答!这个我也试试!!

以上是关于将 2 个连续字节转换为一个 int 值在 C# 中提高速度的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中将 2 个字节转换为 Short

如何在飞镖中将 2 个字节转换为 Int16?

在c#中对字节数组表示的Int32求和

将字节数组转换为 int

将 2 个字节转换为整数

(61)C#里怎么样转换字节数组与int类型