I have a black and white image like this (color overlays are mine, and can be removed):
I need to figure out the edge of the hand shown, how can I do that?
My current algorithm:
List<Point> edgePoints = new List<Point>();
for (int x = 0; x < largest.Rectangle.Width && edgePoints.Count == 0; x++) {
//top
for (int y = 0; y < largest.Rectangle.Height - 3 && edgePoints.Count == 0; y++) {
if (colorGrid[x, y].ToArgb() == Color.White.ToArgb() &&
colorGrid[x, y + 1].ToArgb() == Color.White.ToArgb() &&
colorGrid[x, y + 2].ToArgb() == Color.White.ToArgb() &&
colorGrid[x, y + 3].ToArgb() == Color.White.ToArgb()
) {
edgePoints.Add(new Point(x, y));
//g.DrawLine(new System.Drawing.Pen(Color.Orange), new Point(largest.Rectangle.X + x, largest.Rectangle.Y + y), new Point(largest.Rectangle.X + x, largest.Rectangle.Y + y + 3));
break;
}
}
//bottom
for (int y = largest.Rectangle.Height - 1; y > 3 && edgePoints.Count == 0; y++) {
if (colorGrid[x, y].ToArgb() == Color.White.ToArgb() &&
colorGrid[x, y - 1].ToArgb() == Color.White.ToArgb() &&
colorGrid[x, y - 2].ToArgb() == Color.White.ToArgb() &&
colorGrid[x, y - 3].ToArgb() == Color.White.ToArgb()
) {
edgePoints.Add(new Point(x, y));
//g.DrawLine(new System.Drawing.Pen(Color.Orange), new Point(largest.Rectangle.X + x, largest.Rectangle.Y + y), new Point(largest.Rectangle.X + x, largest.Rectangle.Y + y + 3));
break;
}
}
}
Results in a fairly well defined outline, but if the and curves in anywhere, that edge is not detected. I.E., if I held my hand sideways, I'd get the edge of the top finger and bottom finger, but that's it.
What can I do to correct this and get a real edge?
Have a look on projects like this: http://code.google.com/p/aforge/ that will help you a lot and you dont have to reinvent the wheel!
There is a solution on C++ http://outliner.codeplex.com/
But it will not be an easy task to convert it to C#, the algorithm is quite complex.
Related
So i am making a function that scans a Grid and every square's neighbours, and changes certain values (dead/live) in the grid. The current problem I have is: The modifications are made to certain parts of the grid BEFORE the whole scan is done. This means the scan will come out wrong. Here is the code to the function:
public void GridScan(Vector3 worldposition, int range)
{
GetXY(worldposition, out int originx, out int originy);
for (int x = 0; x < range; x++)
{
for (int y = 0; y < range; y++)
{
Debug.Log(GetValue(originx + x, originy + y));
if ((GetValue(originx + x, originy + y)) == 100)
{
if (Neighbours(GetWorldPosition(x, y), 2) < 2)
{
SetValue(x, y, 0);
}
if (Neighbours(GetWorldPosition(x, y), 2) > 3)
{
SetValue(x, y, 0);
}
}
if ((GetValue(originx + x, originy + y)) == 0)
{
if (Neighbours(GetWorldPosition(x, y), 2) == 3)
{
SetValue(x, y, 100);
}
}
}
}
}
Bit of context:
"GetXY" simply converts the vector3 worldposition to coordinates of the graph.
The two for loops scan through the whole graph from the origin, going from (0,0)-(range,0) then (0,1)-(range,1) etc.
"SetValue" & "GetValue" do exactly what they say with an input of the two coordinates.
"Neighbours" Scans for the number of neighbours with a certain value neighbours.
"GetWorldPosition" coverts the x,y coordinates into a vector 3 that "Neighbours" can use.
Is there anyway to do the "SetValue" after the for loops are done? Can I Make an instance of the grid perhaps (if so, how?)? Would those methods solve my problem? This is one of my first projects so bare with me.
Just create a list of all the changes you are about to make, and complete them after the loop in order. List<(int x, int y, int funkyNumber)>
Note I am not sure if you can use ValueTuples in unity these days. If you can't, you could just create your own struct
Example
var list = new List<(int x, int y, int funkyNumber)>();
GetXY(worldposition, out int originx, out int originy);
for (int x = 0; x < range; x++)
{
for (int y = 0; y < range; y++)
{
Debug.Log(GetValue(originx + x, originy + y));
if ((GetValue(originx + x, originy + y)) == 100)
{
if (Neighbours(GetWorldPosition(x, y), 2) < 2)
list.Add((x, y, 0));
if (Neighbours(GetWorldPosition(x, y), 2) > 3)
list.Add((x, y, 0));
}
if ((GetValue(originx + x, originy + y)) == 0)
{
if (Neighbours(GetWorldPosition(x, y), 2) == 3)
list.Add((x, y, 100));
}
}
}
foreach (var item in list)
SetValue(item.x,item.y,item.funkyNumber)
I with a team trying to make Tetris Attack/Panel de Pon. I did debug and saw that Debug.Log("Match?"); is not executable. Before foreach (Vector2Int n in exist) Debug working.
How could I change my script?
With this part of code, I am trying to get cells that match with each other horizontally and vertically.
private List<Vector2Int> FindCellNeighbor(int x, int y, List<Vector2Int> matching)
{
matching.Add(new Vector2Int(x, y));
List<Vector2Int> exist = new List<Vector2Int>();
foreach (Vector2Int n in exist)
{
if (!n.Equals(matching))
{
Debug.Log("Match?");
if (x >= 0 && x <= height && y >= 0 && y <= width) // checks if cell coordiantes hits the borders
{
if (data[x, y] == data[x + 1, y])
{
matching.AddRange(FindCellNeighbor(x + 1, y, matching));
exist = matching;
Debug.Log("x + 1");
}
if (data[x, y] == data[x - 1, y])
{
matching.AddRange(FindCellNeighbor(x - 1, y, matching));
exist = matching;
Debug.Log("x - 1");
}
if (data[x, y] == data[x, y + 1])
{
matching.AddRange(FindCellNeighbor(x, y + 1, matching));
exist = matching;
Debug.Log("y + 1");
}
if (data[x, y] == data[x, y - 1])
{
matching.AddRange(FindCellNeighbor(x, y - 1, matching));
exist = matching;
Debug.Log("y - 1");
}
}
}
}
return matching;
}
Full codes GitHub
I am writing a game of minesweeper. Below is code for 3 methods in minesweeper. The first method is to check all the spaces around the button pressed and to count how many bombs are around it. The next method is to be called recursively, in order that if the user pressed a button with 0 buttons around it, it will open all of the squares that also indicate 0 squares around it. The third method is to check that it will be in bound the check. The empty space recursive call is getting me a stackoverflow error, what am I doing wrong?
Thanks!
private int GameLogicChecker(int x, int y)
{
int count = 0;
if (_grid[x, y] != -1)
{
if (x + 1 < SizeX)
{ //Right
if (_grid[x + 1, y] == -1)
count++;
}
if (x - 1 > 0)
{ //Left
if (_grid[x - 1, y] == -1)
count++;
}
if (y + 1 < SizeY)
{ //Upper
if (_grid[x, y + 1] == -1)
count++;
}
if (y - 1 > 0)
{ //Lower
if (_grid[x, y - 1] == -1)
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY)
{ //Right-Upper
if (_grid[x + 1, y + 1] == -1)
count++;
}
if (x + 1 < SizeX && y - 1 > 0)
{ //Right-Lower
if (_grid[x + 1, y - 1] == -1)
count++;
}
if (x - 1 > 0 && y + 1 < SizeY)
{ //Left-Upper
if (_grid[x - 1, y + 1] == -1)
count++;
}
if (x - 1 > 0 && y - 1 > 0)
{ //Left-Lower
if (_grid[x - 1, y - 1] == -1)
count++;
}
}
return count;
}
void OpenEmptySpace(int x, int y)
{
for (var k = -1; k <= 1; k++)
{
for (var l = -1; l <= 1; l++)
{
if (CheckBounds(x + k, y + l) && GameLogicChecker(x + k, y + l) == 0)
{
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
}
}
}
private bool CheckBounds(int x, int y)
{
return x >= 0 && x < SizeX && y >= 0 && y < SizeY;
}
For k = 0 and l = 0, you are calling yourself again and again and again...
Thanks to #BenVoigt for pointing out that two zeroes adjacent to each other will also lead to infinite recursion. So, in order to solve that one method is to create a boolean grid too and set a particular cell's value to true if it has been run through once. Assuming the grid is called Explored, I've added the condition for it in the code below.
If you insist on your current code, try changing the condition to:
if (CheckBounds(x + k, y + l)
&& GameLogicChecker(x + k, y + l) == 0
&& !(k == 0 && l == 0)
&& !Explored[x + k, y + l])
{
Explored[x + k, y + l] = true;
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
Here is another answer for you, rewriting your methods one-by-one following better coding practices. Like in the other answer, a boolean grid called Explored[SizeX, SizeY] has been assumed.
1. GameLogicChecker()
private int GameLogicChecker(int x, int y)
{
if (_grid[x, y] == -1) return 0;
int count = 0;
if (x + 1 < SizeX && _grid[x + 1, y] == -1) //Right
{
count++;
}
if (x - 1 > 0 && _grid[x - 1, y] == -1) //Left
{
count++;
}
if (y + 1 < SizeY && _grid[x, y + 1] == -1) //Upper
{
count++;
}
if (y - 1 > 0 && _grid[x, y - 1] == -1) //Lower
{
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY && _grid[x + 1, y + 1] == -1) //Right-Upper
{
count++;
}
if (x + 1 < SizeX && y - 1 > 0 && _grid[x + 1, y - 1] == -1) //Right-Lower
{
count++;
}
if (x - 1 > 0 && y + 1 < SizeY && _grid[x - 1, y + 1] == -1) //Left-Upper
{
count++;
}
if (x - 1 > 0 && y - 1 > 0 && _grid[x - 1, y - 1] == -1) //Left-Lower
{
count++;
}
return count;
}
What's better? Quicker returning from the method for special case. Reduced nesting in If(...) blocks.
2. OpenEmptySpace()
public/private void OpenEmptySpace(int x, int y)
{
for (var deltaX = -1; deltaX <= 1; deltaX += 2)
{
for (var deltaY = -1; deltaY <= 1; deltaY += 2)
{
var thisX = x + deltaX;
var thisY = y + deltaY;
if (OpeningNotNeeded(thisX, thisY))
{
continue;
}
Explored[thisX, thisY] = true;
_buttons[thisX, thisY].Text = "0";
OpenEmptySpace(thisX, thisY);
}
}
}
private bool OpeningNotNeeded(int x, int y)
{
return !CheckBounds(x, y)
|| GameLogicChecker(x, y) != 0
|| Explored[x, y];
}
What's better? Properly named indexing variables in both loops. Properly written condition (+= 2 instead of ++). Reduced nesting in If(...). Easier to read method call in the If(...) instead of three predicates. Useful temporary variables added which make it clear what x + k and y + l were in the code written earlier.
3. CheckBounds() is written fine.
I was bored and had only 30 minutes of free time so I decided to have a crack at making the game of life. I followed that rules on wikipedia and it doesn't seem to be working correctly. Could someone please tell me what I would be doing wrong?
Here are the rules:
Any live cell with fewer than two live neighbours dies, as if caused by under-population.
Any live cell with two or three live neighbours lives on to the next generation.
Any live cell with more than three live neighbours dies, as if by overcrowding.
Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
public void PerformLogic()
{
if (in_game)
{
time_elapsed += rate;
if (time_elapsed > frame_rate)
{
time_elapsed = 0;
for (int x = 0; x < board_width; x++)
{
for (int y = 0; y < board_height; y++)
{
if (board[x, y] == alive)
{
int surrounding_cells = 0;
for (int x2 = -1; x2 <= 1; x2++)
{
for (int y2 = -1; y2 <= 1; y2++)
{
if (!(x2 + x <= -1 || y2 + y <= -1 || x + x2 >= board_width || y + y2 >= board_height))
{
if (board[x + x2, y + y2] == alive)
{
surrounding_cells++;
}
}
}
}
if (surrounding_cells < 2)
{
board[x, y] = dead;
}
if (surrounding_cells == 2 ||
surrounding_cells == 3)
{
board[x, y] = alive;
}
if (surrounding_cells > 3)
{
board[x, y] = dead;
}
}
else if (board[x, y] == dead)
{
int surrounding_cells = 0;
for (int x2 = -1; x2 <= 1; x2++)
{
for (int y2 = -1; y2 <= ; y2++)
{
if (!(x2 + x <= -1 || y2 + y <= -1 || x + x2 >= board_width || y + y2 >= board_height))
{
if (board[x + x2, y + y2] == alive)
{
surrounding_cells++;
}
}
}
}
if (surrounding_cells == 3)
{
board[x, y] = alive;
}
}
}
}
}
}
}
Any ideas?
I believe you are updating the board too early. The game of life should update the board after it finishes scanning the whole board, rather than while scanning.
E.g.:
if (surrounding_cells > 3)
{
board[x, y] = dead;
}
After this, for the cell next to it, this cell would be treated as dead.
Marc is right, too.
for (int x2 = -1; x2 <= 1; x2++)
{
for (int y2 = -1; y2 <= 1; y2++)
{
looks to me like you're including the central cell in this loop, so 9 instead of 8.
I'm not sure the nested for is the best option, but if you are using that, add:
if(x2 == 0 && y2 == 0) continue;
at the start of the inner loop (i.e. after the last line that I've posted above)
I'm drawing a cross in the console. Here's my code:
for (int x = 0; x < 320; x++)
{
for (int y = 0; y < 100; y++)
{
Console.SetCursorPosition(Convert.ToInt32(x / 4),Convert.ToInt32(y / 4));
if (x == 160)
{
if (y == 50)
{
Console.Write("┼");
}
else
{
Console.Write("│");
}
}
else
{
if (y == 50)
{
Console.Write("─");
}
}
}
}
The console draws the cross except the middle "┼" symbol. When I debugged the program it hit the Console.Write("┼"); line. Instead the program written the "─" symbol. What I'm doing wrong and how to solve this problem?
The problem seems to be that you are writing to each location multiple times because of the part where you divide by 4.
When (x, y) is (160, 50) you write a cross at (40, 12). Then (x, y) is (160, 51) so you write a vertical pipe at the same location, overwriting the cross. Then later when (x, y) becomes (161, 50) you overwrite the pipe with a dash.
Try this instead:
for (int x = 0; x < 80; x++)
{
Console.SetCursorPosition(x, 12);
Console.Write("─");
}
for (int y = 0; y < 25; y++)
{
Console.SetCursorPosition(40, y);
Console.Write("|");
}
Console.SetCursorPosition(40, 12);
Console.Write("┼");