How do I find group areas in a 2D int Array - c#

I have an int[,] filled with "0" and "1" values. I'm using this to draw a new bitmap and that's working good.
What I'm having problem with, is finding "Empty areas" in that array.
Now, let's take this array as an example:
000000000
011101110
010101010
011101110
000000000
000000000
000000111
000000101
000000111
How can I find all "rectangles" possible in the empty space (0s Block)?
What I need is to check for blocks of Zeros and find all blocks bigger than X Width and Y Height.
Let's say I'm looking for blocks bigger than 3x3.
222000000
222000000
222222
000222
000222
This is one of the results possible.
My goal is to find how many empty "Spaces" I have in an image.

Related

C# - Black points recognition from a photo

I have some photos of white pages with some black points drawn on, like this:
photo (the points aren't very circular, I can draw them better),
and I would find the coordinates of these points.
I can binarize the images (the previous photo binarized: image), but how can I find the coordinates of these black points? I need only the coordinates of one pixel for each point, the approximate center.
This is for a school assignment.
Since its for school work I will only provide you with a high level algorithm.
Since the background is guarantee to be white, you are in luck.
First you need to define a threshold on the level black which you want to consider as the black dot's color.
#ffffff is pure white and #000000 is pure black. I would suggest some where like #383838 to be your threshold.
Then you make a two dimensional bool array to keep track of which pixel you have visited already.
Now we can start looking at the picture.
You read the pixel one at the time horizontally and see if the pixel is > threshold. If yes then you do a DFS or BFS to find the entire area where the pixel's neighbor is also > threshold.
During the process you will be marking the bool array we created earlier to indicate that you have already visited the pixel.
since its a circle point you can just take the min, max of x and y coordinate and calculate the center point.
Once you are done with one point you would keep looping thru the picture's pixel and find the points that you have not visited (false in the bool array)
Since the points you have on the photo contains some small dots on the edge which is not connected to the large point, you might have to do some math to see if the radius is > some number to consider that a valid point. Or instead of a radius 1 neighbor you do a 5 - 10 pixel neighbor BFS/DFS to include the ones that are really close to the main point.
The basics for processing image data can be found in other questions, so I won't go into deeper detail about that, but for the threshold check specifically, I'd do it by gathering the red, green and blue bytes of each pixel (as indicated in the answer I linked), and then just combine them to a Color c = Color.FromArgb(r,g,b) and testing that to be "dark" using c.GetBrightness() < brightnessThreshold. A value of 0.4 was a good threshold for your test image.
You should store the result of this threshold detection in an array in which each item is a value that indicates whether the threshold check passed or failed. This means you can use something as simple as a two-dimensional Boolean array with the original image's height and width.
If you already have methods of doing all that, all the better. Just make sure you got some kind of array in which you can easily look up the result of that binarization. If the method you have gives you the result as image, you will be more likely to end up with a simple one-dimensional byte array, but then your lookups will simply be of a format like imagedata[y * stride + x]. This is functionally identical to how internal lookups in a two-dimensional array happen, so it won't be any less efficient.
Now, the real stuff in here, as I said in my comment, would be an algorithm to detect which pixels should be grouped together to one "blob".
The general usage of this algorithm is to loop over every single pixel on the image, then check if A) it cleared the threshold, and B) it isn't already in one of your existing detected blobs. If the pixel qualifies, generate a new list of all threshold-passed pixels connected to this one, and add that new list to your list of detected blobs. I used the Point class to collect coordinates, making each of my blobs a List<Point>, and my collection of blobs a List<List<Point>>.
As for the algorithm itself, what you do is make two collections of points. One is the full collection of neighbouring points you're building up (the points list), the other is the current edge you're scanning (the current edge list). The current edge list will start out containing your origin point, and the following steps will loop as long as there are items in your current edge list:
Add all items from the current edge list into the full points list.
Make a new collection for your next edge (the next edge list).
For each point in your current edge list, get a list of its directly neighbouring points (excluding any that would fall outside the image bounds), and check for all of these points if they clear the threshold, and if they are not already in either the points list or the next edge list. Add the points that pass the checks to the next edge list.
After this loop through the current edge list ends, replace the original current edge list by the next edge list.
...and, as I said, loop these steps as long as your current edge list after this last step is not empty.
This will create an edge that expands until it matches all threshold-clearing pixels, and will add them all to the list. Eventually, as all neighbouring pixels end up in the main list, the new generated edge list will become empty, and the algorithm will end. Then you add your new points list to the list of blobs, and any pixels you loop over after that can be detected as already being in those blobs, so the algorithm is not repeated for them.
There are two ways of doing the neighbouring points; you either get the four points around it, or all eight. The difference is that using four will not make the algorithm do diagonal jumps, while using eight will. (An added effect is that one causes the algorithm to expand in a diamond shape, while the other expands in a square.) Since you seem to have some stray pixels around your blobs, I advise you to get all eight.
As Steve pointed out in his answer, a very quick way of doing checks to see if a point is present in a collection is to create a two-dimensional Boolean array with the dimensions of the image, e.g. Boolean[,] inBlob = new Boolean[height, width];, which you keep synchronized with the actual points list. So whenever you add a point, you also mark the [y, x] position in the Boolean array as true. This will make rather heavy checks of the if (collection.contains(point)) type as simple as if (inBlob[y,x]), which requires no iterations at all.
I had a List<Boolean[,]> inBlobs which I kept synced with the List<List<Point>> blobs I built, and in the expanding-edge algorithm I kept such a Boolean[,] for both the next edge list and the points list (the latter of which was added to inBlobs at the end).
As I commented, once you have your blobs, just loop over the points inside them per blob and get the minimums and maximums for both X and Y, so you end up with the boundaries of the blob. Then just take the averages of those to get the center of the blob.
Extras:
If all your dots are guaranteed to be a significant distance apart, a very easy way to get rid of floating edge pixels is to take the edge boundaries of each blob, expand them all by a certain threshold (I took 2 pixels for that), and then loop over these rectangles and check if any intersect, and merge those that do. The Rectangle class has both an IntersectsWith() for easy checks, and a static Rectangle.Inflate for increasing a rectangle's size.
You can optimise the memory usage of the fill method by only storing the edge points (threshold-matching points with non-matching neighbours in any of the four main directions) in the main list. The final boundaries, and thus the center, will remain the same. The important thing to remember then is that, while you exclude a bunch of points from the blob list, you should mark all of them in the Boolean[,] array that's used for checking the already-processed pixels. This doesn't take up any extra memory anyway.
The full algorithm, including optimisations, in action on your photo, using 0.4 as brightness threshold:
Blue are the detected blobs, red is the detected outline (by using the memory-optimised method), and the single green pixels indicate the center points of all blobs.
[Edit]
Since it's been almost a year since I posted this, I guess I might as well link to the implementation I made of this. I actually managed to use it myself about a month after I wrote it, when recreating the video compression algorithm of an old DOS game which used chunked up diff frames.

