Interpolating 2d array of points - c#

I have a 2d array of points (each point stored in my Points struct, which contains only 3 properties: X Y Z), with size of 128x128. I want to interpolate (stretch) this 2d array to greater size (132x132 for example). So far I have managed to interpolate X and Y coordinates of each point using linear interpolation (simply taking coordinates into array of double, interpolating it, and returning it to new 2d array of Points). Here is the code of linear interpolation:
private double[] InterpolateArray(double[] array, int newLength)
{
double[] result = new double[newLength];
result[0] = array[0];
result[newLength - 1] = array[array.Length - 1];
for (int i = 1; i < newLength - 1; i++)
{
double jd = ((double)i * (double)(array.Length - 1) / (double)(newLength - 1));
int j = (int)jd;
result[i] = array[j] + (array[j + 1] - array[j]) * (jd - (double)j);
}
return result;
}
Problem is that I have no idea how to interpolate Z coordinates of each point. Could that be done same way like X and Y coordinates? Or completely different approach is needed?
Edit: code for my Points struct:
public struct Points
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public Points(double X, double Y, double Z)
{
this.X = X;
this.Y = Y;
this.Z = Z;
}
}
And code which does interpolation (or should do it at least):
public Points[,] Interpolate(Points[,] array, int newWidth, int newHeight)
{
Points[,] result = new Points[newWidth, newHeight];
double[] bufferBefore = new double[domes.GetLength(0)];
double[] bufferAfter = new double[newWidth];
for (int i = 0; i < domes.GetLength(1); i++)
{
for (int j = 0; j < domes.GetLength(0); j++)
{
bufferBefore[j] = domes[j, i].X;
}
bufferAfter = InterpolateArray(bufferBefore, newWidth);
for (int j = 0; j < newWidth; j++)
{
result[j, i].X = bufferAfter[j];
}
}
bufferBefore = new double[domes.GetLength(1)];
bufferAfter = new double[newHeight];
for (int i = 0; i < newWidth; i++)
{
for (int j = 0; j < domes.GetLength(1); j++)
{
bufferBefore[j] = result[i, j].Y;
}
bufferAfter = InterpolateArray(bufferBefore, newHeight);
for (int j = 0; j < newHeight; j++)
{
result[i, j].Y = bufferAfter[j];
}
}
return result;
}

I cannot see any way your current code is correct. In the second part you are doing bufferBefore[j] = result[i, j].Y;, but as far as I can see this has not been set anywhere before.
So when interpolating you need to interpolate all the values. So you would need to repeat the interpolation for each of x/y/z for each direction.
This however be done a bit simpler by implement the multiply operator for your point struct. This could allow you to do the interpolation for both x/y at once with code looking something like this:
public static Vector3 BilinearSample(this Vector3[,] self, in Vector2 point)
{
var xi = (int)Math.Floor(point.X);
var xi1 = xi + 1;
var xf = point.X - xi;
var yi = (int)Math.Floor(point.Y);
var yi1 = yi + 1;
var yf = point.Y - yi;
// You might need to add checks to ensure the sample is fully inside the image etc.
var v1 = self[xi, yi];
var v2 = self[xi1, yi];
var v3 = self[xi, yi1];
var v4 = self[xi1, yi1];
// Do the bilinear sample
var xfn1 = 1 - xf;
var v5 = v1 * xfn1 + v2 * xf;
var v6 = v3 * xfn1 + v4 * xf;
var result = v5 * (1 - yf) + v6 * yf;
return result;
}
I'm using System.Numerics instead of Point , but the principle is the same. Note that the above code would be identicalif you change the input/output type to Vector2 or double.
Also note that if the values represents direction or rotation you need to be careful, since the resulting directions might not be normalized after interpolation, and might even be zero.

Related

Parallize elementwise matrix (2dArray) calculations

