Efficient way to fill a 2d array with position based values - c#

There is the following code:
public int[,] GenerateArray(int size)
{
int[,] data = new int[size, size];
for (int x = 0; x < size; ++x)
for (int y = 0; y < size; ++y)
data[x, y] = x * y; // Example calculation function that depends on indexes
return data;
}
As you can see, I'm trying to fill a 2d array with values. Each element's value is calculated based on it's indexes. The amount of data that needs to be processed is enourmous, so it's taking some time to deal with it. Is there a more effecient method of achieving this? Like, using a GPU shader or something.

Can you use not array, but math function instead? If you need [2123,453] position you just calculate it's data using your func(2123,453). If you need to safe data you can safe just this modified section.
I think you can parallel calculations using GPU based Task.Run
What's the array size and calculation function?

Related

Dynamically create a point array

I would like to draw a curve using graphics.DrawCurve and I have x and y values in separate arrays (float x[] and float y[]). As DrawCurve needs point array as input, I need to convert or dynamically create the point array from the float arrays x and y. Is there any quick way for this?
I have around 20000 points for plotting the curve, Is it good idea to use graphics.DrawCurve on this purpose?
There are several questions to answer.
I couldn't find out how to allocate a point array.
Well, there is no difference in allocating a point array than to do so for any other kind of array:
const int size = 100;
Point[] pointArray = new Point[size];
But arrays are missing some "convenience". For example, they have a fixed size that you need to specify at the point of initialization (allocation). And if you need more space, you have to manually create a new (bigger) array and copy all the values from the old to the new.
That's why almost everywhere you would work with an array, you're probably better off using a list:
List<Point> pointList = new List<Point>();
And then, wherever you actually need to pass an array, you can simply get it via:
Point[] pointArray = pointList.ToArray();
dynamically collect the x and y values in the allocated point array
When you work with a list, that's as easy as:
pointList.Add(new Point(x, y));
We don't know how you fill your float x[] and float y[]. If possible, I'd not have those two separate arrays in the first place and simply use the pointList from the start. With one caveat: a System.Drawing.Point only works with int values, not with float values. So I assume you meant to collect int values for the coordinates.
dynamically create the point array from the float arrays x and y
If you cannot change the collection of the coordinates and have to work with those arrays, you can "zip" them together like this:
IEnumerable<Point> points = x.Zip(y, (xCoord, yCoord) =>
(new Point((int)xCoord, (int)yCoord));
Or, if you know you need an array:
Point[] pointArray = x.Zip(y, (xCoord, yCoord) =>
(new Point((int)xCoord, (int)yCoord)).ToArray();
For this, you need to be able to use System.Linq (in other words higher than .Net 2.0).
If you cannot use Linq, you have to do it "by hand". Something like:
int size = Math.Min(x.Length, y.Length);
Point[] pointArray = new Point[size];
for (int index = 0; index < size; index++)
{
pointArray[index] = new Point((int)x[index], (int)y[index]);
}
You can create List<Point> which is better than arrays.
List<Point> list = new List<Point>();
Point point=new Point(10,15);
list.Add(point);
You can get all x and y coordinates from two arrays and put together in list as points and than use this list to draw curve.
Given the values in both arrays have the same Index you can itereate over them, create points and add them to a list.
List<Point> points = new List<Point>();
for(int i = 0; i < x.Length; i++){
points.Add(new Point(x[i],y[i]);
}
I don't see a particular problem in using DrawCurve here.
If you need an array of Points use points.ToArray();

Converting 2D array to bitmap image. C#

I'm working on a project to show a 2D world generation process in steps using bitmap images.
Array data is stored in this way:
Main.tile[i, j].type = x;
With x being an integer value >= 0.
Basically i and j are changed every time the program loops using for-loops, and the following statement is run after certain conditions are met during the loop process at the end of the loop.
So, a possible sequence could be:
Main.tile[4, 67].type = 1;
Main.tile[4, 68].type = 1;
Main.tile[4, 69].type = 0;
And so on.
I tried several methods of directly modifying the bitmap image once the array was changed/updated (using Bitmap.SetPixel), but this seemed way to slow to be useful for a 21k,8k pixel resoltion bitmap.
I'm looking for a way to digest the whole array at the end of the whole looping process (not after each individual loop, but between steps), and put colored points (depending on the value of the array) accordingly to i, j (as if it were a coordinate system).
Are there any faster alternatives to SetPixel, or are there easier ways to save an array to a bitmap/image file?
Change your array to one dimension array and apply all operation on the one dimension array and ONLY if you want to
display the image change it back to 2 dimension.
How to change whole array from 2D to 1D:
byte[,] imageData = new byte[1, 2]
{
{ 1, 2 }
{ 3, 4 }
};
var mergedData = new byte[ImageData.Length];
// Output { 1, 2, 3, 4 }
Buffer.BlockCopy(imageData, 0, mergedData, 0, imageData.Length);
From 2D to 1D:
// depending on whether you read from left to right or top to bottom.
index = x + (y * width)
index = y + (x * height)
From 1D to 2D:
x = index % width
y = index / width or
x = index / height
y = index % height
I hope this will solve your problem!

Eigenvector and Eigenvalue of 8 X 8 matrix

I have a 8 x 8 matrix of floating point numbers and need to calculate eigenvector and eigenvalue from it. This is for feature reduction using PCA (Principal Component Analysis) and is one hell of a time consuming job if done by traditional methods. I tried to use power method as, Y = C*X where X is my 8 X 8 matrix.
float[,] XMatrix = new float[8, 1];
float[,] YMatrix = new float[8, 1];
float max = 0;
XMatrix[0, 0] = 1;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 1; j++)
{
for (int k = 0; k < 8; k++)
{
YMatrix[i, j] += C[i, k] * XMatrix[k, j];
if (YMatrix[i, j] > max)
max = YMatrix[i, j];
}
}
}
I know it is incorrect but cannot figure it out. I need help for using a power method or perhaps more effective way of calculating it.
Thanks in advance.
To retrieve the eigenvalues/eigenvectors in an efficent manner (i.e. fast!) for any size (dense) matrix, is not entirely trivial. I would suggest you use something like the QR algorithm (although this maybe overkill for a one-off calculation of a single 8x8 matrix).
The QR algorithm computes a Schur decomposition of a matrix. It is certainly one of the
most important algorithm in eigenvalue computations. However, it is applied to dense matrices only (as stated above).
The QR algorithm consists of two separate stages. First, by means of a similarity
transformation, the original matrix is transformed in a finite number of steps to Hessenberg
form or – in the Hermitian/symmetric case – to real tridiagonal form. This first stage of
the algorithm prepares its second stage, the actual QR iterations that are applied to the
Hessenberg or tridiagonal matrix.
The overall complexity (number of floating points) of the algorithm is O(n3). For a good explanation of this algorithm see here. Or searches for eigenvalue algorithm in Google should provide you with many alternative ways of calculating your required eigenvalues/vectors.
Also, I have not looked into this in detail, but Math.NET a free library may help you here...

Hough Circle in c# , dynamic memory

I have problem in dynamic memory allocation getting data from matrix
Image image_gray = new Image("im1.jpg");
Matrix circles = new Matrix(100, 1, 3);
Question 1: How can I locate dynamic memory because I don't know the number of circles?
Emgu.CV.CvInvoke.cvHoughCircles(image_gray, circles, HOUGH_TYPE.CV_HOUGH_GRADIENT,
2, 100, 200, 100, 10, 500);
Question 2: Now circle is matrix with [100 ,3], How can I get
point center= Round (circle[i][1], circle[i][1])
How can I get
int radius= circle[i][2];
what should my for loop look like to get data from matrix and casting should be point and int.
I tried already (NOT WORKING / ERROR)
for (int i=0; i < circles.Rows; i++)
{ Matrix entry = circles.GetRow(i);
float x = entry[0];
float y = entry[1];
float r = entry[2];} // NOT WORKING
because instead of copying (required) only (i) row it copies whole matrix( circles) and float x=......gives errors
No overload for method 'this' takes '1' arguments
please help me in this regard
regards
sorry to answer my question. please give some hint to dynamic memory allocation and matrix data
The documentation suggests that it will grow the matrix to fit, but it also contradicts that, so honestly, I would try a 1 row 1 col matrix on an image with more circles and see what it gives you. I see that you're using Matrix type - I don't know how you convert to the IntPtr needed by cvHoughCircles, but it should be straight forward to iterate over each row and pull out the results, which are 3 floats: (x, y, r) -
for (int i=0; i < circles.Cols; i++) {
Matrix<float> entry = circles.GetRow(i);
float x = entry[0]; // guessing here - the doc'n is truly awful
float y = entry[1];
float r = entry[2];
}

Precision error on matrix multiplication

Coding a matrix multiplication in my program, I get precision errors (inaccurate results for large matrices).
Here's my code. The current object has data stored in a flattened array, row after row. Other matrix B has data stored in a flattened array, column after column (so I can use pointer arithmetic).
protected double[,] multiply (IMatrix B)
{
int columns = B.columns;
int rows = Rows;
int size = Columns;
double[,] result = new double[rows,columns];
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < columns; col++)
{
unsafe
{
fixed (float* ptrThis = data)
fixed (float* ptrB = B.Data)
{
float* mePtr = ptrThis + row*rows;
float* bPtr = ptrB + col*columns;
double value = 0.0;
for (int i = 0; i < size; i++)
{
value += *(mePtr++) * *(bPtr++);
}
result[row, col] = value;
}
}
}
}
}
Actually, the code is a bit more complicated : I do the multiply thing for several chunks (so instead of having i from 0 to size, I go from localStart to localStop), then sum up the resulting matrices.
My problem : for a big matrix I get precision error :
NUnit.Framework.AssertionException: Error at (0,1)
expected: <6.4209571409444209E+18>
but was: <6.4207619776304906E+18>
Any idea ?
Perhaps all you have to do is use Kahan summation. But you can never expect to get exactly a specific result with floating-point math.
Turns out it was just ... a bug. Ended up that instead of having :
float* mePtr = ptrThis + row*rows;
float* bPtr = ptrB + col*columns;
The correct indexers for my rows were :
float* mePtr = ptrThis + row * size;
float* bPtr = ptrB + col * size;
Sorry for that, not really fancy answer here. But thanks for the help !
I originally stated that you should convert the floats to doubles. However, as you point out that will break your algorithm.
You could try:
value += (double)*(mePtr++) * (double)*(bPtr++);
A problem with your code as it now stands is that the multiplication is being done in float precision then added to a double. Casting to double first will help to some extent.
It might be clearer to use intermediate double variables - but that's up to you.
If this doesn't give you the desire accuracy then you'll need to consider using decimal instead of double. However, this may result in a performance hit so do some benchmarks first.
Hem, it doesn't really solve your problem but in NUnit, you can allow to have a precision error and choose the value of this epsilon
As a starting point, use double everywhere instead of float.
At the very least, you should be using doubles throughout. Floats are very imprecise.
This is a phenomenon called "Matrix Creep" which happens gradually during matrix manipulations if you don't consistently normalize your matrices.

Categories