How do I get a flood fill algorithm to cope with closed circles? - algorithm

I have an application that accepts images as input and removes the background on which the image was taken. For example, if you pass in an image of a book on a blanket, the resulting image will be just the book with a transparent background.
The problem I have is when you input an image that has a large empty space in it, e.g. an elastic band. The floodfill algorithm starts at the corners of the image and removes the background of the picture, but of course it never makes it into the interior of the elastic band.
Is there a way of implementing this such that I can take an image of a closed circle against a background and get back just the loop itself, with no background inside or outside it?

You could always resample the image after every flood fill, and restart it whenever you find a color that matches the original background.
Flood fill algorithms are designed to start in one spot, and from there fill a constrained area, an area of similar colors. The circle does not match that background color, so the fill algorithm doesn't "jump" it to find others.
The solution is to flood different areas.
Here is a very crude, recursive, slow flood fill algorithm (from memory, untested):
public void floodfill(Image img, int x, int y, Color oldColor, Color newColor) {
// Check boundary
if (img.contains(x, y)) {
// Get current pixel color
Color currentColor = img.getColor(x, y);
// Check color match
if (currentColor.equals(oldColor)) {
// Set to new color
img.setColor(x, y, newColor);
// Start again on each of the neighbors
floodFill(img, x - 1, y, oldColor, newColor);
floodFill(img, x + 1, y, oldColor, newColor);
floodFill(img, x, y - 1, oldColor, newColor);
floodFill(img, x, y + 1, oldColor, newColor);
}
}
}

This question, and its answers address a very similar problem.

