Comment remodeler un tableau en c #

J’ai un tableau d’octets 3D en c # que j’ai lu à partir d’un bitmap:

byte[w, h, 3] 

Quelle est la manière la plus simple et la plus conviviale de transformer ce tableau en une forme 2D (linéaire)?

 byte[w*h, 3] 

En d’autres termes, je souhaite conserver le nombre de canaux (entités) mais sous une forme linéaire (plutôt que carrée)

Laissez-moi essayer d’illustrer les entrées et les sorties souhaitées:

consortingbution:

 |(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)| 

notez que arr [0, 0, 0] = r1, arr [0, 0, 1] = g1, arr [0, 0, 2] = b1, etc.

et sortie:

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

Cela semble fonctionner correctement , car le tableau est déjà dans la bonne forme en mémoire :

 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)); 

Pour ceux qui sont intéressés: Pour ce qui est de faire si vous voulez vraiment transposer un tableau 2D en 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]; } 

Cela devrait tirer parti de la mise en cache dans la CPU. J'ai seulement effectué des tests limités sur ce sujet - cela pourrait encore être lent. Essayez de le modifier si c'est le cas.
Vous pouvez (de manière non sortingviale) l’étendre à un tableau 3D.

Buffer.BlockCopy fera. Au moins, cela fonctionne dans ce test simple.

 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!"); } } 

Cela dit, je n’utiliserais pas Buffer.BlockCopy de cette façon, à moins d’être absolument sûr qu’il n’y avait pas d’occasions étranges de bourrage, etc. Bien que Buffer.BlockCopy soit certainement plus rapide que la boucle explicite équivalente, il ne devrait pas affecter matériellement l'exécution de votre programme. Sauf si vous effectuez cette conversion dans un morceau de code appelé très, très souvent ... auquel cas vous avez de plus gros problèmes.

Je suggérerais d'écrire la boucle explicite.