I figured out a method that works well for me. I'll try to explain my solution down here in-case anyone else needs help with this topic. Note that this probably isn't the best solution but it does get the job done.
I started with my source array float[,] sourceArray
and a larger array that I want to scale to float[,] targetArray
I then loop through every tile(array element) in my target array and get the percentage value between it's center and the total height and width of the scale target. I then call a method that returns the calculated value, passing in the percentage, source array, the width of the source array, and the height of the source array.
for(float x = 0, x < scaleWidth, x++)
{
for(float y = 0, y < scaleHeight, y++)
{
Vector2 percentage = new Vector2((x+0.5)/scaleWidth, (y+0.5)/scaleHeight);
targetArray[x,y] = GetScaleValueAt(percentage, sourceArray, sourceWidth, sourceHeight);
}
}
My GetScaleValueAt()
method returns the requested, correctly scaled value. First it finds a corresponding location in the source array based on the percentage. Also it finds the tile that the location is inside of.
public float GetScaleValueAt(float percent, float[,] source, int width, int height)
{
Vector2 location = new Vector2(width * percent.X, height * percent.Y);
Point centerTile = new Point((int)Math.Floor(loc.X), (int)Math.Floor(loc.Y));\
Then I use another method to get all the tiles adjacent to the center one (including the center tile)
List<Point> tiles = GetIncNeighborhood(centerTile.X, centerTile.Y, width, height);
Next I iterate through this list and populate a second list with WeightedPair
's which is just a class or struct with two float values - float value, weight
that are accesible. The weight
is calculated from the inverse of the distance between location
and each tile. I also save the total of weighted values.
List<WeightedPair> weightValues = new List<WeightedPair>();
float weightedTotal = 0;
foreach(Point p in tiles)
{
Vector2 distance = new Vector2();
distance.X = System.Math.Abs(loc.X - p.X);
distance.Y = System.Math.Abs(loc.Y - p.Y);
float inverseDist = 1 / distance.Length();
float value = source[p.X, p.Y];
weightedTotal += invDist;
weightValues.Add(new WeightedPair(value, invDist));
}
Finally, I loop through weightValues
list and calculate the value by multiplying each value
by it's corresponding weight/weightedTotal
.
float finalValue = 0;
foreach(WeightedPair w in weightValues)
{
finalValue += w.value * (w.weight/weightedTotal);
}
return finalValue;
}
The result is an image similar to the smaller version in overall shape and complexity with some minor artifacts and fidelity issues. It's not as good as standard image processing techniques but it works perfectly for me. Hope this helps someone.