Fastest way to find reference point in image - image

i'm searching for the fastest way to find one or more reference points, (could be +, or a rectangle).
My first idea is, to go from the mid point of the image and look iterative in all 4 directions for the coloured pixels. But in this case it is not clear for me how to handle a symbol like + .
Hopefully my description is clear.
Greetings
UPDATE
Like in this image, the rectangle should normally in the mid. For the detection it would be ok, if the initial finding of the positions would take longer and a "check" must be really fast.:

I don't know the relative performance of all the aspects of the OpenCV code, but I assume it is pretty good at vector type operations across whole rows of an image rather than scalar operations such as you suggest when you propose doing ever increasing circles radiating from the centre to find the cross. Here is one approach that may work.
First, squidge (TM) all the pixels together to make a column as tall as the original image but just a single pixel wide. I have coloured this in red in the diagram. The darkest pixel in this column gives you the y-coordinate of your reference points.
Then, squidge (TM) all the pixels together to make a row as wide as the original image but just a single pixel high. I have coloured this in blue in the diagram. The darkest of the middle black bar then gives you the x-coordinate of your central reference point.
This will also handle small rotations as well as translations - and if the rotations are larger, you will get 3 black bars on the right.
You may also decide that, in general, and to save time, you only need process the image from the 1/3 to the 2/3 point in the vertical direction and the 1/4 to the 3/4 point in the horizontal direction since that is most likely to include the reference points.

Related

Algorithms: Ellipse matching

