1

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.

Tim Wood
  • 67
  • 1
  • 7

3 Answers3

4

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.

Community
  • 1
  • 1
Tim Wood
  • 67
  • 1
  • 7
2

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.

Throwback1986
  • 5,887
  • 1
  • 30
  • 22
  • Thanks Throwback1986, using r^2 may work. However my problem lies not within how to determine the line but in obtaining the coordinates of the points (they occupy more than one pixel) or processing them in OpenCV. – Tim Wood Apr 08 '11 at 20:57
  • Two thoughts: 1) Compute the centroid of each "hit". This should provide an "average" x and y coord that can be piped into the regression. 2) If the hit occupies a region of pixels (say 8 or 10 pix in area), then you might try sending *all* of the x,y coords associated with hits into the regression. You are dealing with an over-determined system anyway, I don't see the harm in sending clusters of pix into the fitter. Let it do the work. – Throwback1986 Apr 08 '11 at 21:30
  • That approach would work, using cvGet2D(img,i,j) to ascertain the pixel values at each hit. As I am checking for a straight line regression may be a OTT. Using all the pixel values for a hit I could just check the y values within a given tolerance say +/- 10ox are equal. The more of those the better the horizontal line. Cheers for the help, talking out it out helped a lot. May have to resort to regression on 'fuzzier' images – Tim Wood Apr 08 '11 at 22:44
0

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...

Marino Šimić
  • 7,318
  • 1
  • 31
  • 61