This is my first question and I'm relatively new to C#. (Excuse my bad English)
I'm writing a template matching algorithm in C# using the .NET Framework with a WindowsForms Application in Visual Studio. Sadly the new indices and ranges functions from C#8.0, especially the range operator (..), didn't get implemented in the .NET Framework. I know there is a workaround for this as you can see in this thread but it is not supported by Microsoft. So I'm searching for another way to parallelize my elementwise 2dArray (matrix) calculations to make my program faster.
In my program, I'm calculating the differential square (ds) of an area (with the size of my template) inside a 2dArray (my image) and a 2dArray (my template). These values a written to a new 2dAary (DS) which holds all differential squares in the corresponding positions to the image. I can search the indices of DS where the differential square is minimal which is equal to the matching position (highest correspondence between template and image) of the template inside the image.
In python the calculation of DS is very quick using the index range operator (:) and will look like this:
H,W = I.shape # read out Height H & Width W from Image I
h,w = T.shape # read out Height h & Width w from Template T
for i in range(H-h+1):
for j in range(W-w+1):
DS[i,j] = np.sum((I[i:i+h,j:j+w] - T)**2)
But in C# I have to make the calculation of DS elementwise therefore it looks like this and takes for ever:
int Tw = template.Width;
int Th = template.Height;
int Iw = image.Width;
int Ih = image.Height;
int d = 0;
int[,] ds = new int[Tw, Th];
int[,] DS = new int[Iw - Tw + 1, Ih - Th + 1];
for (int y = 0; y < Ih - Th + 1; y++)
{
for (int x = 0; x < Iw - Tw + 1; x++)
{
for (int yT = 0; yT < Th; yT++)
{
for (int xT = 0; xT < Tw; xT++)
{
d = I[x + xT, y + yT] - T[xT, yT];
ds[xt, yt] = d * d;
}
}
int sum = ds.Cast<int>().Sum();
DS[x, y] = sum;
}
}
I know that I could use threads but that would be a little complex for me.
Or maybe I could use CUDA with my Nvidia GPU to speed things up a little.
But I am asking you and myself is there another way to parallelize (optimize) my elementwise 2dArray calculations?
I look forward to any help.
Many thanks in advance!!!
EDIT:
Here I have a working example of my code for a .NET Framework Console App. As you can see I make a lot of elementwise 2d and 3d Array calculations which I would like to process in parallel (or perform them faster in any other way):
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TemplateMatcher_Console
{
class Program
{
public static int[,,] bitmapToMatrix(Bitmap bmp)
{
int[,,] I = new int[bmp.Width, bmp.Height, 3];
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
Color pix = bmp.GetPixel(x, y);
I[x, y, 0] = Convert.ToInt32(pix.R);
I[x, y, 1] = Convert.ToInt32(pix.G);
I[x, y, 2] = Convert.ToInt32(pix.B);
}
}
return I;
}
public static int[] indexOfMiniumValue(int[,] matrix)
{
int value = 0;
int minValue = 999999999;
int minFirstIndex = 0;
int minSecondIndex = 0;
int[] ij = new int[2];
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
value = matrix[i, j];
if (value < minValue)
{
minValue = value;
minFirstIndex = i;
minSecondIndex = j;
}
}
}
ij[0] = minFirstIndex;
ij[1] = minSecondIndex;
return ij;
}
public static void Print2DArray<T>(T[,] matrix)
{
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
Console.Write(matrix[i, j] + "\t");
}
Console.WriteLine();
}
}
static void Main(string[] args)
{
// Deklaration & Eingabe
Console.WriteLine("Type the filepath for your image and then press Enter");
string im = Console.ReadLine();
Console.WriteLine("\nType the filepath for your template and then press Enter");
string temp = Console.ReadLine();
Bitmap template = new Bitmap(#temp);
Bitmap image = new Bitmap(#im);
int Tw = template.Width;
int Th = template.Height;
int Iw = image.Width;
int Ih = image.Height;
int[,] ds = new int[Tw, Th];
int[,] DS = new int[Iw - Tw + 1, Ih - Th + 1];
int[,,] DS_rgb = new int[Iw - Tw + 1, Ih - Th + 1, 3];
int[] xy = new int[2];
// Verarbeitung
// int[,,] I = Array.ConvertAll(image_I, new Converter<byte, int>(Convert.ToInt32));
int[,,] I = bitmapToMatrix(image);
int[,,] T = bitmapToMatrix(template);
for (int rgb = 0; rgb < 3; rgb++)
{
for (int y = 0; y < Ih - Th + 1; y++)
{
for (int x = 0; x < Iw - Tw + 1; x++)
{
//DS_rgb[x, y, rgb] = (I[x .. x + template.Width, y .. y + template.Height, rgb] - T[0 .. template.Width, 0 .. template.Height, rgb]);
for (int yT = 0; yT < Th; yT++)
{
for (int xT = 0; xT < Tw; xT++)
{
ds[xT, yT] = (I[x + xT, y + yT, rgb] - T[xT, yT, rgb]) * (I[x + xT, y + yT, rgb] - T[xT, yT, rgb]);
}
}
int sum = ds.Cast<int>().Sum();
DS_rgb[x, y, rgb] = sum;
}
}
}
//DS[.., ..] = DS_rgb[.., .., 0] + DS_rgb[.., .., 1] + DS_rgb[.., .., 2];
for (int y = 0; y < Ih - Th + 1; y++)
{
for (int x = 0; x < Iw - Tw + 1; x++)
{
DS[x, y] = DS_rgb[x, y, 0] + DS_rgb[x, y, 1] + DS_rgb[x, y, 2];
}
}
//xy = DS.FindIndex(z => z == Math.Min(DS));
xy = indexOfMiniumValue(DS);
// Ausgabe
// Ausgeben der Matrix DS
/*
Console.WriteLine("\nMatrix with all differtial squares:");
Print2DArray(DS);
*/
Console.WriteLine($"\nPosition of your template in your image (upper left corner): ({xy[0]}, {xy[1]})");
Console.Write("\nPress any key to close the TemplateMatcher console app...");
Console.ReadKey();
}
}
}