I have many images like the following (only white and black):
My final problem is to find well matching ellipses. Unfortunately the real used images are not always that nice like this. They could be deformed a bit, which makes ellipse matching probably harder.
My idea is to find "break points". I markes them in the following picture:
Maybe these points could help to make a matching for the ellipses. The end result should be something like this:
Has someone an idea what algorithm may be used to find these break points? Or even better to make good ellipse matching?
Thank you very much
Sample the circumference points
Just scan your image and select All Black pixels with any White neighbor. You can do this by recoloring the remaining black pixels to any unused color (Blue).
After whole image is done you can recolor the inside back from unused color (Blue) to white.
form a list of ordered circumference points per cluster/ellipse
Just scan your image and find first black pixel. Then use A* to order the circumference points and store the path in some array or list pnt[] and handle it as circular array.
Find the "break points"
They can be detect by peak in the angle between neighbors of found points. something like
float a0=atan2(pnt[i].y-pnt[i-1].y,pnt[i].x-pnt[i-1].x);
float a1=atan2(pnt[i+1].y-pnt[i].y,pnt[i+1].x-pnt[i].x);
float da=fabs(a0-a1); if (da>M_PI) da=2.0*M_PI-da;
if (da>treshold) pnt[i] is break point;
or use the fact that on break point the slope angle delta change sign:
float a1=atan2(pnt[i-1].y-pnt[i-2].y,pnt[i-1].x-pnt[i-2].x);
float a1=atan2(pnt[i ].y-pnt[i-1].y,pnt[i ].x-pnt[i-1].x);
float a2=atan2(pnt[i+1].y-pnt[i ].y,pnt[i+1].x-pnt[i ].x);
float da0=a1-a0; if (da0>M_PI) da0=2.0*M_PI-da0; if (da0<-M_PI) da0=2.0*M_PI+da0;
float da1=a2-a1; if (da1>M_PI) da1=2.0*M_PI-da1; if (da1<-M_PI) da1=2.0*M_PI+da1;
if (da0*da1<0.0) pnt[i] is break point;
fit ellipses
so if no break points found you can fit the entire pnt[] as single ellipse. For example Find bounding box. It's center is center of ellipse and its size gives you semi-axises.
If break points found then first find the bounding box of whole pnt[] to obtain limits for semi-axises and center position area search. Then divide the pnt[] to parts between break points. Handle each part as separate part of ellipse and fit.
After all the pnt[] parts are fitted check if some ellipses are not the same for example if they are overlapped by another ellipse the they would be divided... So merge the identical ones (or average to enhance precision). Then recolor all pnt[i] points to white, clear the pnt[] list and loop #2 until no more black pixel is found.
how to fit ellipse from selection of points?
algebraically
use ellipse equation with "evenly" dispersed known points to form system of equations to compute ellipse parameters (x0,y0,rx,ry,angle).
geometrically
for example if you detect slope 0,90,180 or 270 degrees then you are at semi-axis intersection with circumference. So if you got two such points (one for each semi-axis) that is all you need for fitting (if it is axis-aligned ellipse).
for non-axis-aligned ellipses you need to have big enough portion of the circumference available. You can exploit the fact that center of bounding box is also the center of ellipse. So if you got the whole ellipse you know also the center. The semi-axises intersections with circumference can be detected with biggest and smallest tangent change. If you got center and two points its all you need. In case you got only partial center (only x, or y coordinate) you can combine with more axis points (find 3 or 4)... or approximate the missing info.
Also the half H,V lines axis is intersecting ellipse center so it can be used to detect it if not whole ellipse in the pnt[] list.
approximation search
You can loop through "all" possible combination of ellipse parameters within limits found in #4 and select the one that is closest to your points. That would be insanely slow of coarse so use binary search like approach something like mine approx class. Also see
Curve fitting with y points on repeated x positions (Galaxy Spiral arms)
on how it is used for similar fit to yours.
hybrid
You can combine geometrical and approximation approach. First compute what you can by geometrical approach. And then compute the rest with approximation search. you can also increase precision of the found values.
In rare case when two ellipses are merged without break point the fitted ellipse will not match your points. So if such case detected you have to subdivide the used points into groups until their fits matches ...
This is what I have in mind with this:
You probably need something like this:
https://en.wikipedia.org/wiki/Circle_Hough_Transform
Your edge points are simply black pixels with at least one white 4-neighbor.
Unfortunately, though, you say that your ellipses may be “tilted”. Generic ellipses are described by quadratic equations like
x² + Ay² + Bxy + Cx + Dy + E = 0
with B² < 4A (⇒ A > 0). This means that, compared to the circle problem, you don't have 3 dimensions but 5. This causes the Hough transform to be considerably harder. Luckily, your example suggests that you don't need a high resolution.
See also: algorithm for detecting a circle in an image
EDIT
The above idea for an algorithm was too optimistic, at least if applied in a straightforward way. The good news is that it seems that two smart guys (Yonghong Xie and Qiang Ji) have already done the homework for us:
https://www.ecse.rpi.edu/~cvrl/Publication/pdf/Xie2002.pdf
I'm not sure I would create my own algorithm. Why not leverage the work other teams have done to figure out all that curve fitting of bitmaps?
INKSCAPE (App Link)
Inkscape is an open source tool which specializes in vector graphics editing with some ability to work with raster (bitmap) parts too.
Here is a link to a starting point for Inkscape's API:
http://wiki.inkscape.org/wiki/index.php/Script_extensions
It looks like you can script within Inkscape, or access Inkscape via external scripts.
You also may be able to do something with zero scripting, from the inkscape command line interface:
http://wiki.inkscape.org/wiki/index.php/Frequently_asked_questions#Can_Inkscape_be_used_from_the_command_line.3F
COREL DRAW (App Link)
Corel Draw is recognized as the premier industry solution for vector graphics, and has some great tools for converting rasterized images into vector images.
Here's a link to their API:
https://community.coreldraw.com/sdk/api
Here's a link to Corel Draw batch image processing (non-script solution):
http://howto.corel.com/en/c/Automating_tasks_and_batch-processing_images_in_Corel_PHOTO-PAINT

Closest distance to border of shape

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.

How to smoothen a jagged border of an image into a straight line?

