I'm not really good in maths, so I'm having really hard times to find an algorithm do this:
i have a grid like this: (8x8) GRID 8x8
I'm trying to find an alghorithm that help me to find the red polygon and after that, all the cell inside this polygon will be red.
At this moment i'm using C# and i have a multi-dimensional array with the grid colour map, so i have to work on it; but i don't know what i can do.
private Color[,] mapColor;
mapColor= new Color[8, 8];
Thanks in advance
The question is not too clear, and I couldn't see the image (blocked by my firewall). What I understand is that you want to follow all possible paths starting from a red cell and trying to find a polygon.
If it is the question, sounds like a Graph problem. You'll problably solve it using a BFS (Breadth First Search) algorithm, thinking in the Grid as a Graph (each cell can have like 8 edges - if you want to consider diagonal ways - or 4 edges if you want to consider only up/down and left/right directions).
BFS will return the shortest path. If you want all possible paths, you should use DFS (Depth First Search) algorithm.
Just iterate over the bitmap every 64 pixels and then call a function that checks nearby pixels to confirm it has found a red square. As long as there's high contrast in the image like you have, it shouldn't be too hard to find the places inordinately biased towards red.
e.g.
List<KeyValuePair<int, int>> PossibleCoords = new List<KeyValuePair<int,int>();
for(int i = 0; i < Bitmap.Width/64; i++)
{
for(int j = 0; j < Bitmap.Height/64)
{
if(Bitmap.GetPixel(i*64, j*64).R > 200)
{
KeyValuePair<int, int> temp = new KeyValuePair<int, int>();
KeyValuePair.Key = i*64;
KeyValuePair.Value = j*64;
PossibleCoords.Add(temp);
}
}
}
for(int i = 0; i < PossibleCoords.Count; i++)
{
SampleAdjacentPixelsToConfirm(PossibleCoords[i]);
}
To take a sample, I'd check if the ratio of red to the other colors is high if I were after high precision.
Related
I'm reading data from a sensor. The sensor give an array of points (x,y). But as you can see in the image, there is a lot of noise:
.
I need to clean the data in a way that the data filtered, give a few points . Using something like Median,adjacent averaging, mean of the xy points or an algorithm that removes the noise. I know that there are a bunch of libraries in Python that make the work automatically. All the auto libraries that I found are base on image analysis and I think they do not work for this case because this is different, these are points (x,y) in a dataset.
point-cloud noise cleaned:
PD: I wanted to do the median of the points but i got confused when i tried with an bidimensional array (this mean ListOfPoints[[x,y],[x,y],[x,y],[x,y],[x,y],[x,y]]) I didn't know how to make that calculation with for or while to iterate and make the calc. I prefer C#, but if there is a solution in other language without libraries, I would be open to it.
One of the methods you can use is k_means algorithm. This picture briefly explains this algorithm k_means
This link fully explains the k_means algorithm. Also, how to create a loop on the input data. I don't think any additional explanation is needed k_means algorithm
K_menans algorithm is very simple and you will understand it with the first Google search
You could try doing a weighted average of the Y-value at sampled X-positions. Something like this:
List<Point2> filtered_points = new List<Point2>();
for (int x = xmin; x <= xmax; x++)
{
double weight_sum = 0;
List<double> weights = new List<double>();
foreach (Point2 p in point_list)
{
double w = 1.0/((p.x - x)*(p.x - x) + 1e-3);
weights.Add(w);
weight_sum += w;
}
double y = 0;
for (int i = 0; i < point_list.Count; i++)
{
y += weights[i]*point_list[i].y / weight_sum;
}
filtered_points.Add(new Point2(x, y));
}
You would probably need to tune the weights to get nice results. Also, in the example I am using a quadratic decay, but other weighting functions can be used (linear decay, gaussian function...)
I've been making a top-down shooter game in XNA that requires rectangular collision for the map.
The collision walls for a map is stored in a text file in the format of:rect[0,0,1024,8]
The values correspond to defining a rectangle (x, y, width, height).
I've been thinking that I could write a separate application that can illiterate through the data of the map image, find out the pixels that are black (or any color of the wall) and make rectangles there. Basically, this program will generate the rectangles required for the collision. Ideally, it would be pixel perfect, which would require something like a thousand rectangles each 1 pixel wide that covers all the walls.
Is there a possible way to detect which of these rectangles (or squares I should say) are adjacent to one another, then connect them into the a bigger (but still covering the same area) rectangle?
EG. Lets say I have a wall that is 10 by 2. The program would generate 20 different rectangles, each 1 pixel high. How would I efficiently detect that these rectangles are adjacent and automatically make a 10 by 2 rectangle covering the whole wall instead of having 20 different little pixel rectangles?
EDIT: I've worked out a solution that fits my purposes, for future reference, my code is below:
//map is a bitmap, horizontalCollisions and collisions are List<Rectangle>s
for (int y = 0; y < map.Height; y++) //loop through pixels
{
for (int x = 0; x < map.Width; x++)
{
if (map.GetPixel(x, y).Name == "ff000000") //wall color
{
int i = 1;
while (map.GetPixel(x + i, y).Name == "ff000000")
{
if (i != map.Width - x)
{
i++;
}
if (i == map.Width - x)
{
break;
}
}
Rectangle r = new Rectangle(x, y, i, 1);//create and add
x += i - 1;
horizontalCollisions.Add(r);
}
}
}
for (int j = 0; j < horizontalCollisions.Count; j++)
{
int i = 1;
Rectangle current = horizontalCollisions[j];
Rectangle r = new Rectangle(current.X, current.Y + 1, current.Width, 1);
while(horizontalCollisions.Contains(r))
{
i++;
horizontalCollisions.Remove(r);
r = new Rectangle(current.X, current.Y + i, current.Width, 1);
}
Rectangle add = new Rectangle(current.X, current.Y, current.Width, i);
collisions.Add(add);
}
//collisions now has all the rectangles
Basically, it will loop through the pixel data horizontally. When it encounters a wall pixel, it will stop the counter and (using a while loop) move the counter towards the right, one by one until it hits a non-wall pixel. Then, it will create a rectangle of that width, and continue on. After this process, there will be a big list of rectangles, each 1px tall. Basically, a bunch of horizontal lines. The next loop will run through the horizontal lines, and using the same process as above, it will find out of there are any rectangles with the same X value and the same Width value under it (y+1). This will keep incrementing until there are none, in which one big rectangle will be created, and the used rectangles are deleted from the List. The final resulting list contains all the rectangles that will make up all the black pixels on the image (pretty efficiently, I think).
Etiquette may suggest that I should comment this instead of add it as an answer, but I do not yet have that capability, so bear with me.
I'm afraid I am not able to translate this into code for you, but I can send you towards some academic papers that discuss algorithms that can do some of the things that you're asking.
Other time this questions has appeared:
Find the set of largest contiguous rectangles to cover multiple areas
Puzzle: Find largest rectangle (maximal rectangle problem)
Papers linked in those questions:
Fast Algorithms To Partition Simple Rectilinear Polygons
Polygon Decomposition
The Maximal Rectangle Problem
Hopefully these questions and papers can lead help you find the answer you're looking for, or at least scare you off towards finding another solution.
I'm working on a strange project. I have access to a laser cutter that I am using to make stencils (from metal). I can use coordinates to program the machine to cut a certain image, but what I was wondering was: how can I write a program that would take a scanned image that was black and white, and give me the coordinates of the black areas? I don't mind if it gives every pixel even though I need only the outer lines, I can do that part.
I've searched for this for a while, but the question has so many words with lots of results such as colors and pixels, that I find tons of information that isn't relevant. I would like to use C++ or C#, but I can use any language including scripting.
I used GetPixel in C#:
public List<String> GetBlackDots()
{
Color pixelColor;
var list = new st<String>();
for (int y = 0; y < bitmapImage.Height; y++)
{
for (int x = 0; x < bitmapImage.Width; x++)
{
pixelColor = bitmapImage.GetPixel(x, y);
if (pixelColor.R == 0 && pixelColor.G == 0 && pixelColor.B == 0)
list.Add(String.Format("x:{0} y:{1}", x, y));
}
}
return list;
}
If we assume that the scanned image is perfectly white and perfectly black with no in-between colors, then we can just take the image as an array of rgb values and simply scan for 0 values. If the value is 0, it must be black right? However, the image probably won't be perfectly black, so you'll want some wiggle room.
What you do then would look something like this:
for(int i = 0; i < img.width; i++){
for(int j = 0; j < img.height; j++){
// 20 is an arbitrary value and subject to your opinion and need.
if(img[i][j].color <= 20)
//store i and j, those are your pixel location
}
}
Now if you use C#, it'll be easy to import most image formats, stick em in an array, and get your results. But if you want faster results, you'd be better off with C++.
This shortcut relies completely on the image values being very extreme. If large areas of your images are really grey, then the accuracy of this approach is terrible.
While there are many solutions in many languages, I'll outline a simple solution that I would probably use myself. There is a imaging great library for Python called PIL (Python Imaging Library - http://www.pythonware.com/products/pil/) which could accomplish what you need very easily.
Here's an example of something that might help you get started.
image = Image.open("image.png")
datas = image.getdata()
for item in datas:
if item[0] < 255 and item[1] < 255 and item[2] < 255 :
// THIS PIXEL IS NOT WHITE
Of course that will count any pixel that is not completely white, you might want to add some padding so pixels which are not EXACTLY white also get picked up as being white. You'll also have to keep track of which pixel you are currently looking at.
Whats the best way to darken a color until it is readable? I have a series of titles are have an associated color, but some of these colors are very light and any text drawn in them is unreadable. I've been messing around with HSB and I can't seem to get an algorithm down that darkens the color without making it look silverish.
I've basically just been doign this, but it doesn't seem to get what I would call "good" results:
Color c =
FromHSB(
orig.A,
orig.GetHue(),
orig.GetSaturation(),
orig.GetBrightness() > .9 ?
orig.GetBrightness() - MyClass.Random(.5, .10)
: orig.GetBrightness());
I think I want to alter the saturation too. Is there a standard way of doing this?
I basically just hacked together a randomizer that adds components to the RGB values if the sum of the RGB values is too low, or any one item is too low. Its a non-rigourous way to do it, but it seems to produce good results.
double threshold = .8;
for (int j = 0; j < 3; j++)
{
if (color.GetBrightness() > threshold)
{
color[j] -= new MyRandom(0, 20/255);
}
}
I want to develop a basic tool like the one featured here. I will be taking screenshots of a number of web pages and from there I wish to take the top five most popular colours and from there somehow decide whether the colours are a good match.
I want to write this tool in C# and after a bit of research I discovered lockbits. My first idea was to take an image and then get the colour of each pixel, but I am unsure as to whether this will give me the results I desire and how to make six lists of the most popular colours.
Can anyone here provide advice as to how I would create a program to do something similar to the program above, that will take in an image and will select the top five colours used in the image?
Well.. Use a thumbnail image (16x16, 32x32 etc) and select from it the colors like
updated code:
private void button1_Click(object sender, EventArgs e)
{
int thumbSize = 32;
Dictionary<Color, int> colors = new Dictionary<Color, int>();
Bitmap thumbBmp =
new Bitmap(pictureBox1.BackgroundImage.GetThumbnailImage(
thumbSize, thumbSize, ThumbnailCallback, IntPtr.Zero));
//just for test
pictureBox2.Image = thumbBmp;
for (int i = 0; i < thumbSize; i++)
{
for (int j = 0; j < thumbSize; j++)
{
Color col = thumbBmp.GetPixel(i, j);
if (colors.ContainsKey(col))
colors[col]++;
else
colors.Add(col, 1);
}
}
List<KeyValuePair<Color, int>> keyValueList =
new List<KeyValuePair<Color, int>>(colors);
keyValueList.Sort(
delegate(KeyValuePair<Color, int> firstPair,
KeyValuePair<Color, int> nextPair)
{
return nextPair.Value.CompareTo(firstPair.Value);
});
string top10Colors = "";
for (int i = 0; i < 10; i++)
{
top10Colors += string.Format("\n {0}. {1} > {2}",
i, keyValueList[i].Key.ToString(), keyValueList[i].Value);
flowLayoutPanel1.Controls[i].BackColor = keyValueList[i].Key;
}
MessageBox.Show("Top 10 Colors: " + top10Colors);
}
public bool ThumbnailCallback() { return false; }
alt text http://lh3.ggpht.com/_1TPOP7DzY1E/S0uZ6GGD4oI/AAAAAAAAC5k/3Psp1cOCELY/s800/colors.png
The easiest way, as you said is:
Read in each pixel and store them in
a collection.
The top five colours used would be
the values that occur the most.
That's how I'd have ago at first trying something like this.
To further this work, you could take in colour ranges, so using RGB values (Red, Green, Blue) assign a colour to a certain approximation of colour.
For example, say that same image was used, the light blue values would get stored together, then an average could be taken of these to give the most common (yet average) light blue in the scene.
Repeat for the other pixels.
As for the scaling - the example website uses dull/bright values. A simple scale value could be used. Consider a medium red in RGB:
0.7, 0.0, 0.0
You could scale this by adding/multiplying a value. Keep the values within the limit of 0 to 1 however. As for what the scaling value should be, experimant. The higher it is, the duller/brighter the colour will become.
This is an example of how to create a histogram (or a frequency table in another words) where you can take a look on the details on how to go about processing the image.
But my main recommendation is not to use RGB (unless the website you're looking at has mostly plain colors), but use HSB instead. The "H" (hue) component will give you a better indication of the colors used no matter how bright or dark they are.