how to continuously generate Perlin noise as an infinite map grows?

EDIT: I ended up using the FastNoise library found here: https://github.com/Auburns/FastNoise It has everything under the sun which someone might need to generate many different kinds of noise. As the title might suggest its also quite fast!
I'm creating a 2D infinitely, procedural generated world. I load and unload chunks from disc as the player moves. I'm using a cellular automata function to define how local tiles within each chunk are designed but I need noise (Perlin in this case) to define what biome type each chunk will be as new ones are created. I understand how I would translate decimals between 0 and 1 to represent this, my only issue is that the tutorial I followed on creating Perlin noise requires that you pass it a predefined 2d array and returns a noise array of the same size. Because my world grows dynamically I'm a bit confused on how I would use a fixed sized array to designate new chunk types.
Other answers I've seen don't cover exactly how to handle the infinite part of noise generation. My best guess is that I need to somehow generate or expand the noise with each newly created chunk although how I do this stumps me.
Here is some code I translated to C# from here: http://devmag.org.za/2009/04/25/perlin-noise/
admittedly some of the math here I don't fully understand yet, especially the bitwise function!
public class PerlinNoiseGenerator
{
public int OctaveCount { get; set; }
public float Persistence { get; set; }
public PerlinNoiseGenerator(int octaveCount, float persistence)
{
this.OctaveCount = octaveCount;
this.Persistence = persistence;
}
public float[,] GenerateWhiteNoise(int width, int height)
{
float[,] noiseFieldToReturn = new float[width, height];
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
noiseFieldToReturn[i, j] = (float)Game1.Utility.RGenerator.NextDouble() % 1;
}
}
return noiseFieldToReturn;
}
public float[,] SmoothNoiseField(float[,] whiteNoise, int octave)
{
int width = whiteNoise.GetLength(0);
int height = whiteNoise.GetLength(1);
float[,] smoothField = new float[width, height];
int samplePeriod = 1 << octave;
float sampleFrequency = 1.0f / samplePeriod;
for(int i =0; i < width; i++)
{
int samplei0 = (i / samplePeriod) * samplePeriod;
int samplei1 = (samplei0 + samplePeriod) % width;
float horizontalBlend = (i - samplei0) * sampleFrequency;
for(int j =0; j < height; j++)
{
int samplej0 = (j/samplePeriod) * samplePeriod;
int samplej1 = (samplej0 + samplePeriod) % height;
float verticalBlend = (j - samplej0) * sampleFrequency;
float top = LinearInterpolate(whiteNoise[samplei0, samplej0],
whiteNoise[samplei1, samplej0], horizontalBlend);
float bottom = LinearInterpolate(whiteNoise[samplei0, samplej1],
whiteNoise[samplei1, samplej1], horizontalBlend);
smoothField[i, j] = LinearInterpolate(top, bottom, verticalBlend);
}
}
return smoothField;
}
public float[,] GeneratePerlinNoise(float[,] baseNoise, int octaveCount)
{
int width = baseNoise.GetLength(0);
int height = baseNoise.GetLength(1);
float[][,] smoothNoise = new float[octaveCount][,];
float persistance = .5f;
for(int i =0; i < octaveCount;i++)
{
smoothNoise[i] = SmoothNoiseField(baseNoise, i);
}
float[,] perlinNoise = new float[width, height];
float amplitude = 1f;
float totalAmplitude = 0.0f;
for(int octave = octaveCount - 1; octave > 0; octave-- )
{
amplitude *= persistance;
totalAmplitude += amplitude;
for(int i =0; i < width;i++)
{
for(int j =0; j < height; j++)
{
perlinNoise[i, j] += smoothNoise[octave][i, j] * amplitude;
}
}
}
for(int i =0; i < width; i++)
{
for(int j =0; j < height; j++)
{
perlinNoise[i, j] /= totalAmplitude;
}
}
return perlinNoise;
}
public float LinearInterpolate(float a, float b, float alpha)
{
return a * (1 - alpha) + alpha * b;
}
}
This code should compile and produces a FIXED size array of noise
The main thing you want to make sure is that the starting random noise is pseudo random, so you always have a "fixed random value" for a coordinate.
It might be that you'd have to rewrite your random noise generator, using the coordinates as input. I imagine your maps have a random seed number, so you could use this post as a starting point, adding 1 factor:
A pseudo-random number generator based on 2 inputs
For a bit of inspiration for your map making, I wrote this article a while back: https://steemit.com/map/#beeheap/create-a-fantasy-grid-map-in-excel
Added after your comment: the only function you'd need to change is the GenerateWhiteNoise one. I don't speak C#, but this is the general idea:
GenerateWhiteNoise(int x_start_coord, int y_start_coord, int random_seed) {
int default_x_width = 100;
int default_y_heigth = 50;
float[,] noiseFieldToReturn = new float[width, height];
for (in x = x_start_coord; i < default_x_width + x_start_coord; x++)
{
for (in y = y_start_coord; i < default_y_width + y_start_coord; y++)
{
noiseFieldToReturn[i, j] = (float)pseudo_rnd_value(x, y, random_seed);
}
}
return noiseFieldToReturn;
}
That should give you the pseudo random values you need to build your map tiles, the only thing you need is the coordinate of the player (x and y).