I have an image like this (thresholding, noise removal, etc. completed):
My final output should be an image without any of the jagged edges, and smaller than the given image. By this, I mean to say that the only difference between the 2 images must be that in the new one, the jagged edges must be removed, and not the jagged edges filled in. Like so (the final image must be the region within the red border, the red border is shown only for explanation):
I was thinking of something along the lines of using Hough transforms, or of using dilations and then erosions, but nothing seems to be working (probably my fault, because I have not worked in too much detail with them before).
Note that the language I'd like t do this in is MATLAB.
There are 2 primary aims to this:
To get the edges themselves, using Hough transforms
So that the 'Extrema' property returns the desired pints when using regionprops, like so:
The question, in a more concise form:
How would I go about extracting this T in MATLAB, such that it does not have rugged edges, but the overall figure is not larger than the original, as shown in the second figure above? In other words, what set of transformations (in MATLAB) would I use to smoothen the borders of the image with as little of the area lost as little as possible (but no area added) such that ruggedness disappears?
Is there a more efficient way of extracting the corner (extrema) points as shown in figure 2 above without requiring to go through step 1?
EDIT:
A few more sample images:
NB: All images in consideration will be composed of rectangles approximately at 90 to each other, and no other figure. So smoothening an image with a curved edge, for example, would be beyond the scope of an answer to this question (or even, for that matter, a trapezium, although I think that smoothening 2 straight edges should be the same, irrespective of whether the edge has another parallel to it or not).
Here are a few more images, for reference:
I'm not sure if my answer would satisfy your requirements. I'm putting it here because I think it's too long for a comment.
since you want the final output to be smaller than the input image, erode the input image. You can pick an appropriate kernel size.
perform a corner detection on this eroded image. This will give you all strong corners, but without any order
trace the boundaries of the eroded image. This should give you an ordered list of boundary pixels
now, with the help of these ordered boundary points you can order the corners that you found earlier
filter corner points that form approximately 90 degrees of angle. You can do this considering each 3 ordered corner points (two green points and the red point in between in the image below. It's just for illustration, not corner points that I calculated. At the end of this operation, you have all red points in the image below which are at strong corners, in addition to other yellow and green corner points)
now you can either find the equation of the line connecting 2 consecutive red points
or
fit a least-squares-line to the points between (and including) each 2 consecutive red points
since you did all this processing on a eroded image that is essentially smaller than the original image, you should get a smaller shape

Recreate image using only overlapping squares

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.

2D raster image line of sight algorithm

I'm working on a simple mapping application for fun, and one of the things I need to do is to find (and color) all of the points that are visible from the current location. In this case, points are pixels. My map is a raster image where transparent pixels are open space, and any other pixels are opaque. (There are no semi-transparent pixels; alpha is either 0 or 100%.) In this sense, it's sort of like a regular flood fill, with the constraint that each filled pixel has to have a clear line-of-sight to the origin point. The following image shows a couple of such areas colored in (the tiny crosshairs are the origin points, and white = transparent):
(http://tinyurl.com/nf3nqa4)
In addition, what I am ultimately interested in are the points that "border" other colors, i.e., I want the list of points that make up the edge of the visible region.
My current and very inefficient solution is the modified flood-fill I described above. This approach returns correct results, but due to the need to iterate every pixel on a line to the origin for every pixel in the flood fill, it's very slow. My images are downsized and quantized, but I still need about 1MP for acceptable accuracy, and typical LoS areas are at least 100,000 pixels each.
I may well be using the wrong search terms, but I haven't been able to find any discussion of algorithms that would solve this (rasterized) LoS case.
I suspect that this could be done more efficiently if your "walls" were represented as equations rather than simply pixels in a raster image. For example, polygons/triangles, circles, ellipses.
It would then be like raytracing (search for this term) in 2D. In other words, you could consider the ray/line from each pixel in the image to the point of interest and color the pixel only if it does not intersect with any object.
This method does require you to test the intersection for each pixel in the image with each object; however, if you look up raytracing you will find a number of efficient methods for testing these intersections. They will mostly be for the 3D case but it should be straightforward to convert them to 2D.
There are 3D raytracers that are very fast on MUCH larger images so this should be very doable.
You can try a delaunay triangulation on each color. I mean you can try to find the shape of each color with DT.

Resources