efficient line from hough transform coordinates - computer-vision

i'm working with a hough transform (polar coordinates). i'd like to compute a vector representation of a line from a coordinate from the hough transform.
my current implementation loops through all the pixel coordinates in the image from (0,0) to (M, N) where M and N are the size of the image. as the loop traverses the space, this value is computed:
// angle and rho are the polar coordinates from hough space.
tmp = (int) ( (i * cos( angle ) ) + ( j * sin(angle) ) );
where tmp - rho == 0, is part of the line, so i track that position. when the loop reaches the end of the image (i,j) == (M,N), the loop is done again from the opposite direction (M, N) to (0,0).
the first (tmp-rho == 0) going left to right and the second (tmp-rho == 0) going right to left are the coordinates of the line. i then subtract those pixel coordinates to get a vector of the line in the hough space.
this is terribly inefficient (slow) and i'm 100% sure there's a better way to compute this but, i can't seem to figure it out. any help would be greatly appreciated!

You can solve your equation for i=0, i=M, j=0, j=N instead of looping
rho = i * cos(angle) + j * sin(angle)
i = 0 --> j1 = rho / sin(angle)
i = M --> j2 = (rho - M*cos(angle)) / sin(angle)
j = 0 --> i1 = rho / cos(angle)
j = N --> i2 = (rho - N*sin(angle)) / cos(angle)

Related

How to draw an arc with given starting point in opengl?

I want to draw an arc with opengl. The arc should start from an specific point and ends at a given point. Given are radius, centre of the arc and arc length, start angle and end angle.
I have tried following function:
for (double theta = start_angle1; theta < end_angle1; theta += angle_increment)
{
glVertex2f((arcCenX+ r * sinf(theta)),(arcCenY+ r * cosf(theta)));
}
This functions gives arc properly, but starting point of arc is different.
How to specify a starting point of an arc?
Edit: I also have tried this
for ( angleIndex = 0; angleIndex < arc_len; angleIndex = angleIndex+arcSegmentIndex )
{
glVertex2f((x + ( cosf( start_angle1 + angleIndex ) )* r),
(y + ( sinf( start_angle1 + angleIndex ) )* r));
}
But it also not working.
It should be
glVertex2f((arcCenX+ r * cosf(theta)),(arcCenY+ r * sinf(theta)));
Its bascially the parametric equation of the circle so
x = r cos(0)
y = r sin(0)
where "r" is the radius of the circle. You have your x and y coordinates swapped maybe that's what's causing the problem.
Edit:- to clear it up, the starting point of the arc depends on the first theta value you put in. so if for example the first value that goes into theta is 90 degrees then the arc starts directly above the center of the circle at a distance r.

line-width for ellipse is not constant