Fast inversion of an axis of 3D data stored in a 1D array

I have a large dataset that represents a 3D image (approx 100,000,000 pixels). I want to invert the pixels along the 'z' axis of the image. My data is stored in a byte array where the data is ordered x, y, z (i.e [] = { (x=0,y,z=0), (x=1,y=0,z=0), (x=2,y=0,z=0) ...)
I can easily sort them using the following code, however I am looking to reduce computation time where possible (currently reporting around 7 seconds). I am considering using an array 'sort' function, but am not sure how to handle the indexing.
Here is my current code:
private int GetIndex(Image _image, int _x, int _y, int _z)
{
return (_z * _image.Size.X * _image.Size.Y) + (_y * _image.Size.X) + _x;;
}
private void InvertZ(Image _image)
{
for (int z = 0; z < _image.Size.Z/2; z++)
{
for (int y = 0; y < _image.Size.Y; y++)
{
for (int x = 0; x < _image.Size.X; x++)
{
int srcIndex = GetIndex(_image, x, y, z);
int destIndex = GetIndex(_image, x, y, _image.Size.Z - z - 1);
byte src = _image.Buffer[srcIndex];
byte dest = _image.Buffer[destIndex];
_image.Buffer[srcIndex] = dest;
_image.Buffer[destIndex] = src;
}
}
}
}
One solution is to copy each frame. Reduces the number of iterations drastically.
private void InvertZ(Image _image)
{
int frameSize = _image.Size.X * _image.Size.Y;
byte[] temp = new byte[frameSize];
for (int z = 0; z < _image.Size.Z / 2; z++)
{
int inverseZ = _image.Size.Z - z - 1;
Array.Copy(_image.Buffer, z * frameSize, temp, 0, frameSize);
Array.Copy(_image.Buffer, inverseZ * frameSize, _image.Buffer, z * frameSize, frameSize);
Array.Copy(temp, 0, _image.Buffer, inverseZ * frameSize, frameSize);
}
}
Runtime approx < 18 ms compared to 3175 ms.
This might be faster that your one loop solution even if it uses several loops, one for each axis.
There are 2 major speed enhancements (very common algorithm enhancements within image processing).
The Image is converted to a array for quick legwork
The index become partly precomputed within the the loops making sure the you calculate as much as possible as few times as possible. (no more use of the built-in thing in Image which is nice for one and another pixel but not suitable for the whole map)
I usually only do this work on 2d so the z axis is just added. it might be faster having it as the last loop. (fringe example running in 2d if y is before x then you loose about 30-40% speed because of the way memory/cache is built Src this happens at 3d as well (that's why I placed the z (levels/pages at the front))
Here is the code I would base my solution on.
private void InvertZ(Image _image)
{
byte[] array =imageToByteArray(_image);
int pageSize = _Image.Size.Y * _Image.Size.X;
for (int z = 0; z < _image.Size.Z/2; z++)
{
int level = z * pageSize;
int dstLevel = (_image.Size.Z - z - 1) * pageSize;
for (int x = 0; x < _image.Size.X; x++)
{
int Row = x*_Image.Size.Y;
int RowOnLevel = level + Row ;
int dstRowOnLevel = dstLevel + xRow;
for (int y = 0; y < _image.Size.Y; y++)
{
int srcIndex = RowOnLevel + y;
int destIndex = dstRowOnLevel + y;
byte tmpDest = array[destIndex];
array[destIndex] = array[srcIndex];
array[srcIndex] = tmpDest;
}
}
}
return byteArrayToImage(array);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
You can use the fact that the array layout is like this
Z Length
==== ======
[0] x * y
[1] x * y
[2] x * y
...
[z-1] x * y
This allows us to greatly reduce index calculations. We can use a variation of the classic O(N) reverse algorithm like this
static void InvertZ(Image _image)
{
int len = _image.Size.X * _image.Size.Y;
for (int lo = 0, hi = (_image.Size.Z - 1) * len; lo < hi; lo += len, hi -= len)
for (int i = 0; i < len; i++)
Swap(ref _image.Buffer[lo + i], ref _image.Buffer[hi + i]);
}
static void Swap<T>(ref T a, ref T b) { var c = a; a = b; b = c; }

c# feed a method with x and y values from a chart (polynomial calculation)

I have got this method to get a polynomial with my desired degree:
public static double[] Polyfit(double[] x, double[] y, int degree)
{
// Vandermonde matrix
var v = new DenseMatrix(x.Length, degree + 1);
for (int i = 0; i < v.RowCount; i++)
for (int j = 0; j <= degree; j++) v[i, j] = Math.Pow(x[i], j);
var yv = new DenseVector(y).ToColumnMatrix();
QR qr = v.QR();
// Math.Net doesn't have an "economy" QR, so:
// cut R short to square upper triangle, then recompute Q
var r = qr.R.SubMatrix(0, degree + 1, 0, degree + 1);
var q = v.Multiply(r.Inverse());
var p = r.Inverse().Multiply(q.TransposeThisAndMultiply(yv));
Console.WriteLine(p.Column(0).ToString());
return p.Column(0).ToArray();
}
How can I feed the method above with values from my chart (x and y)?
chart.Series[0].Points.... ?
I think you need this:
chart1.Series[0].YValueMembers
chart1.Series[0].XValueMember
The Points property is a getter, so you cannot set a new instance of DataPointCollection to it. You should however be able to access methods on the current DataPointCollection.
You could try something along the lines of:
chart.Series[0].Points.AddXY(double, double)
You would then iterate the array(s) and set the points manually.
MSDN DataPointCollection for more information.
A working solution is:
////generate polynomial of degree 4 fiting to the points
double[] arrayX = new double[chart.Series[0].Points.Count()];
double[] arrayY = new double[chart.Series[0].Points.Count()];
double[] arrayResult = { };
for (int i = 0; i < chart.Series[0].Points.Count(); i++)
{
arrayX[i] = chart.Series[0].Points[i].XValue;
arrayY[i] = chart.Series[0].Points[i].YValues[0];
}
arrayResult = Polyfit(arrayX, arrayY, 4);
foreach (double element in arrayResult)
{
MessageBox.Show(element.ToString());
}
double functionVarE = arrayResult[0];
double functionVarD = arrayResult[1];
double functionVarC = arrayResult[2];
double functionVarB = arrayResult[3];
double functionVarA = arrayResult[4];
double equationVar = 0;
//prepare the function series in the graph
if (chart.Series.IndexOf("function") < 0)
chart.Series.Add("function");
chart.Series[2].Points.Clear();
chart.Series[2].ChartType = SeriesChartType.Line;
for (int x = -500; x < 1000; x++) //hardcoding
{
equationVar = functionVarA * (Math.Pow(x, 4)) + functionVarB * (Math.Pow(x, 3)) + functionVarC * (Math.Pow(x, 2)) + functionVarD * x + functionVarE;
chart.Series[2].Points.AddXY(Convert.ToDouble(x), equationVar);
}
This is a working solution I coded. If you see any improvement feel free to tell me!

If Best Fit Straight Line the best method for prediction

I need to make prediction for a next point, based on given set of point samples on 2-d coordinate system.
I am using Best-Fit Straight Line method for such prediction.
Please let me know if there is method better than Best-Fit Straight Line?
My code is below:
public class LineEquation
{
public double m; //slope
public double c; //constant in y=mx+c
}
public class Point
{
public double x;
public double y;
}
public class BestFitLine
{
public Point[] points = new Point[7];
public void InputPoints(Point[] points)
{
for (int i = 0; i < points.Length; i++)
{
points[i] = new Point();
}
points[0].x = 12;
points[0].y = 13;
points[1].x = 22;
points[1].y = 23;
points[2].x = 32;
points[2].y = 33;
points[3].x = 42;
points[0].y = 23;
points[4].x = 52;
points[4].y = 33;
points[5].x = 62;
points[5].y = 63;
points[6].x = 72;
points[6].y = 63;
}
public LineEquation CalculateBestFitLine(Point[] points)
{
double constant = 0;
double slope=0;
for (int i = 0; i < points.Length - 1; i++)
{
for (int j = i + 1; j < points.Length; j++)
{
double m = (points[j].y - points[i].y) / (points[j].x - points[i].x);
double c = points[j].y - (m * points[j].x);
constant += c;
slope += m;
}
}
int lineCount =((points.Length-1)*points.Length)/2;
slope = slope / lineCount;
constant = constant / lineCount;
LineEquation eq = new LineEquation();
eq.c = constant;
eq.m = slope;
return eq;
}}
If your x coordinate is composed of dates, you can rely on generalized additive models with the following components :
- trend
- yearly profile
- weekly profile
- daily profile
GAM models are available in R, so I would advice you to use JRI in order to interface your java code with R.
Cheers
I think you could consider smoothing algorithms like Exponential Moving average to predict the near future data points,
http://en.wikipedia.org/wiki/Exponential_smoothing

Categories