template <class P> static StarDetector::Status Detect( DPoint& pos, int& radius, float threshold, const GenericImage<P>& img ) { img.Status().DisableInitialization(); /* * Iteratively find the barycenter of a star. */ for ( int it = 0; it < 10; ++it ) { // Central pixel in the current search box Point p0 = pos; // Search box Rect r0( p0-radius, p0+radius+1 ); if ( !img.Intersects( r0 ) ) return StarDetector::OutsideImage; // Extract the search subimage img.SelectRectangle( r0 ); r0 = img.SelectedRectangle(); // in case the search box is clipped Image simg( img ); // Threshold background pixels Threshold( simg, threshold ); // Begin searching from the brightest pixel if ( simg.LocateMaximumPixelValue( p0 ) == simg.MinimumPixelValue() ) return StarDetector::NoSignificantData; // Coordinate and intensity accumulators. double sx = 0, sy = 0, si = 0; // Star bounding rectangle. Rect r( p0, p0 ); for ( int down = 0; down < 2; ++down ) { if ( down ? (p0.y == simg.Height()-1) : (p0.y == 0) ) continue; for ( int y = down ? p0.y+1 : p0.y; ; ) { double yc = y + 0.5; int xa, xb; /* * Explore the left segment of this row. */ for ( xa = p0.x+1; xa > 0; ) { Image::sample f = simg.Pixel( xa-1, y ); if ( f == 0 ) break; --xa; sx += f*(xa + 0.5); sy += f*yc; si += f; } /* * Explore the right segment of this row. */ for ( xb = p0.x; xb < simg.Width()-1; ) { Image::sample f = simg.Pixel( xb+1, y ); if ( f == 0 ) break; ++xb; sx += f*(xb + 0.5); sy += f*yc; si += f; } /* * Update horizontal boundaries. */ if ( xa < r.x0 ) // left boundary r.x0 = xa; if ( xb >= r.x1 ) // right boundary r.x1 = xb+1; /* * Update y to explore the next row. */ if ( down ) { ++y; if ( y == simg.Height() ) break; } else { if ( y == 0 ) break; --y; } /* * Decide whether we are done with this star, or if there is at * least one more row that has to be explored. This is true if * there is at least one significant pixel touching the current row * in the next row. */ bool nextRow = false; for ( int x = xa; x <= xb; ++x ) if ( simg.Pixel( x, y ) != 0 ) { nextRow = true; break; } if ( !nextRow ) break; /* * Update vertical boundaries. */ if ( down ) r.y1 = y+1; // bottom boundary else r.y0 = y; // top boundary } } /* * Check if we have gathered some data. */ if ( 1 + si == 1 ) return StarDetector::NoSignificantData; /* * Update barycenter coordinates. */ DPoint lastPos = pos; pos.x = r0.x0 + sx/si; pos.y = r0.y0 + sy/si; /* * Update search radius. */ int r1 = Range( Max( r.Width(), r.Height() ), 5, 127 ); if ( r1 != radius ) radius = r1; else { /* * If the search radius has stabilized, check if we have reached * convergence. We converge to within +/- 0.01 px. */ if ( Abs( pos.x - lastPos.x ) < 0.005 && Abs( pos.y - lastPos.y ) < 0.005 ) return (r.x0 > 0 && r.y0 > 0 && r.x1 < simg.Width() && r.y1 < simg.Height()) ? StarDetector::DetectedOk : StarDetector::CrossingEdges; } } return StarDetector::NoConvergence; }