How would you convert X,Y points to Rho,Theta for hough transform in C? - c

So I am trying to code Hough Transform on C. I have a binary image and have extracted the binary values from the image. Now to do hough transform I have to convert the [X,Y] values from the image into [rho,theta] to do a parametric transform of the form
rho=xcos(theta)+ysin(theta)
I don't quite understand how it's actually transformed, looking at other online codes. Any help explaining the algorithm and how the accumulator for [rho,theta] values should be done based on [X,Y] would be appreciated.Thanks in advance. :)

Your question hints at the fact that you think that you need to map each (X,Y) point of interest in the image to ONE (rho, theta) vector in the Hough space.
The fact of the matter is that each point in the image is mapped to a curve, i.e. SEVERAL vectors in the Hough space. The number of vectors for each input point depends on some "arbitrary" resolution that you decide upon. For example, for 1 degree resolution, you'd get 360 vectors in Hough space.
There are two possible conventions, for the (rho, theta) vectors: either you use [0, 359] degrees range for theta, and in that case rho is always positive, or you use [0,179] degrees for theta and allow rho to be either positive or negative. The latter is typically used in many implementation.
Once you understand this, the Accumulator is little more than a two dimension array, which covers the range of the (rho, theta) space, and where each cell is initialized with 0. It is used to count the number of vectors that are common to various curves for different points in the input.
The algorithm therefore compute all 360 vectors (assuming 1 degree resolution for theta) for each point of interest in the input image. For each of the these vectors, after rounding rho to the nearest integral value (depends on precision in the rho dimension, e.g. 0.5 if we have 2 points per unit) it finds the corresponding cell in the accumulator, and increment the value in this cell.
when this has been done for all points of interest, the algorithm searches for all cells in the accumulator which have a value above a chosen threshold. The (rho, theta) "address" of these cells are the polar coordinates values for the lines (in the input image) that the Hough algorithm has identified.
Now, note that this gives you line equations, one is typically left with figure out the segment of these lines that effectively belong in the input image.
A very rough pseudo-code "implementation" of the above
Accumulator_rho_size = Sqrt(2) * max(width_of_image, height_of_image)
* precision_factor // e.g. 2 if we want 0.5 precision
Accumulator_theta_size = 180 // going with rho positive or negative convention
Accumulator = newly allocated array of integers
with dimension [Accumulator_rho_size, Accumulator_theta_size]
Fill all cells of Accumulator with 0 value.
For each (x,y) point of interest in the input image
For theta = 0 to 179
rho = round(x * cos(theta) + y * sin(theta),
value_based_on_precision_factor)
Accumulator[rho, theta]++
Search in Accumulator the cells with the biggest counter value
(or with a value above a given threshold) // picking threshold can be tricky
The corresponding (rho, theta) "address" of these cells with a high values are
the polar coordinates of the lines discovered in the the original image, defined
by their angle relative to the x axis, and their distance to the origin.
Simple math can be used to compute various points on this line, in particular
the axis intercepts to produce a y = ax + b equation if so desired.
Overall this is a rather simple algorithm. The complexity lies mostly in being consistent with the units, for e.g. for the conversion between degrees and radians (most math libraries' trig functions are radian-based), and also regarding the coordinates system used for the input image.

Related

Check if geo location is within radius of other geolocation without using sin/cos/tan

I want to develop a simple geo-fencing algorithm in C, that works without using sin, cos and tan. I am working with a small microcontroller, hence the restriction. I have no space left for <math.h>. The radius will be around 20..100m. I am not expecting super accurate results this way.
My current solution takes two coordinate sets (decimal, .00001 accuracy, but passed as a value x10^5, in order to eliminate the decimal places) and a radius (in m). When multiplying the coordinates with 0.9, they can approximately be used for a Pythagorean equation which checks, if one coordinate lies within the radius of another:
static int32_t
geo_convert_coordinates(int32_t coordinate)
{
return (cordinate * 10) / 9;
}
bool
geo_check(int32_t lat_fixed,
int32_t lon_fixed,
int32_t lat_var,
int32_t lon_var,
uint16_t radius)
{
lat_fixed = geo_convert_distance(lat_fixed);
lon_fixed = geo_convert_distance(lon_fixed);
lat_var = geo_convert_distance(lat_var);
lon_var = geo_convert_distance(lon_var);
if (((lat_var - lat_fixed) * (lat_var - lat_fixed) + (lon_var - lon_fixed) * (lon_var - lon_fixed))
<= (radius * radius))
{
return true;
}
return false;
}
This solution works quite well for the equator, but when changing the latitude, this becomes increasingly inaccurate, at 70°N the deviation is around 50%. I could change the factor depending on the latitude, but I am not happy with this solution.
Is there a better way to do this calculation? Any help is very much appreciated. Best regards!
UPDATE
I used the input I got and managed to implement a decent solution. I used only signed ints, no floats.
The haversine formula could be simplified: due to the relevant radii (50-500m), the deltas of the latitude and longitude are very small (<0.02°). This means, that the sine can be simplified to sin(x) = x and also the arcsine to asin(x) = x. This approach is very accurate for angles <10° and even better for the small angles used here. This leaves the cosine, which I implemented according to #meaning-matters 's suggestion. The cosine will take an angle and return the actual result multiplied by 100, in order to be able to use ints. The square root was implemented with an iterative loop (I cannot find the so post anymore). The haversine calculation was done with the inputs multiplied by powers of 10 in order to achieve accuracy and afterwards divided by the necessary power of 10.
For my 8bit system, this caused a memory usage of around 2000-2500 Bytes.
Implement the Havesine function using your own trigonometric functions that use lookup tables and do interpolation.
Because you don't want very accurate results, small lookup tables, of perhaps twenty points, would be sufficient. And, simple linear interpolation would also be fine.
In case you don't have much memory space: Bear in mind that to implement sine and cosine, you only need one lookup table for 90 degrees of either function. All values can then be determined by mirroring and offsetting.

Question about performance for raytracing algorithm intersection test

I'm currently building a basic raytracing algorithm and need to figure out which system of handling the intersections would be best performance-wise.
In the method I'm checking for a intersection of the ray and the object I'm returning a struct with the distance of the ray traveled to the hit, the position vector of the hit and the normal vector or -1 for the distance if there is no intersection.
For the next step I have to find the shortest distance of all intersections and exclude the ones with a negative distance.
I even thought about having 2 structs, one with only negative distances and one full struct to reduce the amount of space needed, but thought this wouldn't really make a difference.
My options so far:
first go over the array of the intersections and exclude the ones with negative distances, then find the shortest distance from the remainings via a sorting algorithm (probably insertion sort due to quick implementation).
Or put them together in one algorithm and test in each sort step if the distance is negative.
typedef Point3f float[3];
typedef struct {
float distance;
Point3f point;
Point3f normal;
} Intersection;
Intersection intersectObject (Ray-params, object) {
Intersection intersection;
//...
if (hit) {
intersection.distance = distance;
intersection.point = point;
intersection.normal = normal;
} else {
intersection.distance = -1.0f;
}
return intersection;
}
//loop over screen pixel
Intersection* intersections;
int amountIntersections;
//loop over all objects
//here I would handle the intersections
if (amountIntersections) {
//cast additional rays
}
I can't really figure out what would be the best way to handle this, since this would be called a lot of times. The intersection array will probably be a dynamic array with the amountIntersections as the length variable or an array with the most expected amount of intersections which then have intersections in it with negative distances.
Here is the approach I've succesfully used for a huge number of objects. (Especially for ball-and-stick atomic models; see my Wikipedia user page for the equations I used for those.)
First, transform the objects to a coordinate system where the eye is at origin, and the projected plane is parallel to the xy plane, with center on the positive z axis. This simplifies the equations needed a lot, as you can see from the above linked page.
As an example, if you have a unit ray n (so n·n = 1) and a sphere of radius r centered at c, the ray intersects the sphere if and only if h ≥ 0,
h = (n·c)2 + r2 - (c·c)
and if so, at distance d,
d = n·c ± sqrt(h)
If you work out the necessary code, and use sensible temprary variables, you'll see that you can reject non-intersecting spheres using eight multiplications and six additions or subtractions, and that this vectorizes across objects easily using SSE2/AVX intrinsics (#include <x86intrin.h>). (That is, do not try to use an XMM/YMM vector register for n or c, and instead use each register component for a different object, calculating h for 2/4/8 objects at a time.)
For each ray, sort/choose the objects to be tested according to their known minimum z coordinate (say, cz - r for spheres). This way, when you find an intersection at distance d, you can ignore all objects with minimum z coordinate larger than d, because the intersection point would necessarily be further out, behind the already known intersection.
Similarly, you should ignore all intersections where the distance is smaller than the distance to the projection plane (which is zd / nz, if the plane is at z = zd, and only needs to be computed once per ray), because those intersections are between the eye and the projection plane. (Technically, you've "crashed into" something then, if you think of the projection plane as a camera.)

C floats : how to go around them for 2d geometry (lines)

I am currently doing some 2D geometry in C, mostly lines intersecting themselves. Those lines have all kinds of slopes : from 0.001 to 1000 (examples, I don't even know).
I was using floats until now and did not have to worry about whether the value was very small (and then floating point would store 0,0011 as 1e-3 with no rounding) or very high (and then 1001 would be stored as 1e3), with in both cases little loss of precision where relevant.
But now I want to try without floats, with integers. How to maintain precision in my calculations ? I could have a flag telling me whether the slope is going to be big or small and then consider a tenth of big slopes and ten times small slopes so that rounding is no problem for small slopes and there is no overflow in the case of big slopes. But that feels like a headache.
Basically I need to still be able to differentiate between a slope of 0.2 and 0.4 and also on the overflow side of things a slope of 1000 and 2000 (supposing that ints overflow at 1000 - less of a problem here).
Any other ideas?
Store the slope as a pair of integers
struct slope {
int delta_y;
int delta_x;
};
This allows for a wide range of slopes like 0 and +/- 1/INT_MAX ... +/- INT_MAX, even vertical. With careful coding, exact computations can be had.
Tardy credit: This is much like #Ignacio Vazquez-Abrams comment.
Generally speaking, with lines of arbitrary orientation it is not recommended to work with the slope/intercept representation y = mx + p, but with the implicit equation a x + b y + c = 0. The latter is more isotropic, supports vertical lines and gives you extra flexibility to scale the coefficients.
Meeting #chux's answer, the coefficients can be the deltas, Dy x - Dx y + c = 0 (assuming that the lines are defined by two points, Dx and Dy are likely to not overflow). Overflow is still possible on c, and you can use the variant Dy (x - x0) - Dx (y - y0) = 0.
Anyway, intermediate computations such as intersections may require larger ranges, i.e. double length integers.
The idea of flagging the large/low value is a little counterproductive: it is actually a primitive way of doing floating-point, i.e. separating the scale from the mantissa. Working this way, you will somehow re-design a foating-point system, less powerful than the built-in type and costing you sweat and tears.
Unfortunately, high range arithmetic can't be avoided. Indeed, the intersection of two straight lines is given by the Cramer formulas
x = (c b' - c' b) / (a b' - a' b),
y = (a c' - a' c) / (a b' - a' b)
where the products to be evaluated are one order of magnitude larger than the initial coefficients. This is explained by the fact that quasi-parallel lines have far-away intersections.
Look up fixed point arithmetic if you want to use int in a general way.
You can also design your algorithms so that you do every computation in such a way that you don't need sub-integer accuracy (for example look up Bresenham's line and circle drawing algorithms).
To your particular problem, you could try to keep quotient and fraction separately, in other words use rational numbers. Or ot put it another way, have delta X and delta Y as two numbers.

Sprite Rotation Math Formula for Screen Width and Height

I am programming an asteroids type game in C, and I have a sprite sheet of 36 sprites that is the ship rotating. I would like to know a math formula for figuring out how to move the ship in the direction of the sprite I have chosen from the sprite sheet. Note that I am incrementing by 10 degrees (hence 36 sprites for 360 degrees).
For example, my screen is 320 pixels wide by 256 pixels high.
If I select sprite image 10 (which is 90 degrees (the ship is facing right)), how can I calculate (using some sort of formula) the X and Y coordinates to move the ship in? I know 90 degrees is an easy one, by imagine if it were 30 degrees. There is a certain value for X and a certain value for Y. Since the screen in wider in width that height, the X speed would be higher than the Y speed.
Hope that makes sense.
Many thanks.
There are two easy approaches: you can build a table of [x,y] distances for each of the 36 angles, or you can do the math "on the fly".
The advantage of calculating the distances immediately is that you can easily increase the accuracy later on, if you decide you want more than 36 angles (and don't mind the sprite is off by a couple of degrees). Also, since you will be working with floats anyway, you can do all of your calculations with a far greater accuracy. Your speed could be as low as 0.01 pixel per second, and if you store your position as floats as well, you'd see your sprite move a tiny bit every few minutes.
Pre-calculating a table is easy and fast, though. Run this program to create the arrays xmove and ymove. Then, for an angle a, you can set xpos += ((speed*xmove[a])>>8) and ypos += ((speed*ymove[a])>>8).
The table stores sin and cos times 256, as integers. The values need to be multiplied by some large factor because they always fall inside the floating point range -1..1; storing them as their original floating point value is possible but unnecessary (it would only re-introduce floating point calculations in what can be reasonably approximated with pure integers, in your case). Now since the values are "premultiplied" by 256, you need to divide the speed*move calculation again by that number -- shifting right by 8 bits is all it takes. (There is a small rounding issue here; if it bothers you, add 128 before the right-shift.)
You can use a larger accuracy by using a multiplier of 1024 or higher, but again, more accuracy is probably entirely invisible for your purposes. ('1024' instead of '1000' because you can still efficiently use bit-shifting with that number.)
I believe that nowadays any modern screen has nigh-on square pixels, so unless you want it as some sort of special effect, speed in the y direction should be the same as x-speed. However, it's simple to add. Instead of dividing by 256, you'd use something like ypos += ((speed*ymove[angle])/341); -- this is (4*256/3), so the vertical speed is 75% of the horizontal speed.
A final possible refinement: you can also store your xpos,ypos as pre-multiplied by 256! Then you would not shift right the new coordinates, but immediately add the correct value. Only when displaying the actual sprite, you'd divide the coordinates by 256. That way your ship will not move by "entire pixels" only, but way more smooth. If your speed is variable, you can store it with higher accuracy the same way (remember to scale down correctly, because it'd make your 'virtual' speed is 256*256 higher than your 'screen' speed).
The table created below assumes #0 is "straight up", #9 (not 10!) is "right", #18 is down and #27 is "left", where positive y points downwards.
By the way: the size of your ship doesn't really matter ... You probably don't want it to "jump" distances equal to its own size.
#include <stdio.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
int main (void)
{
int i, angle;
printf ("int xmove[36] = {\n");
for (i=0; i<36; i++)
{
angle = 10*i;
// x distance: sin
printf ("\t%d,", (int)(round(256*sin(angle * M_PI/180))));
printf ("\t\tangle: %d\n", angle);
}
printf ("};\n");
printf ("\n");
printf ("int ymove[36] = {\n");
for (i=0; i<36; i++)
{
angle = 10*i;
// y distance: cos
printf ("\t%d,", (int)(round(-256*cos(angle * M_PI/180))));
printf ("\t\tangle: %d\n", angle);
}
printf ("};\n");
return 0;
}

Simple circular gesture detection

I'm looking at a simple, programmatic way of detecting whether or not the user has drawn a circular shape. I'm working in C, but am happy to work from pseudo-code. A bit of Googling brings up a number of (hopefully) overly-complex methods.
I'm tracking the mouse coordinates as floats, and have created an array of vectors to track the mouse movement over time. Essentially I'm looking to detect when a circle has been drawn and then disgard all movement data not associated with that circle.
I have a basic idea of how this might be accomplished:
Track all movements using a polling function. Each time the function is polled the current mouse position is stored. Here, we loop through the historic position data and do a rough 'snap to position' to compare the two locations. If the new location is within a close enough distance to an old position, we remove all historic data before the old location.
While this works in theory, it's a mess in practice. Does anyone have any suggestions? Bonus points if the method suggested can detect whether it's been drawn clockwise or counter-clockwise.
Based on your tracking/polling function, which pushes float pairs on a stack. This must be done on a regular timing interval.
Do a threshold-based search for two equal entries in the list. Now you have two indexes in your stack; the first and the second equal entries. Consider this as a line.
Get the absolute difference in indices. Then divide by two and get the coordinates of this point. (Center of the line.)
You've got two points: thus you can get the radius of the circle, by getting the distance between the two points divided by two.
Divide the number of step 2 by 2, now you've got the quarters.
If the line at step 1 is vertical and the first point of the line is at the top: If the first quarter is left of the center-point, the circle was drawn counter-clockwise. If the first quarter is right of the center-point, the circle was drawn clockwise. If the first point of the line is at the bottom, reverse (i.e. ccw => cw and cw => ccw)
If the line at step 1 is horizontal and the first point of the list is at the left: If the first quarter is above the center-point, the circle was drawn counter-clockwise. If the first quarter is below of the center-point, the circle was drawn clockwise. If the first point of the line is at the right, reverse.
Check if it was a circle: iterate over all pairs of coordinates and calculate the distance to the center-point. Tweak the threshold of allowed distances from the calculated distance and the actual distance to the center-point.
In step 2 and 4 you can tweak this algorithm further by taking the average of several indices if the timing interval is very low (fast polling). For instance: there are 30 pairs in the array, then you average pairs at 0, 1 and 28, 29 to get the upper point. Do the same for all other points.
I hope this is easy enough.
You are definitely on the right track IMHO. Basically you need to compare each mouse point with the previous mouse point and calculate the angle between them (as envisioned on a unit circle where the first point is at the origin). For this you can use the formula:
double angle = atan2(y2 - y1, x2 - x1) * 180 / PI;
if (angle < 0)
angle += 360;
What you end up with is that for clockwise movement, the angle will cycle in a positive direction, whereas for counterclockwise movement the angle will cycle in a negative direction. You can figure out if the current angle is greater or less than the previous one with the following logic:
if (angle2 > 270 && angle1 < 90)
{
angle1 += 360
}
else if (angle1 > 270 && angle2 < 90)
{
angle2 += 360
}
bool isPositive = (angle2-angle1 > 0);
If you get a certain number of vectors all with angles that are increasing (isPositive is true, let's say, 10 times), you can assume a clockwise circle is being drawn; if the tendency is negative (isPositive is false 10 times) it's a counterclockwise circle. :)
Here's an algorithm to see if an array of points fits a circle:
calculate the centroid of the points (average of all the x and y coordinates)
calculate the distance of all points to the centroid
find the maximum and minimum distances
if maximum - minimum < tolerance, circular section detected
NB This will detect a section of a circle as well so you will need to determine that enough of an angle is swept through for it to be a full circle.
To do this:
calculate centroid as above
calculate angle between centroid and each point (use atan2 function)
map angles to segments (I find 12 30 degree segments works for me; just divide angle by 30 and round down to integer - assuming you are working in degrees here)
if all segments contain at least 1 point, then it is a circle (i.e. your mapped segments array contains all values between 0 and 11)
bonus: increasing angle is anti-clockwise; decreasing is clockwise
Haven't tried this, but the idea came to mind reading your question, so might as well share it with you:
I'm assuming the circle has to be drawn within a reasonable amount of time, given a steady "sample-rate" of the mouse that would leave a known-size array of 2D vectors (points). Add them all and divide by the count of 2D vectors to get an estimate of the "center" point in the array. Then form vectors from this center-point to the points in the array and do dot-products (normalizing by vector length), making sure the sign of the dot-products remain identical for a range of points means those points all move in the same direction, a positive sign will indicate counter-clockwise movement, negative is just the opposite. If the accumulated angle exceeds 2 PI, a circular movement was drawn..
Good luck.
1 - Pick any 3 of the points
2 - If the points are collinear +/- 'some buffer' then it isn't a circle.
3 - Use the method described on Wikipedia for finding the circumscribed circle for a triangle to find the midpoint and radius of your candidate circle
The circumcenter of a triangle can be constructed by drawing any two
of the three perpendicular bisectors. For three non-collinear points,
these two lines cannot be parallel, and the circumcenter is the point
where they cross. Any point on the bisector is equidistant from the
two points that it bisects, from which it follows that this point, on
both bisectors, is equidistant from all three triangle vertices. The
circumradius is the distance from it to any of the three vertices.
4 - Check the distance to the remaining points. If those points are within the 'candidate circle radius' +/- 'some buffer allowance' then it is a circle.
5 - To determine direction, simply calculate the angle between the first and 2nd points from the midpoint. A negative angle is right. A positive angle is left. (Could be reversed depending on the coordinate system you are using)

Resources