I'm working on a project that requires me to pass 2D arrays between C# and Unmanaged C++.
I need to do this for 2D integer array sand 2D float arrays but right now I'm stuck on the 2D integer arrays.
I have a pattern for 1D integer arrays working just fine....
My demo C# code looks like this
// Test 2D integer Array
int[,] cs2DIntArray = new int[5,2];
cs2DIntArray[0, 0] = 0;
cs2DIntArray[0, 1] = 1;
cs2DIntArray[1, 0] = 10;
cs2DIntArray[1, 1] = 11;
cs2DIntArray[2, 0] = 20;
cs2DIntArray[2, 1] = 21;
cs2DIntArray[3, 0] = 30;
cs2DIntArray[3, 1] = 31;
cs2DIntArray[4, 0] = 40;
cs2DIntArray[4, 1] = 41;
int my2DArrayIntReturn = tess.test2DIntArray(cs2DIntArray, 5, 2);
"tess" is a managed C++ Wrapper class and implements the test2DIntArray method like this,
int test2DIntArray(array<int, 2>^ my2DIntArray, int rows, int columns){
using System::Runtime::InteropServices::GCHandle;
using System::Runtime::InteropServices::GCHandleType;
GCHandle my2DIntArrayGCHandle = GCHandle::Alloc(my2DIntArray,GCHandleType::Pinned);
IntPtr my2DIntArrayPtr = my2DIntArrayGCHandle.AddrOfPinnedObject();
my2DIntArray[0, 0] = 0;
my2DIntArray[0, 1] = 11;
my2DIntArray[1, 0] = 110;
my2DIntArray[1, 1] = 111;
my2DIntArray[2, 0] = 120;
my2DIntArray[2, 1] = 121;
my2DIntArray[3, 0] = 130;
my2DIntArray[3, 1] = 131;
my2DIntArray[4, 0] = 140;
my2DIntArray[4, 1] = 141;
return pu->uTest2DIntArray((int*)my2DIntArrayPtr.ToPointer(),rows,columns);
};
pu is the unmanaged class and implements uTest2DIntArray like this
int UnmanagedModel::uTest2DIntArray(int* my2DIntArray, int arrayRows, int arrayColumns)
{
my2DIntArray[0,0] = 20;
my2DIntArray[0,1] = 21;
my2DIntArray[1,0] = 210;
my2DIntArray[1,1] = 211;
my2DIntArray[2,0] = 220;
my2DIntArray[2,1] = 221;
my2DIntArray[3,0] = 230;
my2DIntArray[3,1] = 231;
my2DIntArray[4,0] = 240;
my2DIntArray[4,1] = 241;
return my2DIntArray[1,1];
}
This compiles and runs without errors or warnings BUT when the code returns to C# only the first two values [0,0] and [0,1] reflect the changes made to the values in the unmanaged code as shown below. All of the other values reflect the changes made in the managed C++ method.
cs2DIntArray {int[5, 2]} int[,]
[0, 0] 240 int
[0, 1] 241 int
[1, 0] 110 int
[1, 1] 111 int
[2, 0] 120 int
[2, 1] 121 int
[3, 0] 130 int
[3, 1] 131 int
[4, 0] 140 int
[4, 1] 141 int
Can anyone see/explain what I'm doing wrong and what needs to be done to correct this code? I haven't coded in a while and I did spend quite a while looking for solutions on Google but can't quite get this work as desired.
Any guidance will be gratefully received.
Doug
Further information
If I change the indexing in the unmanaged code to use a single index (from 0 to 9) instead of a 2D index (0,0 to 4,1) then all of the values are updated correctly
In the debugger, when I look at the address of each array value[x,y] - they all show exactly the same address
Using 2D array indexing it seems like the first index is being completely ignored - the only the second index is being used and since this varies from 0 to 1 the code is simply overwriting the first two array values.
Which tells me I do have access to the correct memory for the array inside my unmanaged code, but I can't use 2D indexing to get to it. Which is a pain, and has to fixable.
c++ doesn't have 2-dimensional arrays. The comma-operator turns 4,0 into 0, so my2DIntArray[4,0] is equivalent to my2DIntArray[0].
Since my2DIntArray is a pointer to a one-dimensional array, you have to simulate 2 dimensions by manually calculating the index like this: my2DIntArray[line * columns + column]
Related
I'm having trouble while attempting to extract a row from my array. This is my code :
using System;
namespace C_sharp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!. This is the one !");
dynamic[] res = new Object[3];
res[0] = new int[2,2]{{3,2},{16,9}};
res[1] = new int[2,2]{{4,7},{6,29}};
res[2] = new int[2,2]{{30,29},{5,49}};
//dynamic resultat = res[0][0];
}
}
}
As you can see, at the end of my program, the contents of my local variable res looks like this :
[0] [dynamic]:{int[2, 2]}
[0, 0] [int]:3
[0, 1] [int]:2
[1, 0] [int]:16
[1, 1] [int]:9
[1] [dynamic]:{int[2, 2]}
[0, 0] [int]:4
[0, 1] [int]:7
[1, 0] [int]:6
[1, 1] [int]:29
[2] [dynamic]:{int[2, 2]}
[0, 0] [int]:30
[0, 1] [int]:29
[1, 0] [int]:5
[1, 1] [int]:49
Now, I want to put only the first row of res[0] in my variable resultat in order to get a 1D array. So, at the end of the process, resultat should be equal to :
[0] [int]:3
[1] [int]:2
I've already tried res[0][0,] and res[0][0:]. None of them worked. Any help ?
You can flatten 2d array using .Cast<int>() and then take first row using .Take(2):
const int arraySize = 2;
var resultat = (res[0] as int[,]).Cast<int>().Take(arraySize).ToArray();
In general case for an arbitrary row index you can use .Skip(arraySize * rowIndex)
If it is too slow for you, you may try Buffer.BlockCopy:
const int rowSize = 2;
const int intSize = 4;
int[] resultat = new int[rowSize];
Buffer.BlockCopy(res[0], 0, resultat, 0, intSize * rowSize);
In general case it would be
const int intSize = 4; // Size of integer type in bytes
int[,] matrix = res[0];
int rowSize = matrix.GetLength(1); // Get size of second 2d-array dimension
int rowIndex = 0; // Index of a row you want to extract
int[] resultat = new int[rowSize];
Buffer.BlockCopy(res[0], // Copy source
rowSize * intSize * rowIndex, // Source offset in bytes
resultat, // Copy destination
0, // Destination offset
intSize * rowSize); // The number of bytes to copy
Buffer.BlockCopy documentation
I played a bit around with the Kinect v2 and C# and tried to get a 512x424 pixel-sized image array that contains depth data aswell as the regarding color information (RGBA).
Therefore I used the MultiSourceFrameReader class to receive a MultiSourceFrame from which I got the ColorFrame and DepthFrame. With the methods ColorFrame.CopyConvertedFrameDataToArray() and DepthFrame.CopyFrameDataToArray() I received the arrays that hold color and depth information:
// Contains 4*1920*1080 entries of color-info: BGRA|BGRA|BGRA..
byte[] cFrameData = new byte[4 * cWidth * cHeight];
cFrame.CopyConvertedFrameDataToArray(cFrameData, ColorImageFormat.Bgra);
// Has 512*424 entries with depth information
ushort[] dFrameData = new ushort[dWidth* dHeight];
dFrame.CopyFrameDataToArray(dFrameData);
Now I would have to map the color-quadruples that live within the ColorFrame-data-array cFrameData to each of the entries of the DepthFrame-data-array dFrameData but that's where I'm stuck. Output should be an array that is 4 times (RGBA/BGRA) the size of the dFrameData array and contains the color information to each pixel of the depth-frame:
// Create the array that contains the color information for every depth-pixel
byte[] dColors = new byte[4 * dFrameData.Length];
for (int i = 0, j = 0; i < cFrameData.Length; ++i)
{
// The mapped color index. ---> I'm stuck here:
int colIx = ?;
dColors[j] = cFrameData[colIx]; // B
dColors[j + 1] = cFrameData[colIx + 1]; // G
dColors[j + 2] = cFrameData[colIx + 2]; // R
dColors[j + 3] = cFrameData[colIx + 3]; // A
j += 4;
}
Does anyone have any suggestions?
I also took a look at the Kinect-SDK's CoordinateMappingBasics example but they did it vice versa for the 1920x1080 pixel-sized image which I already got to work.
Edit
I recognized that I should be able to get the mapped color information by using the ColorSpacePoint-struct which contains the X and Y coordinates to the specific color pixel. Therefore I set up the points like..
// Lookup table for color-point information
ColorSpacePoint[] cSpacePoints = new ColorSpacePoint[dWidth * dHeight];
this.kinectSensor.CoordinateMapper.MapDepthFrameToColorSpace(dFrameData, cSpacePoints);
.. and tried to access the color information like ..
int x = (int)(cSpacePoints[i].X + 0.5f);
int y = (int)(cSpacePoints[i].Y + 0.5f);
int ix = x * cWidth + y;
byte r = cFrameData[ix + 2];
byte g = cFrameData[ix + 1];
byte b = cFrameData[ix];
byte a = cFrameData[ix + 3];
.. but I'm still getting the wrong colors. Mostly white ones.
Well, I figured it out by myself. The error was trivial. As the array is not a pixel-array where one entry contains RGBA information but a byte array where each entry represents either R, G, B or A I had to multiply the index by the bytes-per-pixel value which in this case is 4. So the solution looks like:
int ix = (x * cWidth + y) * 4;
byte r = cFrameData[ix + 2];
byte g = cFrameData[ix + 1];
byte b = cFrameData[ix];
byte a = cFrameData[ix + 3];
I have a 2d array of UInt16s which I've converted to raw bytes - I would like to take those bytes and convert them back into the original 2D array. I've managed to do this with a 2d array of doubles, but I can't figure out how to do it with UInt16.
Here's my code:
UInt16[,] dataArray;
//This array is populated with this data:
[4 6 2]
[0 2 0]
[1 3 4]
long byteCountUInt16Array = dataArray.GetLength(0) * dataArray.GetLength(1) * sizeof(UInt16);
var bufferUInt16 = new byte[byteCountUInt16Array];
Buffer.BlockCopy(newUint16Array, 0, bufferUInt16, 0, bufferUInt16.Length);
//Here is where I try to convert the values and print them out to see if the values are still the same:
UInt16[] originalUInt16Values = new UInt16[bufferUInt16.Length / 8];
for (int i = 0; i < 5; i++)
{
originalUInt16Values[i] = BitConverter.ToUInt16(bufferUInt16, i * 8);
Console.WriteLine("Values: " + originalUInt16Values[i]);
}
The print statement does not show the same values as the original 2d array. I'm pretty new to coding with bytes and UInt16 so most of this I'm learning in the process.
*Also, I know the last chunk of my code isn't putting values into a 2d array like the original array - right now I'm just trying to print out the values to see if they even match the original data.
If what you want is just to cast UInt16[,]->Byte, and then Byte->UInt16 you can do another Block copy, which is very fast at run-time, code should look like this:
UInt16[,] dataArray = new UInt16[,] {
{4, 6, 2},
{0, 2, 0},
{1, 3, 4}
};
for (int j = 0; j < 3; j++)
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Value[" + i + ", " + j + "] = " + dataArray[j,i]);
}
}
long byteCountUInt16Array = dataArray.GetLength(0) * dataArray.GetLength(1) * sizeof(UInt16);
var bufferUInt16 = new byte[byteCountUInt16Array];
Buffer.BlockCopy(dataArray, 0, bufferUInt16, 0, bufferUInt16.Length);
//Here is where I try to convert the values and print them out to see if the values are still the same:
UInt16[] originalUInt16Values = new UInt16[bufferUInt16.Length / 2];
Buffer.BlockCopy(bufferUInt16, 0, originalUInt16Values, 0, BufferUInt16.Length);
for (int i = 0; i < 5; i++)
{
//originalUInt16Values[i] = BitConverter.ToUInt16(bufferUInt16, i * 8);
Console.WriteLine("Values---: " + originalUInt16Values[i]);
}
by the way, you only divided each UInt16 into two bytes, so you should calculate your new size dividing by two, not eight
The program
public static void Main(string[] args)
{
UInt16[,] dataArray = new ushort[,]{ {4,6,2}, {0,2,0}, {1,3,4}};
//This array is populated with this data:
long byteCountUInt16Array = dataArray.GetLength(0) * dataArray.GetLength(1) * sizeof(UInt16);
var byteBuffer = new byte[byteCountUInt16Array];
Buffer.BlockCopy(dataArray, 0, byteBuffer, 0, byteBuffer.Length);
for(int i=0; i < byteBuffer.Length; i++) {
Console.WriteLine("byteBuf[{0}]= {1}", i, byteBuffer[i]);
}
Console.WriteLine("Byte buffer len: {0} data array len: {1}", byteBuffer.Length, dataArray.GetLength(0)* dataArray.GetLength(1));
UInt16[] originalUInt16Values = new UInt16[byteBuffer.Length / 2];
for (int i = 0; i < byteBuffer.Length; i+=2)
{
ushort _a = (ushort)( (byteBuffer[i]) | (byteBuffer[i+1]) << 8);
originalUInt16Values[i/2] = _a;
Console.WriteLine("Values: " + originalUInt16Values[i/2]);
}
}
Outputs
byteBuf[0]= 4
byteBuf[1]= 0
byteBuf[2]= 6
byteBuf[3]= 0
byteBuf[4]= 2
byteBuf[5]= 0
byteBuf[6]= 0
byteBuf[7]= 0
byteBuf[8]= 2
byteBuf[9]= 0
byteBuf[10]= 0
byteBuf[11]= 0
byteBuf[12]= 1
byteBuf[13]= 0
byteBuf[14]= 3
byteBuf[15]= 0
byteBuf[16]= 4
byteBuf[17]= 0
Byte buffer len: 18 data array len: 9
Values: 4
Values: 6
Values: 2
Values: 0
Values: 2
Values: 0
Values: 1
Values: 3
Values: 4
You see that a ushort, aka UInt16 is stored in a byte-order in which 4 = 0x04 0x00, which is why I chose the conversion formula
ushort _a = (ushort)( (byteBuffer[i]) | (byteBuffer[i+1]) << 8);
Which will grab the byte at index i and take the next byte at i+1 and left shift it by the size of a byte (8 bits) to make up the 16 bits of a ushort. In orhter words, ushort _a = 0x[second byte] 0x[first byte], which is then repeated. This conversion code is specific for the endianess of the machine you are on and thus non-portable.
Also I fixed the error where the byteBuffer array was to big because it was multiplied with factor 8. A ushort is double the size of a byte, thus we only need factor 2 in the array length.
Addressing the title of your question (Convert byte[] to UInt16):
UInt16 result = (UInt16)BitConverter.ToInt16(yourByteArray, startIndex = 0);
Your casting up so you should be able to do things implicitly
var list = new List<byte> { 1, 2 ,
var uintList = new List<UInt16>();
//Cast in your select
uintList = list.Select(x => (UInt16)x).ToList();
I am new to Unity3D and c#. I am tinkering with storing some grid positions within a 2d array however I've run into
the array index is out of range
error and I don't know why:
public int[,] myArray;
myArray = new int[,]{
{0,375},
{75,300},
{150,225},
{225,150},
{300,75},
{375,0}
};
Debug.Log(myArray[1,4]); // array index is out of range... why? I expected to get 75.
Here are some other resources I was looking at for help:
http://wiki.unity3d.com/index.php/Choosing_the_right_collection_type
https://msdn.microsoft.com/en-us/library/2yd9wwz4.aspx
You have a 2D array which is 6x2 - not one which is 2x6. Each "subarray" you're specifying in the initialization is one "row", if you think of accessing the array by array[row, column].
So for example, myArray[0, 1] is 375 - the second element of the first "row", which is { 0, 375 }.
Basically, you need to pivot either your array initialization, or your array access. So if you really want a 2x6 array, you'd need:
myArray = new int[,] {
{ 0, 75, 150, 225, 300, 375 },
{ 375, 300, 225, 150, 75, 0 }
};
... or you could keep the existing initialization, and access myArray[4, 1].
The C# specification explains it like this:
For a multi-dimensional array, the array initializer must have as many levels of nesting as there are dimensions in the array. The outermost nesting level corresponds to the leftmost dimension and the innermost nesting level corresponds to the rightmost dimension. The length of each dimension of the array is determined by the number of elements at the corresponding nesting level in the array initializer. For each nested array initializer, the number of elements must be the same as the other array initializers at the same level. The example:
int[,] b = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
creates a two-dimensional array with a length of five for the leftmost dimension and a length of two for the rightmost dimension:
int[,] b = new int[5, 2];
and then initializes the array instance with the following values:
b[0, 0] = 0; b[0, 1] = 1;
b[1, 0] = 2; b[1, 1] = 3;
b[2, 0] = 4; b[2, 1] = 5;
b[3, 0] = 6; b[3, 1] = 7;
b[4, 0] = 8; b[4, 1] = 9;
Is one of these decidedly faster?
var scan0 = (uint*)bitmapData.Scan0;
int length = pixels.Length;
for (int i = 0; i < length; i++)
{
uint j = scan0[i];
float a = (j >> 24) / 255f;
pixels[i] = new Vector(
(j >> 16 & 0xff) * a / 255,
(j >> 8 & 0xff) * a / 255,
(j & 0xff) * a / 255);
}
versus
var scan0 = (byte*)bitmapData.Scan0;
int length = pixels.Length * 4;
for (int i = 0; i < length; i += 4)
{
float a = scan0[i + 3] / 255f;
pixels[i / 4] = new Vector(
scan0[i + 2] * a / 255,
scan0[i + 1] * a / 255,
scan0[i] * a / 255);
}
In a 32 bit application, the second is about 2.5 times faster than the first. In a 64 bit application, the second is about 25% faster than the first.
Note that there is a bug in your second code. As you are adding four in each iteration, you will place the objects in every fourth item in the pixels array, and cause an IndexOutOfRangeException exception when it runs out of array.
Slightly faster (about 5%) than the second is to move the pointer for each pixel:
byte* scan0 = (byte*)bitmapData.Scan0;
for (int i = 0; i < pixels.Length; i++) {
float a = scan0[3] / 255f;
pixels[i] = new Vector(
scan0[2] * a / 255,
scan0[1] * a / 255,
scan0[0] * a / 255
);
scan0 += 4;
}
Note also that if you are reading data from a Bitmap image, it is not stored as a continuous array of pixel data. There may be padding between the scan lines, so the code can only read pixels from a single scan line, it can not safely read data from an entire image.
Edit:
Also, I just realised that you put the length of the array in a variable and used that in the loop. That will just make the code slower instead of faster, as the compiler can't optimise away the range check on the array accesses.
I think the bit shift "Your first solution" is faster. however you can test it by using Stopwatch. Start the stopwatch before the call the method, run the method multiple time, and then stop the watch and check its ElapcedMilliseconds. Like:
System.Diagnostics.Stopwatch watch = Stopwatch.StartNew();
//run your method that want to test its executable time multi time
for (int testIndex = 0; testIndex < 100; testIndex++)
{
TestWithShift();
}
watch.Stop();
Console.WriteLine("Test with shift time: {0}", watch.ElapcedMilliseconds);
And repeat the test for the other method. Hope that helps.