Flood Fill implementation - c#

This is my C# implementation of a stack-based flood fill algorithm (which I based on wikipedia's definition). Earlier while coding, I only wanted to see it work. And it did. Then, I wanted to know the number of pixels that was actually filled. So in my code, I changed the return type to int and returned the "ctr" variable. But then ctr turned out to be approximately twice the actual number of filled pixels (I made a separate function with the sole purpose of counting those pixels -- just to know for certain).
Can anyone enlighten as to how and why the variable "ctr" is incremented twice as it should have?
*Pixel class only serves as a container for the x, y, and color values of the pixels from the bitmap.
public Bitmap floodfill(Bitmap image, int x, int y, Color newColor)
{
Bitmap result = new Bitmap(image.Width, image.Height);
Stack<Pixel> pixels = new Stack<Pixel>();
Color oldColor = image.GetPixel(x, y);
int ctr = 0;
pixels.Push(new Pixel(x, y, oldColor));
while (pixels.Count > 0)
{
Pixel popped = pixels.Pop();
if (popped.color == oldColor)
{
ctr++;
result.SetPixel(popped.x, popped.y, newColor);
pixels.Push(new Pixel(popped.x - 1, popped.y, image.GetPixel(x - 1, y));
pixels.Push(new Pixel(popped.x + 1, popped.y, image.GetPixel(x + 1, y));
pixels.Push(new Pixel(popped.x, popped.y - 1, image.GetPixel(x, y - 1));
pixels.Push(new Pixel(popped.x, popped.y + 1, image.GetPixel(x, y + 1));
}
}
return result;
}

You do check the color of the pixel here:
if (popped.color == oldColor)
But popped.color may be (and apperently is in 50% of the cases) outdated. Because you do not check for duplicates when you insert pixel into your stack you will have duplicates.
Upon popping these duplicates, the color attribute would have been saved a long time ago.
Maybe it gets clearer with a drawing:
As an example I took a bitmap with 9 pixels. On the first pane you have the numbering of the pixels, and on the right side you have your stack.
You start with pixel no 5. and push pixels 2, 4, 6 and 8 on the stack. Then you take pixel 2 off and push 1 and 3. In the next step you pop 1 and push 2 and 4 (again!). Then you may take 2 and realise it has already gotten the new color when it was pushed. (A bit late, but better late than never)
however: pixel no. 4 is there twice and has remembered the old color twice. So you take pixel no.4 and color it.
Some steps later you have the image filled and still some items on your stack. Because the old color value is still stored inside these items, they get counted again.
While I may have a wrong ordering in the stack, the point stays valid.
Solution to your problem:
Quick and dirty (because it it still inefficient)
if (image.GetPixel(popped.x, popped.y) == oldColor)
it counts pixels only if the current color is wrong, not the remembered color.
Recommended: Check your Pixels whether they need coloring before pushing them onto the stack.

If all Pixel does is hold the color passed to its constructor, it won't update the color after the pixel is filled, therefore can increment ctr more than once per pixel.
If you change Pixel to take a pointer to the image in its constructor, you could re-read the color (i.e. make color a get property that reads the current colour), or track the coordinates already filled and don't push those a second time.
[Edit]
In case it wasn't obvious from the accepted answer, GetPixel returns a Color - a value type. Think of it as an int that encodes the RGB value of the pixel at that time.
If you want to perform a fill fast, look up a Graphics.FloodFill example.
If you're goal is learning I'd recommend copying your image data to an array for processing and back again - most classic image algorithms are not much fun using GetPixel().

Related

Image-comparison algorithms

So Im looking at an image and trying to select one from a set of other images that is the most similar (least different).
Currently I simply look at the average difference between the RGB parts of each pixel, but this has a tendency of picking grey colors. If half the picture is white and the other is black, it's going select some grey shade even though there is no grey in the picture.
I'm assuming there are better algorithms to compare images or trying to achieve what I'm trying to do.
Note that the actual content of the image is not that interesting, just that the colors "look" similar.
For the record what Im trying to do is match someones clothing to a texture-file, if that makes any difference.
Any suggestions or points in the directions of some resources would be greatly appreciated.
EDIT: My solution was to remove the grey colors from the set I was selecting from and it worked pretty well, if anyone else have any better solutions feel free to post.
I just posted this yesterday, I don't want to duplicate the post, but it is very similar.
Making smaller Bitmaps from a Bitmap object
My open source project Transparency Maker creates a Pixel Database, which is actually a list of PixelInformation objects.
Each pixel has properties for Red Green Blue of course, but there are also properties for Total, BlueGreen, BlueRed, and GreenRed, which is just the sum of Blue + Green, Blue + Red, etc.
You can then do Linq queries or for each loops and compare the total for two Pixels (Pixel Information class), and then you can compare on different things like:
Comparing the totals is as easy as:
int difference = pixel1.Total - pixel2.Total;
Which is the same as typing all this if you are using a standard BitMap:
int redDiff = Pixel1.Red - Pixel2.Red;
int green = Pixel1.Green - Pixel2.Green;
int blueDiff = Pixel1.Blue - Pixel2.Blue;
int diff = redDiff + greenDiff + blue;
As a thought, you could refine your algorithm to where each difference gets weighted more,
so for the above the last line could be:
int difference = (redDiff * 17) + (greenDiff * 17) + (blueDifference * 17);
I just made up 17 as an example, what value for weight you use it is up to you.
In theory, the above would give you a closer number to closer images.
Here is the link to my open source project if you want the full code:
https://github.com/DataJuggler/TransparencyMaker
Maybe this will give you some ideas.

How to draw or plot large amount of points in c# repeatedly?

I wanna draw or plot large amount of data points (almost 500,000 points) in Winform application repeatedly (every 10ms).
I have used some common plotting controls but they can't handle this. They become too slow.
My program does another jobs so it should be efficient.
Any suggestions?
Thanks.
Windows Forms may not be a great choice for this, but I suppose you don't really know unless you try. This answer is a good place to start. I assigned a DirectBitmap to a picture box:
_bitmap = new DirectBitmap(pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = _bitmap.Bitmap;
Then I created an array of 500,000 points which I'm continually updating with random data in another thread:
private const int _numPoints = 500000;
private static Point[] _points = new Point[_numPoints];
Now I clear the bitmap (to black) and draw the points by setting individual pixels. Call this every 10ms:
private void DrawPoints() {
Array.Clear(_bitmap.Bits, 0, _bitmap.Bits.Length);
int color = Color.Gray.ToArgb();
for (int i = 0; i < _numPoints; i++) {
int bmpIndex = _points[i].X + _points[i].Y * pictureBox1.Width;
_bitmap.Bits[bmpIndex] = color;
}
pictureBox1.Invalidate();
}
My PC is close to 5 years old and DrawPoints is taking between 4 to 16ms to run. There are plenty more optimisations you could try such as using an 8-bit bitmap or updating parts of the bitmap from multiple threads.
It makes no sense to draw such amount of points since the number of pixels in screen is much less.
I faced a similar problem time ago and I did the following process:
I reduce the number of data points to something more handy.
For example, I realised that I didn't need more than 1000 points because of the number of pixels. Actually the ideal number of points would be the canvas width.
Then, I calculate the number of data points to draw per pixel. This is, if you have 500k data points, and your canvas is 1000 pixels, it means a pixel will draw 500 data points. You see, it makes no sense to draw 500 data points in a column of pixels...
Therefore, I split data points list in groups depending on the number of pixels. For example, for the first pixels I take the first 500 points, for the second pixel, next 500 data points, and so on.
To draw 500 data points in a column of pixels, basically I locate max and min values and draw a vertical line.
Hope this approach helps you.

Find intersection of two images in C#

I have two images (A and B) and would like to know the rectangle intersection of the images. The images represent scrolled screen content, and I would only like the exclusive value of the images with no intersections. So A represents a capture, then B represents the same screen area but scrolled some % of the content, with additional content at the bottom. but because the scroll will not always represent an entire scroll of content (at the end, for instance)
So basically if B was only a partially scrolled view of the content, I want to reduce B so it does not contain any image data that's present in A; so when I merge A and B (and any other scrolls prior to A) they do not contain duplicate data.
This is my example image representing A and B stitched together; as you can see the content is duplicated.
There is some ambiguity here since there could be multiple intersections. By that I mean there could a 1 pixel high intersection as well as a 100 pixel high intersection. One way to resolve that ambiguity is to take the greatest intersection possible between the two images. Here's a brute force method. I'll assume the two screenshots have the same dimensions w x h.
Compare each of `h` rows of A to B.
Perform the same comparison on `h-1` rows with A's y coordinates offset by +1 (down 1).
Perform the same comparison on `h-2` rows with A's y coordinates offset by +2 (down 2).
...
Whenever the comparison succeeds, return that offset. That is the Y coordinate of A that should be stitched to the top of B.
The main issue here is performance. The worst case time is pretty bad (width * height * height) but that's if every pixel compares identical until the last one, for every row. By returning early as soon as one pixel doesn't match the performance might be practically good enough.
Comparing with memcp
Here's an easy and fast way to compare your images starting at a given Y offset.
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(IntPtr b1, IntPtr b2, long count);
static bool compareIntersection(int width, int height, int yOffset, IntPtr a, IntPtr b)
{
int bytesPerPixel = 4; // this needs to be set to reflect your image format
int bytesToRead = (height - yOffset) * width * bytesPerPixel;
IntPtr aStart = a + yOffset * width * bytesPerPixel;
return 0 == memcmp(aStart, b, bytesToRead);
}
The arguments to the function are the width of the image, height of the image, the y offset in A, and pointers into the beginning of each bitmap's memory. You can get those pointers by using Bitmap.LockBits and then BitmapData.Scan0.
The code is untested so it could have problems.

How to extract a rectangular and non-rectangular area from a video?

I am developing a face tracking application using Kinect, and I have output like the following.
What I want to do is the extract the exact face area, either the yellow-lined area or the red rectangular, it would be great if you can tell me how to do both. Basically, I am expecting an output with only the interested area with black otherwise.
Right now I have all the point coordinates that I need, but I am not sure which class and method to use.
Please note that I am working with video frames, if it makes any difference.
Thank you,
I haven't done this in C#, but in c++, running something like this generates an array of RGB values:
const XnRGB24Pixel *pImage = imageMD->RGB24Data(); // generate array
XnRGB24Pixel pixelRGB = *pImage; // get the first element of array
byte red = pixelRGB.nRed // read the RED value
The array is 1-dimensional and elements are stored in it row wise from the bottom (last row, then the row before last row, ...). Going through them with a nested for loop like this would give you the rectangular area you want:
for(int y = RECTANGLE_Y1; y < RECTANGLE_Y2; y++)
{
for(int x = RECTANGLE_X1; x < RECTANGLE_x2; x++)
{
pixelRGB = pImage[y*RESOLUTION_WIDTH + x]; // get the element
// work with pixelRGB
}
}
Replace RECTANGLE_X1 and RECTANGLE_Y1 with the coordinates of the lower left edge coordinates of your rectangle and RECTANGLE_X2 and RECTANGLE_Y2 with the upper right edge coordinates.
For getting the values of pixels inside the non-rectangular area, a similar approach would work if you can figure out the geometric calculations necessary to recognize when a given [x,y] are inside the area; but even after that, I don't have any clue on how to store it in conventional data structures.
Hope this helps.

PCL raster color graphics distorted. Code included: what am I missing?

The function below prints a color raster image to a PCL-5 printer. The function was adapted from a 2-color (1bpp) printing function we had that worked perfectly, except for the grainy 2-color printing. The problem is that the image comes out with a large black bar extending from the right of the image to the edge of the page like this:
IMAGE#########################################
IMAGE#########AREA COMPLETELY BLACK###########
IMAGE#########################################
The image itself looks perfect, otherwise.
Various PCL-to-PDF tools don't show the image at all, which leads me to believe I've forgotten do to something. Appropriate resets (\u001bE\u001b%-12345X) were sent before, and page-feeds after.
Any PCL experts out there? I've got the PCL 5 Color Technical Reference Manual, and it's gotten me this far. This last thing is driving me crazy though.
*Edit:
I now know what command is causing the problem, but I don't know why:
stream("\u001b*r0F");
This should keep the image rotated along with the page (portrait, landscape). If I remove this, the problem goes away. I can compensate by rotating the bitmap beforehand, but I really want to know what caused this!
static void PrintImage()
{
// Get an image into memory
Image original = Image.FromFile("c:\\temp\\test.jpg");
Bitmap newBitmap = new Bitmap(original, original.Width, original.Height);
stream(String.Format("\u001b*p{0:d}x*p{1:d}Y", 1000, 1000));// Set cursor.
stream("\u001b*t300R"); // 300 DPI
stream(String.Format("\u001b*r{0:d}T", original.Height)); // Height
stream(String.Format("\u001b*r{0:d}S", original.Width)); // Width
stream("\u001b*r3U"); // 8-bit color palette
stream("\u001b*r0F"); // Follow logical page layout (landscape, portrait, etc..)
// Set palette depth, 3 bytes per pixel RGB
stream("\u001b*v6W\u0000\u0003\u0000\u0008\u0008\u0008");
stream("\u001b*r1A"); // Start raster graphics
stream("\u001b*b0M"); // Compression 0 = None, 1 = Run Length Encoding
// Not fast, but fast enough.
List<byte> colors = new List<byte>();
for (int y2 = 0; y2 < original.Height; y2++)
{
colors.Clear();
for (int x2 = 0; x2 < original.Width; x2++)
{
Color c = newBitmap.GetPixel(x2, y2);
colors.Add(c.R);
colors.Add(c.G);
colors.Add(c.B);
}
stream(String.Format("\u001b*b{0}W", colors.Count)); // Length of data to send
streamBytes(colors.ToArray()); // Binary data
}
stream("\u001b*rB"); // End raster graphics (also tried *rC -- no effect)
}
There are a few problems with your code. First off your cursor position code is incorrect, it should read:
"\u001b*p{0:d}x1:d}Y", 1000, 1000
This equates to:
<esc>*p1000x1000Y
you had:
<esc>*p1000x*p1000Y
When joining PCL commands together you match up the same parameterized value and group and then simply add value + parametrized character + value + parametrized character etc. Ensure that the final parametrized character is a capital letter which signifies the end of the PCL command.
Also when defining an image I recommend you also specify the width & hight in decipoints, this should help with the scaling of the image (*r3A) on the page so add this (just after your resolution command should be an okay place for it):
Int32 deciHeight = original.Height / (int)original.HorizontalResolution * 720;
Int32 deciWidth = original.Width / (int)original.VerticalResolution * 720;
stream("\u001b*t{0:d}h{1:d}V", deciHeight, deciWidth));
The other recommendation is to write all of this to file (watch your encodings) and use one of the handful of PCL viewers to view your data vs. always printing it. Should save you some time and a forest or two! I've tried all of them and wold recommend spending the $89 and purchasing pclWorks. They also have a complete SDK if you are going to do a lot of PCL. We don't use that as we hardcode all PCL ourselves but it does look good.
As for rotation, we've had problems on some device, You could just rotate the the jpg first (original.RotateFlip) an then write it out.
I don't have much time today but hope that my comments assist. I can test your code on Monday or Tuesday and work with it and post any further comments.
Keep in mind that even though PCL is a standard its support from manufacturer to manufacturer and device to device can be a problem and vastly different. When doing basic things most devices seem okay; however, if you get into macros or complex graphics you will find difference.

Categories