Adding single dimension float array values

I have two questions regarding the Evil Dicom library.
I know with the floats function, all of the pixel data is contained as float elements in a one dimensional array. My question here is how can I add up the individual elements to get one value?
After I have multiplied a black and white mask with the original image, how can I then add up the non-zero values in the image? Do I also use the floats function to get the data as an array and then add up the array elements? If not, how can I add up the pixels in the image from top left corner to bottom right corner?
As far as I know there is no special functionality in the Evil DICOM library for these operations, but there is always LINQ.
If you are looking for the sum of all pixel elements:
var imgMtx = new ImageMatrix("image.dcm");
var sum = imgMtx.Image.Sum();
If you are looking for the sum of the non-zero values:
var nonZeroSum = imgMtx.Image.Where(val => val != 0.0f).Sum();
If you are looking for the average value, simply replace Sum with Average.

Distribute text within a shape

I have an array of simple strings (simple meaning 1-4 words, not in complete sentences) that I want to distribute "evenly" within an arbitrary shape.
By "evenly" I mean that the text does whatever it can to not overlap other text, but all the strings aren't bunched up in one particular location. I don't mean that the text has to be the max distance from eachother, I just want to fill the space as best as I can.
Example:
I have the following array:
var array = new [] {"#WhatIDidLastWeek", "Salena Gomez", "#WWF", "#IThinkOomf", "CES" };
and I have a circle of radius 600px that I want every string in the array to be inside that circle and be spaced far enough appart that they don't overlap and that the general shape of the circle is apparent.
The first thing that comes to mind is to use some sort of MeasureString call in whatever environment you're working with.
The basic idea is measure each word to see if it will fit in the allotted space. If it doesn't fit, move it down to the next "line". The hard part will be what to do when you run out of space to fit all the words.

Implementing A* on a triangular/hexagonal Grid with negative Coordinates