you can figure out what the predominant color of the background is (Which you should be able to do since you're able to remove the background starting at the corners) and look for that color everywhere else in the image.

Related

How to get the four corners of a rotated image?

I have an image rotated with imrotate as follow:
Im_requete=imread('lena.jpg');
Im_requete_G=rgb2gray(Im_requete);
Im_requete_G_scale_rot = imresize(imrotate(Im_requete_G,-20), 1.2);
I'm trying to get the coordinates (x, y) of the four corners of the rotated image as illustrated in the image below (red circle represents the desired corner):
This is my code:
stat = regionprops(Im_requete_G_scale_rot,'Extrema'); %extrema detection of the image.
point = stat.Extrema;
hold on
figure,imshow(Im_requete_G_scale_rot)
hold on
for i = 2:2:length(point)
x = point(i,1);
y = point(i,2);
plot(x,y,'o');
text(x,y,num2str(i),'color','r')
end
But the resulting coordinates are somewhere along the edges and not where I wanted them to be, as illustrated in the second image:
Can someone please tell me what's wrong with this code?
I don't have a good explanation for this, but I suppose regionprops gets confused by the grayscale tones in the image. If we turn the rotated Lena into a logical array, your algorithm works properly:
Im_requete_G_scale_rot = logical(imresize(imrotate(Im_requete_G,-20), 1.2)); % 3rd line

outlining text in processing

My goal is to obtain an outline of text that is 1 pixels wide.
It could look something like this: https://jsfiddle.net/Lk1ju9yw/
I can't think of a good way to go about this so I did the following (in pseudocode):
PImage img;
void setup() {
size(400, 400);
// use text() to write on the canvas
// initialize PImage img
// load pixels for canvas and img
// loop thru canvas pixels and look for contrast
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
// compare canvas pixels at x-y with its neighbors
// change respective pixel on PImage img so as not to disturb canvas
}
}
// update pixels and draw img over the canvas
img.updatePixels();
img(img, 0, 0);
}
In a nutshell, I wrote white text on a black background on the canvas, did some edge detection and drew the results on a PImage, then used the PImage to store the results. I guess I could have skipped the PImage phase but I wanted to see what the edge detection algorithm produced.
So this does a decent job of getting the outline but there are some problems:
The outline is sometimes 1+ pixels wide. This is a problem. Suppose I want to store the outline (ie. all the positions of the white pixels) in an ArrayList.
For example, if using the ArrayList I draw an ellipse at EVERY point along the outline, the result is ok. But if I want the ellipses spaced apart, the ellipse-outline becomes kind of rough. In the fiddle I provided, the left edge of the letter 'h' is 2 pixels wide. Sometimes the ellipse will be drawn at the inner pixel, sometimes at the outer. That kind of thing makes it look ugly.
Elements of the ArrayList might be neighbors in the ArrayList, but not on the PImage. If I want to draw a circle for every 10th ArrayList location, the result won't necessarily be spaced apart on the PImage.
Here is an example of how ugly it can be: https://jsfiddle.net/Lk1ju9yw/1/
I am quite sure I understand why this is happening. I just don't know how to avoid it.
I also believe there is a solution (a PFont method) in p5.js. I am comfortable using p5 but unless I have to (let's say, because of difficulty), I would rather use processing. I've also heard of some libraries in processing that can help with this. Partly, I am interested in the result, but I am also interested in learning if I can program a solution myself (with some guidance, that is).
You can get an outline of text very easily in P5.js, because text honors the fill and stroke colors. So if you call noFill() the text will not be filled in, and if you call stroke(0) the text will have a black outline.
function setup() {
createCanvas(400, 200);
noSmooth();
}
function draw() {
background(220);
textSize(72);
textAlign(CENTER);
noFill();
stroke(0);
text("hey", width/2, height/2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
Unfortunately this approach won't work in regular Processing, because it just uses the stroke color for text. I'm not totally sure about Processing.js, but my guess is it's the same as Processing.
If you draw this to a buffer (using createGraphics()), then you can iterate over the buffer to get a list of points that make up your outline.
Now, as for putting the points in the correct order, you're going to have to do that yourself. The first approach that occurs to me is to sort them and group them by letter.
For example, your algorithm might be:
Find the upper-left-most point. Add it to your list.
Does that point you just added have any neighbors? If so, pick one and add it to your list. Repeat this step until the point has no neighbors.
Are there any points left? If so, find the point closest to the one you just added, and add it to your list. Go to step 2.
This might not be perfect, but if you want something more advanced you might have to start thinking about processing the list of points: maybe removing points that have a left neighbor, for example. You're going to have to play around to find the effect you're looking for.
This was an interesting question., thanks for that. Good luck, sounds like a fun project.

How can i fill a shape with different colours for each pixel?

i'm trying to draw a shape( using rect()) and i want to work on every single pixel within the shape and change the colour of every pixel.
I think i cannot use fill() because it fills the shape with only one colour.
What can i do?
Thanks.
I think what you are looking for is pixels array and the set() function related to it.
The pixels array stores the color of each pixel in your sketch :
Array containing the values for all the pixels in the display window. These values are of the color datatype. This array is the size of the display window. For example, if the image is 100x100 pixels, there will be 10000 values and if the window is 200x300 pixels, there will be 60000 values.
However, you need to call loadPixels() before accessing this array or it might result in a NullPointerException.
For this particular case, you don't need to access that array but I thought it would be useful to mention that here.
Now, coming to the solution. Once you have loaded the pixels, you can use the set(x, y, c) method to set the color value of a pixel. The method takes 3 arguments :
The x and y parameters specify the pixel to change and the c parameter specifies the color value. The c parameter is interpreted according to the current color mode. (The default color mode is RGB values from 0 to 255.)
So, if you know the top-left coordinates and the dimensions of your rect you could use nested for loops to iterate over every pixel of your rect and set the color of that pixel using set(x, y, c)
A sample sketch would look something like this :
int x, y;
int length, breadth;
void setup() {
size(400, 400);
x = 100;
y = 50;
length = 80;
breadth = 60;
}
void draw() {
background(51);
rect(x, y, length, breadth);
loadPixels();
for (int i=x; i<x+length; i++) {
for (int j=y; j<y+breadth; j++) {
set(i, j, color(random(255), random(255), random(255)));
}
}
}
Note that you can get away without calling loadPixels() in this case because you never actually access the elements of the pixels array.
The rect() function is an easy way to draw a simple rectangle. What you're describing is not that simple, so you can't use the rect() function to do it.
Instead, you could just use a nested for loop to iterate over the pixels you want to change, and then call stroke() to set the color and then point() to draw a point. Do that for every pixel you want to fill in. You might also want to call noSmooth() first to avoid drawing semi-opaque points.
More info can be found in the reference.

Find number of white/black pixels in binary image

I have an binary word image with grid and i want to find the foreground pixels (number of black and white in each segments) in each segments
So I just wanted to get the total number of black pixels for an image and I didn't want to segment it. Didn't feel like having to learn how to segment a matrix.
Easy fix to get the sum of the black pixels:
sum(sum(bw == 0))
Conversely to get the white pixels
sum(sum(bw == 1))
The operation function sum(bw == 0) just gets everything to a [1xn] matrix, so you will need to perform sum and you will get the whole image matrix summed.
Thought that cumsum would do the trick, but sum(sum()) is just better for this case. Tells you how little I know about coding. Have fun with this info, note that I'm just using this to determine the area coverage of a binarized image, but for anything else particularly useful.
Assume your black and white image is bw
sum(bw==0) // number of black pixels
sum(bw==1) // number of white pixels
For each grid find the range in both directions, then apply the same idea.
For example, from x1 to x2 and y1 to y2 is one grid:
sum(bw(x1:x2, y1:y2) == 0) // will give you the black pixels you want
That is easy with logical indexing.
For each segment, do:
n_white=sum(segment(:)==1);
n_black=sum(segment(:)==0);

Rotating rectangles so they maintain their relative position to the canvas

I have a background pixmap, basically a canvas, which I draw a bunch of
rectangles on and I need to rotate the pixmap and rectangles.
However rotating the background pixmap and the rectangles needs to be done
seperately, that is the rotation of the background pixmap gets handled via an
external library routine and I need to rotate and redraw the rectangles
on top manually.
So far I am actually able to rotate the rectangles by applying a
transformation matrix I got from Wikipedia
to each vertex. What I don't know is how to translate them that each rectangle retains its position relative to the canvas.
Here is a quick drawing for illustration of what I want to achieve:
I need to do this with C and Xlib, but I'm not necessarily looking for code but would appreciate some general hints/algorithms.
To get the translated position for the child object, you need to rotate the relative position vector for the child object, and then add it to the origin:
Pseudocode would be:
public static Vector2 OffsetByRotation(Vector2 childPos, Vector2 parentPos, float angle)
{
var relativeVector = childPos - parentPos;
relativeVector = Rotate(relativeVector, angle);
return parentPos + relativeVector;
}
Note that your example image not only rotates the parent object, but also translates it: your left image is rotated around (0, 300), but this point is then translated to (0, 0).
The requested transformation is
X' = 300 - Y
Y' = X

Resources