I am trying to write an algorithm that rotates one square around its centre in 2D until it matches or is "close enough" to the rotated square which started in the same position, is the same size and has the same centre. Which is fairly easy.
However the corners of the square need to match up, thus to get a match the top right corner of the square to rotate must be close enough to what was originally the top right corner of the rotated square.
I am trying to make this as efficient as possible, so if the closeness of the two squares based on the above criteria gets worse I know I need to try and rotate back in the opposite direction.
I have already written the methods to rotate the squares, and test how close they are to one another
My main problem is how should I change the amount to rotate on each iteration based on how close I get
E.g. If the current measurement is closer than the previous, halve the angle and go in the same direction otherwise double the angle and rotate in the opposite direction?
However I don't think this is quite a poor solution in terms of efficiency.
Any ideas would be much appreciated.
How about this scheme:
Rotate in 0, 90, 180, 270 angle (note that there are efficient algorithm for these special rotations than the generic rotation); compare each of them to find the quadrant you need to be searching for. In other word, try to find the two axis with the highest match.
Then do a binary search, for example when you determined that your rotated square is in the 90-180 quadrant, then partition the search area into two octants: 90-135 and 135-180. Rotate by 90+45/2 and 180-45/2 and compare. If the 90+45/2 rotation have higher match value than the 180-45/2, then continue searching in the 90-135 octant, otherwise continue searching in the 135-180 octant. Lather, Rinse, Repeat.
Each time in the recursion, you do this:
partition the search space into two orthants (if the search space is from A to B, then the first orthant is A + (A + B) / 2 and the second orthant is B - (A + B) / 2)
check the left orthant: rotate by A + (A + B) / 4. Compare.
check the right orthant: rotate by B - (A + B) / 4. Compare.
Adjust the search space, either to left orthant or the right orthant based on whether the left or right one is have higher match value.
Another scheme I can think of is, instead of trying to rotate and search, you try to locate the "corners" of the rotated image.
If your image does not contain any transparencies, then there are four points located at sqrt(width^2+height^2) away from the center, whose color are exactly the same as the corners of the unrotated image. This will limit the number of rotations you will need to search in.
...also, to build upon the other suggestions here, remember that for any rectangle you rotate around its center, you only need to calculate the rotation of a single corner. You can infer the other three corners by adding or substracting the same offset that you calculated to get the first corner. This should speed up your calculations a bit (assuming [but not thinking] that this is a bottleneck here).
Related
Consider this image:
I can (have!) written the code to locate each individual lilypad (i.e. those red squares, which aren't in the original image)
To a human, those individual lily pads form a very obvious 12 x 12 square grid, and it would be trivial to get a human to assign those pads into a 2D array of pads, at which point I can do any number of more interesting things with them.
But they aren't ACTUALLY in a nice grid. They're not rectilinear, they're not even uniformly offset.
How can I fit the pads (or equivalently, the top left corners of each square) onto a rectilinear grid. (Or what are the keywords necessary to find existing algorithms to do this)
Bonus 90s-kid-points for identifying the source ;)
You can choose the first square (any of them), give it a virtual coordinate (0, 0) and add this square to the queue. Then on each step, pop a square from the queue and try to find best top/bottom/left/right neighbors. For example, when finding a top neighbor we can minimize function equal to |current.top - x.bottom| + |current.left - x.left|. Then if this best neighbor square is not in the queue you add it to the queue with new coordinates (current.x, current.y + 1) and so on. If you get suspiciously large best distance - you are on the edge and you don't need to add a neighbor.
When the queue is empty you will get all squares with relative (to the chosen first square) coordinates and can transform them into the grid coordinates you need.
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 was looking at this doc: https://code.google.com/p/fractalterraingeneration/wiki/Perlin_Noise
And in the document it says:
top-left: just x, y
top-right: x-1
bottom-left: x, y-1
bottom-right: x-1, y-1
This may seem counter-intuitive, but it is to adjust for the possibly negative values in the gradients. Gradients pointing left or down will have negative values, so subtracting 1 from the values compensates for this. I admit I'm still not 100% clear on this, but it is a necessary step.
Am I right in assuming that this only applies if we plan to draw pixels using the final final as the weight? Otherwise, there is no need to subtract 1, correct?
As shown by the last image on the page you've linked, the authour is quite wrong about the -1's in the paragraph quoted. The actual purpose is to generate the four corners of a grid region from a single input point, this axis-aligned square grid is precisely the region size Perlin Noise is designed to operate in.
If the four points are generated in a way that does not correctly align with adjacent patches (like x+1 in a left to right count, or y-1 in a bottom up count), the image breaks sharply on the patch boundaries as that author describes at the bottom of page. Choosing the same point four times (not adding or subtracting anything) turns the entire patch into a single pixel - generating a white noise image with wasted computation.
I'm using OpenCV to match a bunch of viewpoints into a panorama. The result is a bunch of images on a black background (sort of a polygonal shape). What I want to do is crop this polygon so that there is no black in the resulting image. Is there a good algorithm to do this?
The naive way I am thinking is to start with a small square in the middle of the image and expand upwards until I hit black, then expand left and right.
The solution I want is the one that maximizes the total area of the filled region.
EDIT: The polygon is concave so we need to check for that -- I think the O(N^2) algorithm of trying every vertex pair is feasible as N is small. But we need to check that the region bound is filled which I guess could be done in O(N) by checking every vertex to see if it lies within the bounds of the rectangle defined by the vertex pair we picked. This gives us a O(N^3) algorithm
The naive solution may not work well because usually making the rectangle taller will limit its width, so you will not get the optimal solution.
If you do not have too many vertices on the polygon, the following might work: try picking every combination of top and bottom edges. To simplify, assume that they will always include one of the vertices of the polygon. When the top and bottom are specified, the sides can be determined, so for each pair of top/bottom you can calculate the area. Pick the solution that gives the largest area.
The simplification above may give suboptimal results, but it shouldn't be too bad.
Let's assume the polygon is convex on a discrete XY grid. Then the entire shape of the polygon can be represented by an array of (x1,x2) pairs, one for each Y coordinate in the grid. You get this array of (x1,x2) pairs by tracing the edges of the polygon.
You know the square has to touch the polygon in two diagonal points at least, either upper-left-lower-right or lower-left-upper-right.
At each left-edge point, you can find the closest point to the right, the closest directly up and directly down, and the closest point on each diagonal, 45 degrees up and down. If the distance on a diagonal is equal or less than any of the rectilinear distances, you have a square that fits in the polygon. There may be more than one, so keep going to find the largest one.
Considering the limited number of images likely to be in the panorama, you could use a brute force method and try all possible combinations. The user could never tell the difference, and the writing and maintenance of the function would probably be faster. It's just not as interesting that way, though.
Seems like a line sweep algorithm would work well. Start with, say, a vertical line on the left edge and move it to the right some x increment at a time. At each stop, look at every line segment of the line that's internal to the polygon. (There could be more than one when it's concave.) Consider sub-line-segments along the line segment.
Then take horizontal lines from each endpoint of the sub-line-segment and find the crossing intersections with the polygon (in both directions) to find the largest rect containing that sub-line-segment.
Performance could be O(nxny2), though you can reduce it with heuristics and adaptive step sizes.
A case that might be missed by too many assumptions or shortcuts is:
+------\ /---+
| \ / |
\ \/ /
\ /
/ \
/ /\ \
| / \ |
+----/ \-----+
Try distance transform if working with pixels, find the maximum point and then based on this position find maximum square within region by expanding square/rectangle as you mention
If I tile squares, and the squares can be defined by their coordinates, how can I simplify shapes made of multiple squares into vectors that define each edge of the entire shape? Pseudo-code or general terms are fine.
The first thing I can think of is (probably not the most efficient way) :
1) Get the bounding box of your entire tiling - which is min(x), min(y) to max(x), max(y) for all x and y of your tiles
2) For every row, start with STATE==EMPTY, iterate over each column : STATE changes to FULL when you hit a square, and EMPTY when you find a hole. Every time STATE goes from EMPTY to FULL, save the left hand line segment of that square and every time STATE goes from FULL to EMPTY, save the right hand line segment of that square.
3) Repeat above in the Y axis
Now you have a set containing only the outermost line segments, you can combine those that are co-linear etc and get the overall shape.
This will work for non-convex shapes and also if you have holes in your tiling.