Following the apparent tradition of of using this question as the basis of new questions I too have a problem I am looking to solve as elegantly as possible:
I have implemented a hexagonal map as such:
(Wanted to insert image here.. but I'm not allowed due to being new... Please see above link)
But am now wondering how to (elegantly) implement A* for this type of map with these types of coordinates.
I have experience with using A* on typical squared grids (cartesian grids I think?) and the way I handle it there seems incompatible with this coordinate system.
Typically I would generate a 2D array of bytes. The indices of the array would correspond to a grid coordinate and the value at said index would give the 'weight' of that node. (0 being impassible and higher numbers 'weighing' more then lower numbers).
Example:
sbyte[,] pathGrid = new sbyte[5, 5]
{
{0,0,1,0,0},
{9,5,1,3,0},
{9,5,1,3,0},
{9,5,1,3,0},
{0,0,1,0,0}
};
Where the 0's would be impassible, the 1's would be easily traversable, and higher numbers would 'cost' more to traverse. (sorry about formatting.. I'm a stack overflow newb :P )
This array would be generated based on the composition of my map and then fed into my path finding algorithm which would in turn spit out a list of nodes (the path) or return null if no path was found.
However, using this type of grid, that isn't possible (at least at first glance) due to negative coordinates (which obviously do not work in an array) and the fact that the grid doesn't follow the same rules as a 'typical' grid.
There are ways to solve this using my A* method I think but they are all rather sloppy (converting grid coordinates and using empty nodes) and I was wondering if anybody has thought of a way to do this elegantly.
Thanks for reading in any case :)
(Btw I am doing this in C#/.net for what it's worth)
Even though the indices of an array begin at 0, your program doesn't need to conceptually treat the arrays that way. For instance, if you always add e.g. 3 to your indices before using them to look up in an array, you effectively have an array where the indices begin at 3. In order to simplify working with arrays in this way, you could create a class called e.g. ArbitraryBaseArray that wraps an array and a number that specifies the desired base index.
Then, you could create a HexGrid class that contains an array of ArbitraryBaseArray, each with their own base index (depending on how the left edge of your hex area looks). The class could have an indexer that lets you look up a specific element based on two hex coordinates. It could also have a static method which, given a coordinate in the hex grid, returns an array with the six neighbouring coordinates; this method could be used by A*. (Note that while the illustration in the question you linked to uses three coordinates for each hex tile, two coordinates are sufficient.)
You could store your coordinates in a dictionary:
var nodes = new Dictionary<Point, Vector[]>;
This way you're not limited to positive coordinates, and you're also not limited on the number of paths from each node

What is the best way to put 20 pieces on a chessboard in random places?

An idea I had to solve this, is to make up an buffer of size 8x8, fill it up with pointers to my checkers (all 20 of them), and the rest leave 0 (null), then run a shuffling algorithm on the buffer, and thats it (just read it as a 8x8 array)
I was wondering if there's a better way to do this.
I need to write it in C#, and my proposal wouldn't work in the way I described it
anyone ?
To piggyback on Borzio's idea, as you approach the twentieth piece, there is a 1 in 3 chance that you will have to re-generate the random number and try again. With 20 pieces, you're probably still safe, but were you to have, say, 40 pieces, there would be better than a 1 in 2 chance and you might be stuck waiting a while.
Construct the board array, all empty.
Copy a reference to each board square to a list (emptySquareList).
Loop for each piece you want to add:
Generate a random number between 0 and emptySquareList.Length-1.
Put the piece in that square
Remove the square from the emptySquareList.
This way, you're always maintaining a list of empty squares, and choosing from them. Note that an array of indexes into your board array works just as well and might be faster (Enumerable.Range(0,64)).
I encourage you to experiment with the random-and-check algorithm, as well as this one; see which one's more efficient.
An 8x8 matrix which contains either pointers (c++) to piece objects or references (c#/java) seems like a very reasonable design.
You could use an 1D array that is 64 elements big (you can easily map 2D indexes to a 1D array) and use something like this:
using System;
using System.Linq;
Piece[] board = whatever();
// New random number generator.
Random random = new Random();
// LINQ query orders each element by the next random number.
Piece[] randomBoard = (from piece in board
orderby random.Next()
select piece).ToArray();
NOTE: I'm not a c# programmer, but this seems reasonable.
To convert an x,y pair to an array index, you use this algorithm:
int index = (y * 8) + x;
NOTE2: I don't know if you have to follow placement rules of checkers or not, if you do, you need to do something more clever. You could maybe have an array 32 elements big (representing all black squares). Shuffle around in that, then assign each element in the 32 big array to each "black" square of the real 64 element array.
To answer the question that has been posed:
Place the first chess piece in a random spot that isn't already occupied
Repeat for the other 19 pieces
Seriously, you haven't given us enough information to go on to answer this question at all. Here's some questions:
Which chess pieces?
Which colors (there's 16 of each), and does color matter? Will whites have to avoid being captured by blacks, and vice versa?
Assuming there's no rules to follow, except that you need to place all 20 on the board, ie. no collisions, this will do what you want:
Piece[] pieces = ... your 20 pieces here
Piece[] board = new Piece[8 * 8];
Random r = new Random();
foreach (Piece piece in pieces)
{
while (true)
{
Int32 location = r.Next(board.Length);
if (board[location] == null)
{
board[location] = piece;
break;
}
}
}
A simpler solution, provided you already have helper-routines somewhere, would be to just place them at the start of the 64-element array, then shuffle the entire array. This would shuffle those 20 pieces and the 44 empty squares around, and would effectively place them in random spots.
If you have to follow placement rules, given your 8x8 matrix example, I would also consider it a 1d array as Evan pointed out -- (see his math for determining x & y) --
Black and white squares are the odd and even index values; But, hey, you never said you needed placement rules -- I also presume you aren't looking for c# code but more "logic" level ideas...
If you are trying for a Linq-Challenged solution, consider the following;
Construct the "board" array, all empty; (64 elements)
Construct the "game piece" array consisting of your pieces
Create a loop from 1 to # of pieces
Generate a random number between 1 and # of board spaces (64)
If board space pointed to by #4 is !0, redo step 4 (or you can "while" !0)
Place the piece (# from loop in step 3) into square X from step 4
Just ONE idea of which are sure to be many --
Hope it helps ...

Categories