I'm quite confused as to how either flood fill or boundary fill color areas. Specifically when multiple colors are in play.
Let's say we have a polygon with a green border and a checkered interior (black and white). Which algorithm would fill the area correctly with green and why?
Definition of flood fill from the book:
Sometimes we want to fill in (or recolor) an area that is not defined within a single color boundary. We can pain such areas by replacing a specified interior color instead of searching for a particular boundary color. This fill procedure is called a flood-fill algorithm.
You Should Use Boundary Fill Algorithm.
If Keeps Coloring the region inward to outward until a selected boundary color is encountered.
in your case, The boundary color will be Green. So the algo will start from any inside point and proceed outward pixel by pixel until a green(boundary) is encountered. The black or white wont matter here.
flood fill starts at any point inside the polygon, then spreads out in all directions filling pixels. A boundary fill finds the first boundary then traces the boundary, winding into the interior. Boundary fill is usually more complicated but it is a linear algorithm and doesn't require recursion, whereas a flood fill may use an unpredictable amount of memory to finish because it isn't known how many sub-fills will be spawned.
Actually you should not see multiple colors in the filling problem, but rather two categories: the "is-a-border" color or set of colors and the "is-not-a-border" ("inside") color or set of colors. It is a simple dichotomy, as if the image was binary.
In the case you mention, border is green and inside is black-or-white (you can also consider not-green).
Related
I am writing a code that generate start and end points of strokes of a picture (Raster images) to let robot arm paint.
I have wrote an algorithm but with too many overlapping strokes:
https://github.com/Evrid/Painting-stroke-generation-for-robot-arm-or-CNC-machine
The input of my algorithm:
and the output (which is mirrored and re-assigned to the colors I have) with 50 ThresholdOfError (you can see the strokes are overlapping):
Things to notice are:
*The strokes needs to be none overlapping (if overlapping then have too many strokes)
*Painting have different colors, the same color better draw together
*The stroke size is like rectangles
*Some coloring area are disconnected, like below only yellow from a sun flower:
I am not sure which algorithm should I use, here is some possible ones I have thought about:
Method 1.Generate 50k (or more) random direction and position large size rectangles, if its area overlap the same color area and not overlapping other rectangles, then keep it, then decrease generated rectangle size and after a couple rounds keep decreasing again
Method 2.Extract certain color first then generate random direction and position large size rectangles (we have less area and calculation time)
Method 3.Do edge detection first, then rectangles are generated with direction along the edge, if its area overlap the same color area and not overlapping other rectangles, then keep it, then decrease generated rectangle size and after a couple rounds keep decreasing again
Method 4: Generate random circle, let the pen draw points instead (but may result too many points)
Any suggestions about which algorithm I should use?
I would start with:
Quantize your image to your palette
so reduce colors to your palette first see:
Effective gif/image color quantization?
Converting BMP image to set of instructions for a plotter?
segmentate your image by similar colors
for this you can use flood fill or growth fill to create labels (region index) in form of ROI
see Fracture detection in hand using image proccessing
for each ROI create infill path with thick brush
this is simple hatching you do this by generating zig zag like path with "big" brush width in major direction of ROI so use either AABB or OBB or PCA to detect major direction (direction with biggest size of ROI) and just AND it with polygon ROI
for each ROI create outline path with "thin" brush
IIRC this is also called contour extraction, simply select boundary pixels of selected ROI
then you can use A* on ROI boundary to sort the pixels into 2 halves (or more if complex shape with holes or thin parts) so backtrack the pixels and then reorder them to form a closed loop(s)
this will preserve details on boundary (while using infill with thick brush)
Something like this:
In case your colors are combinable you can use CMY color space and Substractive color mixing and process each C,M,Y channel separately (max 3 overlapping strokes) to have much better color match.
If you want much better colors you can also add dithering however that will slow down the painting a lot as it requires much much more path segments and its not optimal for plotter with tool up/down movement (they are better for printing heads or printing triggered without additional movements ...). To partially overcome this issue you could use partial dithering where you can specify the amount of dithering created (leading to less segments)
there are a lot of things you can improve/add to this like:
remove outline from ROI (to limit the overlaps and prevent details overpaint)
do all infills first and then all outlines
set infill brush width based on ROI size
adjust infill hatching pattern to better match your arm kinematics
order ROIs so they painted faster (variation of Traveling Sailsman problem TSP)
infill with more than just one brush width to preserve details near borders
Suggest you use the flood fill algorithm.
Start at top right pixel.
Flood fill that pixel color. https://en.wikipedia.org/wiki/Flood_fill
Fit rectangles into the filled area.
Move onto the next pixel that is not in the filled area.
When the entire picture has been covered, sort the rectangles by color.
I have an image which has plain dots scattered across. The dots are of the same size and they are solid (I can read the color to decide whether a point is inside or not). What is the most efficient algorithm to find the exact number of the dots?
I thought of Monte Carlo, but I don't know the sufficient number of random points that I should use. Any advice?
Edit: it's a white image that contains dots only.
This is good case for image processing algorithms.
For example, using OpenCV library, you could exploit the next approach:
If image format is color, convert it to gray scale (cvtColor)
Make image binary (pure black and white) with color inversion (cvThreshold with THRESH_BINARY_INV) to make white spots on the black background
Find connected components (findContours) - after that contours.size gives you number of dots
If you don't want to use any libraries, key point is connected components labeling
The simplest way to make CCL for small dots - using of Floodfill algorithm.
Make flood fill for background pixels, mark them with 0.
Scan through all pixels. When you meet unmarked one (at X,Y), start new flood fill with next marker value K (1,2 etc).
After each floodfill return to the next coordinate (X+1,Y) and continue scanning.
The last K value is the number of spots.
I have a shape (in black below) and a point inside the shape (red below). What's the algorithm to find the closest distance between my red point and the border of the shape (which is the green point on the graph) ?
The shape border is not a series of lines but a randomly drawn shape.
Thanks.
So your shape is defined as bitmap and you can access the pixels.
You could scan ever growing squares around your point for border pixels. First, check the pixel itself. Then check a square of width 2 that covers the point's eight adjacent pixels. Next, width 4 for the next 16 pixels and so on. When you find a border pixel, record its distance and check against the minimum distance found. You can stop searching when half the width of the square is greater than the current minimum distance.
An alternative is to draw Bresenham circles of growing radius around the point. The method is similar to the square method, but you can stop immediately when you have a hit, because all points are supposed to have the same distance to your point. The drawback is that this method is somewhat inaccurate, because the circle is only an approximation. You will also miss some pixels along the disgonals, because Bresenham circles have artefacts.
(Both methods are still quite brute-force and in the worst case of a fully black bitmap will visit every node.)
You need a criterion for a pixel on the border. Your shape is antialiassed, so that pixels on the border are smoothed by making them a shade of grey. If your criterion is a pixel that isn't black, you will chose a point a bit inside the shape. If you cose pure white, you'll land a bit outside. Perhaps it's best to chose a pixel with a grey value greater than 0.5 as border.
If you have to find the closest border point to many points for the same shape, you can preprocess the data and use other methods of [nearest-neighbour serach].
As always, it depends on the data, in this case, what your shapes are like and any useful information about your starting point (will it often be close to a border, will it often be near the center of mass, etc).
If they are similar to what you show, I'd probably test the border points individually against the start. Now the problem is how you find the border without having to edge detect the entire shape.
The problem is it appears you can have sharply concave borders (think of a circle with a tiny spike-like sliver jutting into it). In this case you just need to edge detect the shape and test every point.
I think these will work, but don't hold me to it. Computational geometry seems to be very well understood, so you can probably find a pro at this somewhere:
Method One
If the shape is well behaved or you don't mind being wrong try this:
1- Draw 4 lines (diving the shape into four quandrants). And check the distance to each border. What i mean by draw is keep going north until you hit a white pixel, then go south, west, and east.
2- Take the two lines you have drawn so far that have the closest intersection points, bisect the angle they create and add the new line to your set.
3- keep repeating step two until are you to a tolerance you can be happy with.
Actually you can stop before this and on a small enough interval just trace the border between two close points checking each point between them to refine the final answer.
Method Two (this wil work with the poorly behaved shapes and plays well with anti-aliasing):
1- draw a line in any direction until he hit the border (black to white). This will be your starting distance.
2- draw a circle at this distance noting everytime you go from black to white or white to black. These are your intersection points.
As long as you have more than two points, divide the radius in half and try again.
If you have no points increase your radius by 50% and try again (basically binary search until you get to two points - if you get one, you got lucky and found your answer).
3- your closet point lies in the region between your two points. Run along the border checking each one.
If you want to, to reduce the cost of step 3 you can keep doing step 2 until you get a small enough range to brute force in step 3.
Also to prevent a very unlucky start, draw four initial lines (also east, south, and west) and start with the smallest distance. Those are easy to draw and greatly reduce your chance of picking the exact longest distance and accidentally thinking that single pixel is the answer.
Edit: one last optimization: because of the symmetry, you only need to calculate the circle points (those points that make up the border of the circle) for the first quadrant, then mirror them. Should greatly cut down on computation time.
If you define the distance in terms of 'the minimum number of steps that need to be taken to reach from the start pixel to any pixel on the margin', then this problem can be solved using any shortest path search algorithm like bread first search or even better if you use A* search algorithm.
I'm trying to take a source image, and recreate it on a transparent canvas using only overlapping mono-colored squares. The goal is to use as few squares as possible.
In other words, I'm taking a blank transparent image, and drawing squares of various colors until I recreate the source image, with the goal being to use as few squares as possible.
For example:
Here is a source image. It has two colors: red and green. I want to use only squares, that may overlap, to recreate the source image.
The ideal solution would be a large red square, and then two green squares drawn on top - that is what I want my algorithm to find, with any source image - the position, size, color and order of each square.
My target image that I intend to process is this:
(8x enlargement)
It has 1411 non-transparent pixels (worst case), and with a brute force solution that does not use overlapping squares, I've recreated the image using 1246 squares.
My current solution is a brute force method along the lines of:
Create a list of all colors used in the source image. Each item is a "layer". A layer has a color and a 2D array representing pixels. The order is important, but I don't know what order the layers need to be in, so its arbitrary initially.
For each layer in the list, initialize the 2D array. Each element corresponds to a pixel in the source image. Pixels that are the same color as the layer's chosen color is marked as '1'. Pixels that are in a layer ABOVE the current layer are marked as "don't care". All other pixels are marked as '0'.
Use some algorithm to process each layer, using the smallest number of squares to reach every pixel marked '1', without touching any pixels marked '0'.
Rearrange the order of layers and go back to Step 2. Do this for every possible combination of layers, then check to see which ordering uses the least number of squares in total.
Someone has perhaps a better explanation in a response; but brute force testing every permutation is not viable, because my target image has 31 colors (resulting in 31! permutations).
As for why I'm doing this? I'm trying to create an image in a game (Starbound), where I can only use squares. The lazy solution is to use a square for each pixel, but that's just too many squares.
Just a suggestion for a possible solution. I haven't tried it.
It's a greedy approach.
For every pixel, compute the largest uniform square that contains it.
Then choose the largest of all squares and mark all pixels it covers as "covered".
Then among all unmarked pixels, choose the largest covering square, and so on until no unmarked pixel remains.
Ties do no matter, just take any largest square and mark its pixels.
UPDATE: overlaps offer opportunities for reduction in the number of squares.
Consider all possible permutations of the filling order of the shapes. The shapes drawn first, on the bottom layers, can be (partly) hidden by some others. Process the shapes starting from the top layer. When you process a shape to associate every pixel with the largest uniform square that contains it, treat all covered pixels as don't care.
In the given example, fill the green squares first; then when filling the red square, the green pixels can be considered red or not, depending on convenience.
If you cannot try all permutations, then try them at random. Heuristic approaches such as genetic algorithms or simulated annealing could help. Nothing straightforward here.
It would be hard to guarantee an optimal solution. The brute force search would be huge. This calls for a heuristic.
Start at the edges. Walking the outside edge, find the most frequent color. Draw squares
to fill the background.
Iterate, working inwards drawing smaller and smaller squares which cover the most
pixels which are the wrong color. Ending with single-pixel squares.
Working inwards means to reduce the size of the bounding box, outside
of which all pixels are the correct color. At each step, the upper limit on the size of a square would be fitting in the bounding box. Choose the squares which give the best score.
Score is based on old vs new color being wrong or right, so there are 4 possible values for each pixel. One example function for per-pixel score would be:
wrong -> wrong: 0
wrong -> right: 1
right -> right: 1
right -> wrong: -2
I think that if you always reduce the number of wrong squares on the edge of the bounding box and never increase the size of the square, then the algorithm must halt with a solution without needing to backtrack. A backtracking solution could probably do better.
An "erosion-based" heuristic.
Consider all outline pixels, i.e. having at least a neighbor outside the shape.
Among these pixels, choose a color (the most frequent one ?).
For all outline pixels of this color, compute the largest square that does not exceed the shape.
Fill these squares, from larger to smaller, until the complete outline is covered.
Remove the correctly filled pixels and restart the procedure on the eroded shape.
In the case of the red square, all outline pixels will be covered by the red square itself, and the first filling will "consume" the whole area.
Then, removing the pixels covered in red, the two green square will remain.
All green outline pixels will now be covered by the two green squares, and the two first fillings will "consume" all green area.
I have an image like in the left side. I want to get covered areas or the arc points of polygons for getting image like in the right side. I have got end point-values of all lines.
How can I do that (get all covered areas)? Any algorithm or ideas?
The easiest way to do this is with a recursive fill technique.
Assuming you have a black and white image to start with, you drop a pixel of color on one region. You recursively fill the areas to the up, down, left, and right of that pixel. When each of those pixels returns (because all surrounding pixels are colored or black for wall) you return.
You can do this iteratively for each x,y coordinate, skipping it if it's already colord by a previous run. In doing this, you can iterate over colors as well, if you so desire.
This is a classic case of binary image segmentation, as far as I can see in the limited resolution of the input image. Invert your image, maybe erode it to fill holes in your lines, and then do an image segmentation. A trivial algorithm for this is to perform a forward scan of the image and assigning each pixel the region value of its backward (directly left or any above direction) white neighbours, or a new region value if it has only black backward neighbours, joining regions when there are neighbours with different region numbers.
As a second approach, if you have a list of unbroken lines, you might try a graph approach. Consider each line as an edge in a graph, and each intersection point as a node, and find the minimal cycles in the graph. These are your rooms.