I am drawing hollow ellipse using opengl. I calculate vertices in c++ code using standard ellipse formula. In fragment shader i just assign color to each fragment. The ellipse that i see on the screen has thinner line width on the sharper curves as compared to that where curve is not that sharp. So question is, how to make line-width consistent across the entire parameter of ellipse? Please see the image below:
C++ code :
std::vector<float> BCCircleHelper::GetCircleLine(float centerX, float centerY, float radiusX, float radiusY, float lineWidth, int32_t segmentCount)
{
auto vertexCount = (segmentCount + 1) * 2;
auto floatCount = vertexCount * 3;
std::vector<float> array(floatCount);
const std::vector<float>& data = GetCircleData (segmentCount);
float halfWidth = lineWidth * 0.5f;
for (int32_t i = 0; i < segmentCount + 1; ++i)
{
float sin = data [i * 2];
float cos = data [i * 2 + 1];
array [i * 6 + 0] = centerX + sin * (radiusX - halfWidth);
array [i * 6 + 1] = centerY + cos * (radiusY - halfWidth);
array [i * 6 + 3] = centerX + sin * (radiusX + halfWidth);
array [i * 6 + 4] = centerY + cos * (radiusY + halfWidth);
array [i * 6 + 2] = 0;
array [i * 6 + 5] = 0;
}
return std::move(array);
}
const std::vector<float>& BCCircleHelper::GetCircleData(int32_t segmentCount)
{
int32_t floatCount = (segmentCount + 1) * 2;
float segmentAngle = static_cast<float>(M_PI * 2) / segmentCount;
std::vector<float> array(floatCount);
for (int32_t i = 0; i < segmentCount + 1; ++i)
{
array[i * 2 + 0] = sin(segmentAngle * i);
array[i * 2 + 1] = cos(segmentAngle * i);
}
return array;
}
Aiming this:
The problem is likely that your fragments are basically line segments radiating from the center of the ellipse.
If you draw a line, from the center of the ellipse through the ellipse you've drawn, at any point on the perimeter, you could probably convince yourself that the distance covered by that red line is in fact the width that you're after (roughly, since you're working at low spatial resolution; somewhat pixelated). But since this is an ellipse, that distance is not perpendicular to the path being traced. And that's the problem. This works great for circles, because a ray from the center is always perpendicular to the circle. But for these flattened ellipses, it's very oblique!
How to fix it? Can you draw circles at each point on the ellipse, instead of line segments?
If not, you might need to recalculate what it means to be that thick when measured at that oblique angle - it's no longer your line width, may require some calculus, and a bit more trigonometry.
Ok, so a vector tangent to the curve described by
c(i) = (a * cos(i), b * sin(i))
is
c'(i) = (- a * sin(i), b * cos(i))
(note that this is not a unit vector). The perpendicular to this is
c'perp = (b * cos(i), a * sin(i))
You should be able to convince yourself that this is true by computing their dot product.
Lets calculate the magnitude of c'perp, and call it k for now:
k = sqrt(b * b * cos(i) * cos(i) + a * a * sin(i) * sin(i))
So we go out to a point on the ellipse (c(i)) and we want to draw a segement that's perpendicular to the curve - that means we want to add on a scaled version of c'perp. The scaling is to divide by the magnitude (k), and then multiply by half your line width. So the two end points are:
P1 = c(i) + halfWidth * c'perp / k
P2 = c(i) - halfWidth * c'perp / k
I haven't tested this, but I'm pretty sure it's close. Here's the geometry you're working with:
--
Edit:
So the values for P1 and P2 that I give above are end-points of a line-segment that's perpendicular to the ellipse. If you really wanted to continue with just altering the radiusX and radiusY values the way you were doing, you could do this. You just need to figure out what the 'Not w' length is at each angle, and use half of this value in place of halfWidth in radiusX +/- halfWidth and radiusY +/- halfwidth. I leave that bit of geometry as an exercise for the reader.

OpenGL - Creating a circle, change radius?

I must be the worst person on the planet when it comes to math because i can't figure out how to change this circle radius:
from math import *
posx, posy = 0,0
sides = 32
glBegin(GL_POLYGON)
for i in range(100):
cosine=cos(i*2*pi/sides)+posx
sine=sin(i*2*pi/sides)+posy
glVertex2f(cosine,sine)
I'm not entirely sure how or why this becomes a circle because the *2 confuses me a bit.
Note that this is done in Pyglet under Python2.6 calling OpenGL libraries.
Followed Example 4-1: http://fly.cc.fer.hr/~unreal/theredbook/chapter04.html
Clarification: This works, i'm interested in why and how to modify the radius.
This should do the trick :)
from math import *
posx, posy = 0,0
sides = 32
radius = 1
glBegin(GL_POLYGON)
for i in range(100):
cosine= radius * cos(i*2*pi/sides) + posx
sine = radius * sin(i*2*pi/sides) + posy
glVertex2f(cosine,sine)
But I would pick another names for variables. cosine and sine is not exactly what these variables are.
And as far as I see, you son't need a loop from 1 to 100 (or from 0 to 99, I'm not too good at Python), you just need a loop from 1 to sides.
Explanation:
When you calculate
x = cos (angle)
y = sin(angle)
you get a point on a circle with radius = 1, and centre in the point (0; 0) (because sin^2(angle) + cos^2(angle) = 1).
If you want to change a radius to R, you simply multiply cos and sin by R.
x = R * cos (angle)
y = R * sin(angle)
If you want to transfer the circle to another location (for example, you want the circle to have it's centre at (X_centre, Y_centre), you add X_centre and Y_xentre to x and y accordingly:
x = R * cos (angle) + X_centre
y = R * sin(angle) + Y_centre
When you need to loop through N points (in your case N = sides) on your circle, you should change the angle on each iteration. All those angles should be equal and their sum should be 2 * pi. So each angle should be equal to 2 * pi/ N. And to get i-th angle you multiply this value by i: i * 2 * pi / N.
math : P=pr^2=p*r*r= p*r*2 programming i*2*pi/sides
together : i = p i*2, *2=r^2 this should help you

OpenCV detect if points lie along line/plane

I am working on a form of autocalibration for an optics device which is currently performed manually. The first part of the calibration is to determine whether a light beam has illuminated the set of 'calibration' points.
I am using OpenCV and have thresholded and cropped the image to leave only the possible relevant points. I know want to determine if these points lie along a stright (horizontal) line; if they a sufficient number do the beam is in the correct position! (The points lie in a straight line but the beam is often bent so hitting most of the points suffices, there are 21 points which show up as white circles when thresholded).
I have tried using a histogram but on the thresholded image the results are not correct and am now looking at Hough lines, but this detects straight lines from edges wwhere as I want to establish if detected points lie on a line.
This is the threshold code I use:
cvThreshold(output, output, 150, 256, CV_THRESH_BINARY);
The histogram results with anywhere from 1 to 640 bins (image width) is two lines at 0 and about 2/3rds through of near max value. Not the distribution expected or obtained without thresholding.
Some pictures to try to illistrate the point (note the 'noisy' light spots which are a feature of the system setup and cannot be overcome):
12 points in a stright line next to one another (beam in correct position)
The sort of output wanted (for illistration, if the points are on the line this is all I need to know!)
Any help would be greatly appreciated. One thought was to extract the co-ordinates of the points and compare them but I don't know how to do this.
Incase it helps anyone here is a very basic (the first draft) of some simple linaear regression code I used.
// Calculate the averages of arrays x and y
double xa = 0, ya = 0;
for(int i = 0; i < n; i++)
{
xa += x[i];
ya += y[i];
}
xa /= n;
ya /= n;
// Summation of all X and Y values
double sumX = 0;
double sumY = 0;
// Summation of all X*Y values
double sumXY = 0;
// Summation of all X^2 and Y^2 values
double sumXs = 0;
double sumYs = 0;
for(int i = 0; i < n; i++)
{
sumX = sumX + x[i];
sumY = sumY + y[i];
sumXY = sumXY + (x[i] * y[i]);
sumXs = sumXs + (x[i] * x[i]);
sumYs = sumYs + (y[i] * y[i]);
}
// (X^2) and (Y^2) sqaured
double Xs = sumX * sumX;
double Ys = sumY * sumY;
// Calculate slope, m
slope = (n * sumXY - sumX * sumY) / (n* sumXs - Xs);
// Calculate intercept
intercept = ceil((sumY - slope * sumX) / n);
// Calculate regression index, r^2
double r_top = (n * sumXY - sumX * sumY);
double r_bottom = sqrt((n* sumXs - Xs) * (n* sumYs - Ys));
double r = 0;
// Check line is not perfectly vertical or horizontal
if(r_top == 0 || r_bottom == 0)
r = 0;
else
r = r_top/ r_bottom;
There are more efficeint ways of doing this (see CodeCogs or AGLIB) but as quick fix this code seems to work.
To detect Circles in OpenCV I dropped the Hough Transform and adapeted codee from this post:
Detection of coins (and fit ellipses) on an image
It is then a case of refining the co-ordinates (removing any outliers etc) to determine if the circles lie on a horizontal line from the slope and intercept values of the regression.
Obtain the x,y coordinates of the thresholded points, then perform a linear regression to find a best-fit line. With that line, you can determine the r^2 value which effectively gives you the quality of fit. Based on that fitness measure, you can determine your calibration success.
Here is a good discussion.
you could do something like this, altough it is an aproximation:
var dw = decide a medium dot width in pixels
maxdots = 0;
for each line of the image {
var dots = 0;
scan by incrementing x by dw {
if (color==dotcolor) dots++;
}
if (dots>maxdots) maxdots=dots;
}
maxdots would be the best result...

Algorithm to generate radial gradient

I have this algorithm here:
pc = # the point you are coloring now
p0 = # start point
p1 = # end point
v = p1 - p0
d = Length(v)
v = Normalize(v) # or Scale(v, 1/d)
v0 = pc - p0
t = Dot(v0, v)
t = Clamp(t/d, 0, 1)
color = (start_color * t) + (end_color * (1 - t))
to generate point to point linear gradients. It works very well for me. I was wondering if there was a similar algorithm to generate radial gradients. By similar, I mean one that solves for color at point P rather than solve for P at a certain color (where P is the coordinate you are painting).
Thanks
//loop through vector
//x and y px position
int x = i%w;
int y = i/w;
float d = distance(center,int2(x,y));
//if within the grad circle
if(d < radius)
{
//somehow set v[i] alpha to this:
float a = d/r;
}
Linerise over atan2(dy,dx) where dx is x-center, and dy is y-center.
cx # center x
cy # center y
r1 # ring is defined by two radius
r2 # r1 < r2
c1 # start color
c2 # stop color
ang # start angle
px # currect point x,y
py
if( px^2 + py^2 <= r2^2 AND px^2 + py^2 >= r1^2 ) # lies in ring?
t= atan2(py-cy,px-cx)+ang
t= t+ pi # atan2 is from -pi to pi
if (t > 2* pi) # it might over 2pi becuse of +ang
t=t-2*pi
t=t/(2*pi) # normalise t from 0 to 1
color = (c1 * t) + (c2 * (1 - t))
Problem whit this algorhitm is that ang is actualy wrong and should be rotated by pi and normalized between 0 and 2pi.
Based on the comment, what you want can still be viewed as a linear gradient -- i.e. you have a line from the center to the outside of the circle, and you have a linear gradient along that line. As such, the calculation is virtually identical to what you already had.
Edit: Okay, apparently I misunderstood what you want. To figure a gradient running around a radius, you still basically linearize it -- figure out the circumference at that radius (2*Pi*R), and then do a linear interpolation along a line of that length.