如何在c#中重塑数组

我在c#中有一个3D字节数组,我从位图中读取了这个数组:

byte[w, h, 3] 

将此数组重塑为2D(线性)forms的最简单,性能更友好的方法是什么?

 byte[w*h, 3] 

换句话说,我想保持通道数(特征)但是呈线性形状(而不是方形)

让我试着说明输入和期望的输出:

输入:

 |(r1,g1,b1) (r2,g2,b2) (r3,g3,b3)| |(r4,g4,b4) (r5,g5,b5) (r6,g6,b6)| |(r7,g7,b7) (r8,g8,b8) (r9,g9,b9)| 

注意arr [0,0,0] = r1,arr [0,0,1] = g1,arr [0,0,2] = b1等。

并输出:

 |(r1,g1,b1) (r2,g2,b2) (r3,g3,b3) (r4,g4,b4) (r5,g5,b5) (r6,g6,b6) ...| 

这似乎工作正常,因为数组在内存中已经是正确的形状

 var a = new byte[2, 2, 2] { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }; var b = new byte[2 * 2, 2]; //sizeof(byte) is obviously 1 here, but I put it there for documentation Buffer.BlockCopy(a, 0, b, 0, a.Length * sizeof(byte)); 

对于那些感兴趣的人:至于如果你真的想要将2D数组转换成1D怎么办:

 byte[,] a = { {1, 2}, {3, 4}, {5, 6}, }; var b = new byte[a.GetLength(1) * a.GetLength(0)]; //Transpose const int R_STRIDE1 = 8; //Tune this for your CPU const int C_STRIDE1 = 8; //Tune this for your CPU //You should hoist the calls to GetLength() out of the loop unlike what I do here for (int r1 = 0; r1 < a.GetLength(0); r1 += R_STRIDE1) for (int c1 = 0; c1 < a.GetLength(1); c1 += C_STRIDE1) for (int r2 = 0; r2 < R_STRIDE1; r2++) for (int c2 = 0; c2 < C_STRIDE1; c2++) { var r = r1 + r2; var c = c1 + c2; if (r < a.GetLength(0) && c < a.GetLength(1)) b[c * a.GetLength(0) + r] = a[r, c]; } 

这应该利用CPU中的缓存。 我对此进行了有限的测试 - 它仍然可能很慢。 如果是的话,尝试调整它。
你可以(有点非平凡地)将它扩展到3D数组。

Buffer.BlockCopy会做到这一点。 至少,它适用于这个简单的测试。

 byte[, ,] src = new byte[10, 10, 3]; byte[,] dest = new byte[100, 3]; List srcList = new List(); Random rnd = new Random(); for (int i = 0; i < 10; ++i) { for (int j = 0; j < 10; ++j) { for (int k = 0; k < 3; ++k) { byte b = (byte)rnd.Next(); src[i, j, k] = b; srcList.Add(b); } } } Buffer.BlockCopy(src, 0, dest, 0, 300); List destList = new List(); for (int i = 0; i < 100; ++i) { for (int j = 0; j < 3; ++j) { destList.Add(dest[i, j]); } } // See if they're in the same order for (int i = 0; i < srcList.Count; ++i) { Console.WriteLine("{0,3:N0} - {1,3:N0}", srcList[i], destList[i]); if (srcList[i] != destList[i]) { Console.WriteLine("ERROR!"); } } 

也就是说,我不会以这种方式使用Buffer.BlockCopy ,除非我绝对确定没有填充问题的奇怪情况等等。虽然Buffer.BlockCopy肯定比等效的显式循环快,但它不应该实质上影响程序的运行时间。 除非你在一段非常经常被调用的代码中进行这种转换......在这种情况下你会遇到更大的问题。

我建议编写显式循环。