I'm trying to do a pixel search in coordinates (x,y)
I need something like a function(int width, int height) that returns an array of points starting from the center.
if image has 1000x1000, i need to get [{500,500}, {501,500}, {501,501}, {500,501}, {499,501}, {499,500} ...]
Example:
Well, that was easier than I thought it would be.
static IEnumerable<Point> GetPixels(int size)
{
Point point = new Point(size/2, size/2);
yield return point;
int sign = 1;
for (int row = 1; row < size; row++)
{
// move right/left by row, and then up/down by row
for (int k = 0; k < row; k++)
{
point.Offset(sign*1, 0);
yield return point;
}
for (int k = 0; k < row; k++)
{
point.Offset(0, -sign*1);
yield return point;
}
sign *= -1;
}
// last leg to finish filling the area
for (int k = 0; k < size-1; k++)
{
point.Offset(sign*1, 0);
yield return point;
}
}
with the result (size=5)
{X=2,Y=2}
{X=3,Y=2}
{X=3,Y=1}
{X=2,Y=1}
{X=1,Y=1}
{X=1,Y=2}
{X=1,Y=3}
{X=2,Y=3}
{X=3,Y=3}
{X=4,Y=3}
{X=4,Y=2}
{X=4,Y=1}
{X=4,Y=0}
{X=3,Y=0}
{X=2,Y=0}
{X=1,Y=0}
{X=0,Y=0}
{X=0,Y=1}
{X=0,Y=2}
{X=0,Y=3}
{X=0,Y=4}
{X=1,Y=4}
{X=2,Y=4}
{X=3,Y=4}
{X=4,Y=4}
or graphically for size=50
The test code is simple enough
static void Main(string[] args)
{
foreach (var point in GetPixels(5))
{
Console.WriteLine($"{point}");
}
Console.WriteLine();
}
Related
I need to make a Jacobi Gauss program but I'm struggling with the start of it. We need to create a class which encapsulates a nxn matrix and stores it in a 2D array, with the default value being 3x3 with all values 0. We then have to add features to this and the rest of the Jacobi Gauss model. I've tried a few ways to make a matrix but I can't get one that relies on user input for size or defaults to a set size/values.
There are many ways to represent 2d matrix but the most simple is just as a native 2d array. By default a new array is filled with default values which for ints is zero. You can initialize yourself. Or, of course you can simply set the values after you create it.
Note in the first case I've created the array based off a integer. In this case for simplicity 1 value, obviously it does not have to be square.
static void Main(string[] _)
{
int dimensions = 3;
int[,] matrix = new int[dimensions, dimensions];
foreach (var v in matrix)
Console.WriteLine(v);
int[,] matrix2 = new int[,] { { 1,1,1},{ 2,2,2},{ 3,3,3} };
for (int x = 0; x < dimensions; ++x)
{
for (int y = 0; y < dimensions; ++y)
{
// matrix2[x,y] = whatever...
Console.WriteLine(matrix2[x, y]);
}
}
}
One option to wrap this in a class is to use a indexer method. For a simple square matrix with absolutely no error handling that might look like this:
public class MyMatrix
{
int[,] data = null;
public MyMatrix(int dims = 3)
{
this.data = new int[dims, dims];
}
public void SetDimensions(int dims)
{
if (this.data.GetLowerBound(0) != dims)
{
this.data = new int[dims, dims];
for (int x = 0; x < dims; ++x)
for (int y = 0; y < dims; ++y)
this.data[x, y] = 0;
}
}
public int this[int x, int y]
{
get { return this.data[x, y]; }
set { this.data[x, y] = value; }
}
public int Size => this.data.GetLowerBound(0);
}
static void Main(string[] _)
{
MyMatrix m = new MyMatrix(3);
for (int x = 0; x < m.Size; ++x)
{
for (int y = 0; y < m.Size; ++y)
{
// m[x,y] = whatever...
Console.WriteLine(m[x, y]);
}
}
}
I have a function which will find a smaller image within a larger image and return me it's position. I want to set a tolerance threshold so that even if a similar (but not exactly the same) is present, it returns it's position as well.
If possible I would also want it to work if the smaller image is rotated.
I tried finding edges in the image using OpenCV, but the edges in the haystack and those in the needle image are never the exact same and it never matches.
public Point? Find(Bitmap haystack, Bitmap needle)
{
if (null == haystack || null == needle)
{
return null;
}
if (haystack.Width < needle.Width || haystack.Height < needle.Height)
{
return null;
}
var haystackArray = GetPixelArray(haystack);
var needleArray = GetPixelArray(needle);
foreach (var firstLineMatchPoint in FindMatch(haystackArray.Take(haystack.Height - needle.Height), needleArray[0]))
{
if (IsNeedlePresentAtLocation(haystackArray, needleArray, firstLineMatchPoint, 1))
{
return firstLineMatchPoint;
}
}
return null;
}
private int[][] GetPixelArray(Bitmap bitmap)
{
var result = new int[bitmap.Height][];
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
for (int y = 0; y < bitmap.Height; ++y)
{
result[y] = new int[bitmap.Width];
Marshal.Copy(bitmapData.Scan0 + y*bitmapData.Stride, result[y], 0, result[y].Length);
}
bitmap.UnlockBits(bitmapData);
return result;
}
private IEnumerable<Point> FindMatch(IEnumerable<int[]> haystackLines, int[] needleLine)
{
var y = 0;
foreach (var haystackLine in haystackLines)
{
for (int x = 0, n = haystackLine.Length - needleLine.Length; x < n; ++x)
{
if (ContainSameElements(haystackLine, x, needleLine, 0, needleLine.Length))
{
yield return new Point(x, y);
}
}
y += 1;
}
}
private bool ContainSameElements(int[] first, int firstStart, int[] second, int secondStart, int length)
{
for (int i = 0; i < length; ++i)
{
if (first[i + firstStart] != second[i + secondStart])
{
return false;
}
}
return true;
}
private bool IsNeedlePresentAtLocation(int[][] haystack, int[][] needle, Point point, int alreadyVerified)
{
//we already know that "alreadyVerified" lines already match, so skip them
for (int y = alreadyVerified; y < needle.Length; ++y)
{
if ( ! ContainSameElements(haystack[y + point.Y], point.X, needle[y], 0, needle.Length))
{
return false;
}
}
return true;
}
How can I achieve this ?
For the first: You have to define your metric for comparing two pixels
I can imagine a distance in the cube defined by RGB, or a distance in the cylinder of HSV (HSV should be more accurate)
Example:
static double GetMetric(Pixel a, Pixel b)
{
double dR = a.R - b.R;
double dG = a.G - b.G;
double dB = a.B - b.B;
return Math.Sqrt(dR * dR + dG * dG + dB * dB);
}
Then just create a window search algorithm. Create window in the haste (same size as needle). Then try every possible position of window and calculate window distance as the sum of pixel distances.
You do not recalculate whole window. While moving window to the right, just recalculate and subtract left column (the one which was removed) and calculate and add right (new) column.
Then you need to remember minimal distance and its location and just compare it.
The result is the closest window to the needle. (Depends on used metric).
A simplified example:
static void Find(Bitmap Haste, Bitmap Needle)
{
//Simplified for Haste.Height = Needle.Height
//But Haste.Width > Needle.Width
int minX = 0;
int minY = 0;
double minMetric = double.MaxValue;
//Setup first window
double actualMetric = 0;
for (int i = 0; i < Needle.Width; i++)
{
for (int j = 0; j < Needle.Height; j++)
{
actualMetric += GetMatric(Needle.GetPixel(i, j), Haste.GetPixel(i, j));
}
}
minMetric = actualMetric;
//Move window to the right
for (int i = 0; i < Haste.Width - Needle.Width; i++)
{
for (int j = 0; j < Needle.Height; j++)
{
//Subtract left column pixel
actualMetric -= GetMatric(Needle.GetPixel(i, j), Haste.GetPixel(i, j));
//Add right column pixel
actualMetric += GetMatric(Needle.GetPixel(i + Needle.Width, j), Haste.GetPixel(i + Needle.Width, j));
}
//Compare
if(actualMetric < minMetric)
{
minX = i;
minY = 0; // Because Y is fixed while simplification Haste and Needle Height
}
}
}
I have a 2d boolean array that checks if the row of the columns are all true. right now I want to check that if a row is filled with all true. I want that row to go all false. and then I take the value above me. and shove it down. just like tetris. this is my pseudo code i made. can someone give me a hint and explanation about how to do it? and btw. if i filled the SECOND column with true. I'm afraid that the first column will also shift down regardless of his lowest column value.
[SerializeField]private int columns;
[SerializeField]private int rows;
private bool[,] grid;
private bool isRowTrue = true;
private int gridColumnCount = 0;
private int gridRowCount = 0;
private int combo = 0;
// Start is called before the first frame update
void Start()
{
grid = new bool[columns, rows];
for (int y = 0; y < grid.GetLength(1); y++)
{
for (int x = 0; x < grid.GetLength(0); x++)
{
grid[y, x] = false;
}
}
}
// Update is called once per frame
void Update()
{
CheckArrays();
}
private void CheckArrays()
{
for (int y = 0; y < grid.GetLength(1); y++)
{
for (int x = 0; x < grid.GetLength(0); x++)
{
if (grid[y, x] == false)
{
isRowTrue = false;
break;
}
}
if (isRowTrue == true)
{
Debug.Log(y + "TH Row Are All True");
for (int x = 0; x < grid.GetLength(0); x++)
{
grid[y, x] = false;
Debug.Log(grid[y, x]);
}
for (int yc = 0; yc < grid.GetLength(1); yc++)
{
for (int xc = 0; xc < grid.GetLength(0); xc++)
{
grid[yc, xc] = grid[yc - 1, xc - 1];
}
}
}
else
{
isRowTrue = true;
}
}
}
If you don't have a specific requirement to build this as a 2d array, this may be easier to reason about in a more object oriented way. For example, create a Row class that will hold an array of bool and have a method IsFull() which returns true if the entire array is true. Then you can hold a ArrayList of Row in your code above. Then, you can iterate over the rows and simply delete the row from the list whenever row.IsFull()==true, this should give you the effect that you are looking for.
I am practicing with 2D arrays and am making a program that separates a 2D array with random integer values into two separate arrays based on if the values are even or odd.
However, the program seems to be adding additional zeroes to each row in the even and odd arrays. What am I doing wrong?
I think the problem is in the sort() function where I determine the size of the even and odd arrays but I am not sure.
class Program
{
static void Main(string[] args)
{
int[,] arr = new int[10, 10];
// Fills 2D array with random values and prints them out
Random r = new Random();
for (int y = 0; y < arr.GetLength(0); y++)
{
for (int x = 0; x < arr.GetLength(1); x++)
{
arr[y, x] = r.Next(1, 99);
Console.Write(arr[y,x] + " ");
}
Console.WriteLine();
}
Console.WriteLine();
// Function that separates original array into 2 separate ones (even and odd)
sort(arr);
Console.ReadLine();
}
public static void sort(int[,] array)
{
int j1 = 0;
int i1 = 0;
int j2 = 0;
int i2 = 0;
// Increases the size of the even/odd arrays whenever the value of the original array is even/odd respectively
// I think this is where the problem is
for (int y = 0; y < array.GetLength(0); y++)
{
for (int x = 0; x < array.GetLength(1); x++)
{
if (array[y,x] % 2 == 0)
{
i1 += 1;
}
else
{
i2 += 1;
}
}
j1 += 1;
j2 += 1;
}
int[,] evenArr = new int[j1, i1];
int[,] oddArr = new int[j2, i2];
// Sets the values for the even/odd arrays
for (int y = 0; y < array.GetLength(0); y++)
{
for (int x = 0; x < array.GetLength(1); x++)
{
if (array[y, x] % 2 == 0)
{
evenArr[y, x] = array[y, x];
}
else
{
oddArr[y, x] = array[y, x];
}
}
}
// Prints the values for the even array
for (int y = 0; y < evenArr.GetLength(0); y++)
{
for (int x = 0; x < evenArr.GetLength(1); x++)
{
Console.Write(evenArr[y, x] + " ");
}
Console.WriteLine();
}
Console.WriteLine();
// Prints the values for the odd array
for (int y = 0; y < oddArr.GetLength(0); y++)
{
for (int x = 0; x < oddArr.GetLength(1); x++)
{
Console.Write(oddArr[y, x] + " ");
}
Console.WriteLine();
}
}
}
When you initialize your arrays (evenArr = new int[j1, i1], oddArr = new int[j2, i2];) the default values are zero. Since there's an extra zero it means you should check the length and probably reduce it by one.
I've adapted QuickSort Method to sort Array's Row.
Here's the code:
That one works fine
static void QuickSort(int lowBound, int highBound, int[] a)
{
int temp = 0;
int x = random.Next(lowBound, highBound);
int pivot = a[x];
int i = lowBound;
int j = highBound;
do
{
while (a[i] < pivot) i++;
while (pivot < a[j]) j--;
if (i <= j)
{
temp = a[i]; //changes an element smaller than the pivot...
a[i] = a[j];//... with the greater one
a[j] = temp;
i++; j--;
}
}
while (i <= j);
if (lowBound < j) { QuickSort(lowBound, j, a); }//recursion
if (i < highBound){ QuickSort(i,highBound, a); }
}
Here's the problematic method
static void QuickSortMatrix(int[,] a)
{
int n = a.GetLength(0);
int m = a.GetLength(1);
for (int i = 0; i < n; i++)
{
QuickSortRow(0, m - 1, i, a);
}
for (int j = 0; j < m; j++)
{
QuickSortRow(0, n - 1, j, a);
}
}
static void QuickSortRow(int lowBound, int highBound, int row, int[,] a)
{
int temp = 0;
int x = random.Next(lowBound, highBound);
int pivot = a[row,x];
int p = lowBound;
int q = highBound;
do
{
while (a[row,p] < pivot) p++;
while (pivot < a[row,q]) q--;
if (p <= q)
{
temp = a[row,p];
a[row,p] = a[row,q];
a[row,q] = temp;
p++; q--;
}
}
while (p <= q);
if (lowBound < q) { QuickSortRow(lowBound, q, row, a); }
if (p < highBound) { QuickSortRow(p, highBound,row, a); }
}
At first when the "for" loop is executed everything's ok bur for some reason when executed recursively the row that should be constant when calling the method goes outside the matrix boundaries.
Here's my array and rows reaches value of 4
int[,] matrix =
{
{7,8,9,10,11,5},
{3,6,4,16,22,4},
{7,9,17,8,3,21},
{24,7,11,19,3,4}
};
I hope my explanation was clear enough.
Could anybody advise me? What I'm missing here?
Thank you for your kind help!
BR
Stephan
n is the number of rows in the matrix (4)
m is the number of columns in the matrix (6)
In your second loop you are going 0..m and passing that value to the row parameter. It blows up because there are more columns in the matrix than rows. i.e. It tries to read matrix[4, 0].
Note: as far as I can tell you don't need the second loop because your rows are already sorted after the first loop. Remove that and it won't throw an exception.