I find myself converting 1D byte and single arrays to 2D by doing the following. I suspect it is probably as fast as other methods, but perhaps there is a cleaner simpler paradigm? (Linq?)
private static byte[,] byte2D(byte[] input, int height, int width)
{
byte[,] output = new byte[height, width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
output[i, j] = input[i * width + j];
}
}
return output;
}
private static Single[,] single2D(byte[] input, int height, int width)
{
Single[,] output = new Single[height, width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
output[i, j] = (Single)input[i * width + j];
}
}
return output;
}
This doesn't help with making the code inside the methods cleaner, but I noticed that you have 2 basically identical methods that differ only in their types. I suggest using generics.
This would let you define your method only once. Using the where keyword, you can even limit the kind of types you allow your method to work on.
private static T[,] Make2DArray<T>(T[] input, int height, int width)
{
T[,] output = new T[height, width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
output[i, j] = input[i * width + j];
}
}
return output;
}
You would call this method like this
int[] a; //or any other array.
var twoDArray = Make2DArray(a, height, width);
Buffer.BlockCopy(input, 0, output, 0, input.Length); is faster, but fastest is to not copy the array at all.
If you don't really need a separate 2D array, you can just access your 1D array like a 2D array trough a function, property, or custom type. For example:
class D2<T> {
T[] input;
int lenght0;
public d2(T[] input, int lenght0) {
this.input = input;
this.lenght0 = lenght0;
}
public T this[int index0, int index1] {
get { return input[index0 * this.lenght0 + index1]; }
set { input[index0 * this.lenght0 + index1] = value; }
}
}
...
byte[] input = { 1, 2, 3, 4 };
var output = new D2<byte>(input, 2);
output[1, 1] = 0; // now input is { 1, 2, 3, 0 };
Also, in .NET access to multidimensional arrays is a bit slower than access to jagged arrays
Generic function:
private static b[,] to2D<a, b>(a source, valueAt: Func<a, int, b>, int height, int width)
{
var result = new b[height, width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
result[i, j] = valueAt(source, i * width + j);
}
}
return result;
}
var bytes = to2D<byte[], byte>([], (bytes, at) => bytes[at], 10, 20);
I know I am late to the party, but if you want to access a 1d array, list, etc. like it were an n-dimensional array (without copying) you can use https://github.com/henon/SliceAndDice to do so without copying.
// create a 2D array of bytes from a byte[]
var a = new ArraySlice<byte>( new byte[100], new Shape(10,10));
// now access with 2d coordinates
a[7,9]=(byte)56;
Of course, everyone can do it for simple 2d, 3d, ... nd volumes easily. But this lib also allows to do slicing of n-dimensional arrays without copying.
Related
This question already has answers here:
Copy single row from multidimensional array into new one dimensional array
(3 answers)
Closed 1 year ago.
Having the following:
int[,] a = new int[4, 2];
int[] b = new int[2];
how do I copy values from b into the first element of a? What's wrong with b.CopyTo(a[0])?
You can access a only by using 2 coordinates (so a[x,y]) because it is defined using 2 dimensions.
Try using int[][] a instead, if you do that then a becomes an array containing 1-dimensional subarrays, and then you can use 1 coordinate to access a subarray.
Example code:
int[][] a = new int[4][];
a[0] = new int[2];
int[] b = new int[2];
Note that after this, when I try do to b.CopyTo(a[0]) I get a "The call is ambiguous " compilation error (in .NET 5) because there two different extension methods that both match the CopyTo signature...
What's wrong with b.CopyTo(a[0])?
A is a two dimensional array, so you need two indices, i.e. a[0,0] = b[0]
Instead of using the built in multidimensional array I would suggest using a wrapper around a 1D array instead, with a indexer something like this:
public T this[int x, int y]
{
get => Data[y * Width + x];
set => Data[y * Width + x] = value;
}
This has the advantage of easier interoperability, since many system exposes 2D buffers of various kinds as 1D data + size. This allows copying data to be done by a block copy instead of copying element by element.
For primitives array types you can define extension methods for packing or unpacking arrays using the Buffer.BlockCopy();
static class Program
{
static void Main(string[] args)
{
int[,] A = new[,] { { 1, 2 }, { 3, 4 } };
int[] data = A.PackMarix();
int[,] B = data.UnPackMarix(2, 2);
Console.WriteLine(B);
}
public static int[,] UnPackMarix(this int[] data, int rows, int columns)
{
int[,] result = new int[rows, columns];
int bytes = Buffer.ByteLength(data);
Buffer.BlockCopy(data, 0, result, 0, bytes);
return result;
}
public static int[] PackMarix(this int[,] data)
{
int[] result = new int[data.Length];
int bytes = Buffer.ByteLength(data);
Buffer.BlockCopy(data, 0, result, 0, bytes);
return result;
}
}
For non-primitive types you have to do the copying manually
public static T[,] UnPackMarix<T>(this T[] data, int rows, int columns)
{
var result = new T[rows, columns];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
result[i, j] = data[i * columns + j];
}
}
return result;
}
public unsafe static T[] PackMarix<T>(this T[,] data)
{
var result = new T[data.Length];
int rows = data.GetLength(0);
int columns = data.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
result[i * columns + j] = data[i, j];
}
}
return result;
}
This has been posted on SO before but I couldn't find the old post. Anyway, use the Microsoft High Performance toolkit. It has spans for 2D memory. With that you can do this:
int[,] a = new int[4, 2];
int[] b = { 1, 2 };
var spanB = b.AsSpan();
var spanA = a.AsSpan2D();
spanB.CopyTo(spanA.GetRowSpan(0));
foreach (var i in spanA)
Console.WriteLine(i);
I have array with data. Array length equals 25 elements. I would like create matrix (5X5). How I can do this in C#? Please help.
Translating a single dimension array into a multi dimension array is straight forward.
public static T getEntry<T>(this T[] array, int column, int row, int width)
{
return array[column+row*width];
}
Add wrapper classes and/or validation as desired.
Usage example:
var array=Enumerable.Range(1,25).ToArray();
for (int row = 0; row < 5; row ++)
{
for (int column = 0; column < 5; column ++)
{
Console.WriteLine("Value in column {0}, row {1} is {2}", column, row, array.getEntry(column,row));
}
}
You can use Buffer.BlockCopy
using System;
class Test
{
static double[,] ConvertMatrix(double[] flat, int m, int n)
{
if (flat.Length != m * n)
{
throw new ArgumentException("Invalid length");
}
double[,] ret = new double[m, n];
// BlockCopy uses byte lengths: a double is 8 bytes
Buffer.BlockCopy(flat, 0, ret, 0, flat.Length * sizeof(double));
return ret;
}
static void Main()
{
double[] d = { 2, 5, 3, 5, 1, 6 };
double[,] matrix = ConvertMatrix(d, 3, 2);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine("matrix[{0},{1}] = {2}", i, j, matrix[i, j]);
}
}
}
}
As #Taemyr suggest you can simply use indexing to simulate the structure of the matrix. If you need to access the element at row 2, col 3 in a 5 by 5 matrix simply access index 2*5+3 of your array. (row * # of cols + col)
If you want to split your array into a 2D array you can do so using the following code:
public static T[,] Matrix<T>(T[] arr, int rows) {
var cols = arr.Length / rows;
var m = new T[rows, cols];
for (var i = 0; i < arr.Length; i++)
m[i / cols, i % cols] = arr[i];
return m;
}
Really I'm trying to apply 3X3 Median Filtering by C# and depending on my understanding the concepts of Median Filtering I wrote the following code but when I'm running it the Form hangs. I think have some problem in the last nested for loop but i don't know where is the error or the wrong in applying the Median concepts!
public static Bitmap MedianFiltering(Bitmap bm)
{
List<int> termsList = new List<int>();
Bitmap res, temp;
Color c;
int counter = 0;
//Convert to Grayscale
for (int i = 0; i < bm.Width; i++)
{
for (int j = 0; j < bm.Height; j++)
{
c = bm.GetPixel(i, j);
byte gray = (byte)(.333 * c.R + .333 * c.G + .333 * c.B);
bm.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
}
}
temp = bm;
//applying Median Filtering
for (int i = 0; i <= temp.Width - 3; i++)
for (int j = 0; j <= temp.Height - 3; j++)
{
for (int x = i; x <= i + 2; x++)
for (int y = j; y <= j + 2; y++)
{
c = temp.GetPixel(x, y);
termsList.Add(c.R);
counter++;
}
int[] terms = termsList.ToArray();
Array.Sort<int>(terms);
Array.Reverse(terms);
int color = terms[4];
temp.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
counter = 0;
}
res = temp;
return res;
}
Thanks.
You are not clearing the termsList after each pixel processing. This is causing the list to keep growing. Sorting and reversing the list will keep taking longer and longer times. This will also cause incorrect results since you only want to get the median of the 9 pixels related to the current pixel.
Simply clear the list like this:
...
int[] terms = termsList.ToArray();
termsList.Clear();
...
UPDATE:
I did more optimization for the code:
public static void MedianFiltering(Bitmap bm)
{
List<byte> termsList = new List<byte>();
byte[,] image = new byte[bm.Width,bm.Height];
//Convert to Grayscale
for (int i = 0; i < bm.Width; i++)
{
for (int j = 0; j < bm.Height; j++)
{
var c = bm.GetPixel(i, j);
byte gray = (byte)(.333 * c.R + .333 * c.G + .333 * c.B);
image[i, j] = gray;
}
}
//applying Median Filtering
for (int i = 0; i <= bm.Width - 3; i++)
for (int j = 0; j <= bm.Height - 3; j++)
{
for (int x = i; x <= i + 2; x++)
for (int y = j; y <= j + 2; y++)
{
termsList.Add(image[x, y]);
}
byte[] terms = termsList.ToArray();
termsList.Clear();
Array.Sort<byte>(terms);
Array.Reverse(terms);
byte color = terms[4];
bm.SetPixel(i + 1, j + 1, Color.FromArgb(color, color, color));
}
}
Please note that in your original method, you returned a Bitmap. I removed this.
Please note that temp = bm; does not create a copy of the Bitmap. It is just pointing the temp variable to the same object (that is pointed by bm). So in your original method, you returned the exact object that is passed in the method parameter. To use the new method pass the Bitmap and then the bitmap it self will be modified (this is also true for your method).
This enhanced performance 4 times on my machine.
What I did is mainly read the bitmap data into a byte array instead of using the Bitmap it self to read/write data multiple times.
If you need to further enhance the performance, take a look at this question.
I have a function which is applied on each element of a 2D array (double[,]), but only along a given dimension.
I had to create two functions because I don't know how to pass the desired dimension to the method as a parameter. I ended up with a "vertical_foo" and a "horizontal_foo" functions, which are almost identical to each other:
private double[,] vertical_foo (double[,] a) {
int height = a.GetLength(0);
int width = a.GetLength(1);
var result = new double[height, weight];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Here I use first ("i") dimension
int before = Math.Max(i-1, 0);
int after = Math.Min(i+1, height-1);
result[i,j] = (a[after, j] - a[before, j]) * 0.5;
}
}
return result;
}
private double[,] horizontal_foo (double[,] a) {
int height = a.GetLength(0);
int width = a.GetLength(1);
var result = new double[height, weight];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Here I use second ("j") dimension
int before = Math.Max(j-1, 0);
int after = Math.Min(j+1, height-1);
result[i,j] = (a[i, after] - a[i, before]) * 0.5;
}
}
return result;
}
I would like to have a signature like this, where the second parameter is the dimension on which I want to apply the indexing:
private double[,] general_foo (double[,] a, int dimension) {}
Any suggestion is much welcome!
I'll take a stab at this:
private double[,] general_foo(double[,] a, int dimension)
{
var w = a.GetLength(0);
var h = a.GetLength(1);
var result = new double[w, h];
var otherDimension = 1 - dimension; // NOTE only works for 2D arrays
var otherDimensionLength = a.GetLength(otherDimension);
var dimensionLength = a.GetLength(dimension);
for (int i = 0; i < dimensionLength; i++)
{
for (int j = 0; j < otherDimensionLength; j++)
{
var setIndexes = new int[2] { j, j };
setIndexes[dimension] = i;
var beforeIndexes = new int[2] { j, j };
beforeIndexes[dimension] = Math.Max(i - 1, 0);
var afterIndexes = new int[2] { j, j };
afterIndexes[dimension] = Math.Min(i + 1, dimensionLength - 1);
var beforeValue = (double)a.GetValue(beforeIndexes);
var afterValue = (double)a.GetValue(afterIndexes);
result.SetValue((afterValue - beforeValue) * 0.5, setIndexes);
}
}
return result;
}
Here's a more generic method. It uses a few lambdas, so the it might also help you understand the use of lambdas a bit also.
// Iterates through every item in a multidementional array array
private Array MutateArray<T>(Array a, Func<T, int[], T> selector)
{
var rank = a.Rank;
var lengths = Enumerable.Range(0, a.Rank)
.Select(r => a.GetLength(r))
.ToArray(); // Get length of a in each dimension
var result = Array.CreateInstance(typeof(T), lengths);
var index = new int[a.Rank];
foreach (T item in a) // flattens array
{
result.SetValue(selector(item, index), index);
// Get next index value (I'm sure this could be improved)
for (var d = 0; d < rank; d++)
{
if (index[d] == lengths[d] - 1)
{
index[d] = 0;
}
else
{
index[d]++;
break;
}
}
}
return result;
}
// Your "foo" method
private double[,] generic_foo(double[,] a, int d)
{
var upperD = a.GetUpperBound(d);
return (double[,])MutateArray<double>(a, (x, i) =>
{
var prev = i.ToArray(); // clone
prev[d] = Math.Max(prev[d] - 1, 0);
var next = i.ToArray(); // clone
next[d] = Math.Min(next[d] + 1, upperD);
var prevVal = (double)a.GetValue(prev);
var nextVal = (double)a.GetValue(next);
return (nextVal - prevVal) * 0.5;
});
}
Would it be acceptable to do something along these lines?
int before_i = i, after_i = i;
int before_j = j, after_j = j;
switch( dimension ) {
case 0:
before_i = Math.max(i-1,0);
after_i = Math.min(i+1, width-1);
break;
case 1:
before_j = Math.max(j-1,0);
after_j = Math.min(j+1, height-1);
break;
}
result[ i, j ] = (a[after_i, after_j] - a[before_i,before_j]) * 0.5
It's not terribly pretty, but at least this way you don't need two functions.
You could pass in a delegate to extract the dimension you're interested in? (or a lambda)
Func<int[,],int,int[]> accessor here indicates the signature of a function (where the last template parameter is the return type)
private void Working()
{
DoSomething(GetRow,1);
}
So, in this example, you want the "DoSomething" worker to work on a row.
private void DoSomething(Func<int[,],int,int[]> accessor, int Idx)
{
int[,] theData = {{1,1,1,1,1},{2,2,2,2,2}};
int[] someData = accessor(theData,Idx);
}
public int[] GetRow(int[,] data,int index)
{
List<int> numbers = new List<int>();
for (int i = 0; i < data.GetLength(1); i++)
{
numbers.Add(data[index, i]);
}
return numbers.ToArray();
}
In the above example, you get a one dimensional array of 2,2,2,2,2
I'm addressing the general case of extracting a particular part of a multidimensional array here... The method/ lambda you pass in extracts the meaningful part of data...
I would like to do the following:
Create three dimesinal array in c# code like this:
var myArray = new short[x,y,z];
UnanagedFunction(myArray);
Pass it to unmanaged code (c++) like this:
void UnmanagedFunction(short*** myArray)
{
short first = myArray[0][0][0];
}
UPDATED
When I try the following code I have runtime error:
Attempted to read or write to protected memory.
Thank you!!!
IntPtr Array3DToIntPtr(short[, ,] Val)
{
IntPtr ret = Marshal.AllocHGlobal((Val.GetLength(0) + Val.GetLength(1) + Val.GetLength(2)) * sizeof(short));
int offset = 0;
for (int i = 0; i < Val.GetLength(0); i++)
{
for (int j = 0; j < Val.GetLength(1); j++)
{
for (int k = 0; k < Val.GetLength(2); k++)
{
Marshal.WriteInt16(ret,offset, Val[i, j, k]);
offset += sizeof(short);
}
}
}
return ret;
}
This has been tested and it works, the only limitation is that you have to call Marshal.FreeHGlobal on the array pointer when you are done with it or you will get a memory leak, I would also suggest that you change your c++ function so that it accepts the array dimensions or you will only be able to use 3d arrays of specific size
I'm writing it in pure C#, but if you take away the unsafe static from Func, the Func should work in C/C++. Be aware that I'm note sure sure it's ok ok to write this :-)
I'm using this Indexing into arrays of arbitrary rank in C#
static unsafe void Main(string[] args) {
var myArray = new short[5, 10, 20];
short z = 0;
for (int i = 0; i < myArray.GetLength(0); i++) {
for (int j = 0; j < myArray.GetLength(1); j++) {
for (int k = 0; k < myArray.GetLength(2); k++) {
myArray[i, j, k] = z;
z++;
}
}
}
// myArray[1, 2, 3] == 243
fixed (short* ptr = myArray) {
Func(ptr, myArray.GetLength(0), myArray.GetLength(1), myArray.GetLength(2));
}
}
// To convert to C/C++ take away the static unsafe
static unsafe void Func(short* myArray, int size1, int size2, int size3) {
int x = 1, y = 2, z = 3;
int el = myArray[x * size2 * size3 + y * size3 + z]; // el == 243
}