//image = 'naco/gck0502.ssa'
//image = '/data2/public/NACO/results/gck0502.ssa'
//fwhm = 5
//hmin = 1000
//sharplim = [.2,1]
//roundlim = [-1,1]
procedure find, image, x, y, flux, sharp, roundness, hmin, fwhm, roundlim, sharplim {
/*
                      PRINT = print, SILENT=silent
;+
; NAME:
;	FIND
; PURPOSE:
;	Find positive brightness perturbations (i.e stars) in an image 
; EXPLANATION:
;	Also returns centroids and shape parameters (roundness & sharpness).
;	Adapted from 1986 STSDAS version of DAOPHOT.
;
; CALLING SEQUENCE:
;	FIND, image, [ x, y, flux, sharp, round, hmin, fwhm, roundlim, sharplim 
;		PRINT= , /SILENT ]
;
; INPUTS:
;	image - 2 dimensional image array (integer or real) for which one
;		wishes to identify the stars present
;
; OPTIONAL INPUTS:
;	FIND will prompt for these parameters if not supplied
;
;	hmin -  Threshold intensity for a point source - should generally 
;		be 3 or 4 sigma above background
;	fwhm  - FWHM to be used in the convolve filter
;	sharplim - 2 element vector giving low and high cutoff for the
;		sharpness statistic (Default: [0.2,1.0] ).   Change this
;		default only if the stars have siginificantly larger or 
;		or smaller concentration than a Gaussian
;	roundlim - 2 element vector giving low and high cutoff for the
;		roundness statistic (Default: [-1.0,1.0] ).   Change this 
;		default only if the stars are significantly elongated.
;
; OPTIONAL INPUT KEYWORDS:
;	SILENT - Normally, FIND will write out each star that meets all
;		selection criteria.   If the SILENT keyword is set and 
;		non-zero, then this printout is suppressed.
;	PRINT - if set and non-zero then T_FIND will also write its results to
;		a file FIND.PRT.   Also one can specify a different output file 
;		name by setting PRINT = 'filename'.
;
; OPTIONAL OUTPUTS:
;	x - vector containing x position of all stars identified by FIND
;	y-  vector containing y position of all stars identified by FIND
;	flux - vector containing flux of identified stars as determined
;		by a gaussian fit.  Fluxes are NOT converted to magnitudes.
;	sharp - vector containing sharpness statistic for identified stars
;	round - vector containing roundness statistic for identified stars
;
; NOTES:
;	The sharpness statistic compares the central pixel to the mean of the
;	surrounding pixels.   If this difference is greater than the originally
;	estimated height of the Gaussian or less than 0.2 the height of the
;	Gaussian (for the default values of SHARPLIM) then the star will be
;	rejected. 
;
; PROCEDURE CALLS:
;	DATATYPE(), GETOPT
; REVISION HISTORY:
;	Written W. Landsman, STX  February, 1987
;	ROUND now an internal function in V3.1   W. Landsman July 1993
;	Change variable name DERIV to DERIVAT    W. Landsman Feb. 1996
;	Use /PRINT keyword instead of TEXTOUT    W. Landsman May  1996
;	Changed loop indices to type LONG       W. Landsman Aug. 1997
;	Converted to IDL V5.0   W. Landsman   September 1997
;-
;
 On_error,2                         ;Return to caller
*/
 if nparams == 0 {
    print "Syntax - FIND, image, [ x, y, flux, sharp, round, hmin, fwhm, roundlim, sharplim"
 } else {

 maxbox = 13 	//Maximum size of convolution box in pixels 

//Determine if hardcopy output is desired

// type = size(image)
// if ( type[0] NE 2 ) then message, $
//     'ERROR - Image array (first parameter) must be 2 dimensional'
 n_x  = naxis1(image); n_y = naxis2(image)

 print "Input Image Size is "+n_x + " by "+ n_y

// if not keyword_set( PRINT )  then print = 0
// if not keyword_set( SILENT ) then silent = 0
 if (fwhm == 0) read "Enter approximate FWHM: ", fwhm

 radius = 0.637*fwhm
 if radius < 2.001 radius = 2.001             //Radius is 1.5 sigma
 radsq = radius^2
 nhalf = int(radius) 
 if nhalf > (maxbox-1)/2 nhalf = (maxbox-1)/2   	
 nbox = int(2*nhalf + 1)	//# of pixels in side of convolution box 
 middle = nhalf          //Index of central pixel

 lastro = n_x - nhalf
 lastcl = n_y - nhalf
 sigsq = ( fwhm/2.35482 )^2
 mask = fits( nbox, nbox )   //Mask identifies valid pixels in convolution box 
 c = fits( nbox, nbox )      //c will contain Gaussian convolution kernel

 dd = [0:nbox-2] + 0.5 - middle	//Constants need to compute ROUND
 dd2 = dd^2

 w = 1. - 0.5*(abs(dd)-0.5) / (middle-.5)   
 ir = (nhalf-1)
 if (ir < 1) ir = 1

 row2 = ([0:nbox-1]-nhalf)^2

 for i = 0, nhalf {
	temp = row2 + i^2
	c[*,nhalf-i+1] = temp         
        c[*,nhalf+i+1] = temp                           
 }
 mask = c * 0
 mask[where(c <= radsq)] = 1
// mask = fix(c LE radsq)     ;MASK is complementary to SKIP in Stetson's Fortran
 good = where(mask == 1)
 pixels = nelements(good)
// good = where( mask, pixels)  ;Value of c are now equal to distance to center

 c = c*mask  
 for i=1,naxis1(c) {
   for j=1, naxis2(c) {
     if (mask[i,j] == 1) c[i,j] = exp(-0.5*c[i,j]/sigsq)
   }
 }
// c[good] = exp(-0.5*c[good]/sigsq)	;Make c into a gaussian kernel

 sumc = total(c)
 sumcsq = total(c^2) - sumc^2/pixels
 sumc = sumc/pixels

 for i=1,naxis1(c) {
   for j=1, naxis2(c) {
     if (mask[i,j] == 1) c[i,j] = (c[i,j]-sumc)/sumcsq
   }
 }
// c[good] = (c[good] - sumc)/sumcsq
 c1 = exp(-.5*row2/sigsq)
 sumc1 = total(c1)/nbox
 sumc1sq = total(c1^2) - sumc1
 c1 = (c1-sumc1)/sumc1sq
 sumc = total(w)                         //Needed for centroid computation

 print "RELATIVE ERROR computed from FWHM " + sqrt(total(c^2))

//  if hmin == 0N_elements(hmin) NE 1 then read, $
//    'Enter minimum value above background for threshold detection: ',hmin

// if N_elements(sharplim) NE 2 then begin
//      print,'Enter low and high cutoffs, press [RETURN] for defaults:'
//GETSHARP:   
//      ans = ''
//      read, 'Image Sharpness Statistic (DEFAULT = 0.2,1.0): ', ans   
//      if ans EQ '' then sharplim = [0.2,1.0] else begin
//         sharplim = getopt(ans,'F')
//          if N_elements(sharplim) NE 2 then begin  
//              message, 'ERROR - Expecting 2 scalar values',/CON
//              goto, GETSHARP     
//          endif
//      endelse                                                      

//GETROUND: 
//  ans = ''
//  read, 'Image Roundness Statistic [DEFAULT = -1.0,1.0]: ',ans
//  if ans EQ '' then roundlim = [-1.,1.] else begin
//      roundlim = getopt( ans, 'F' )
//      if N_elements( roundlim ) NE 2 then begin
 //          message,'ERROR - Expecting 2 scalar values',/CON
//           goto, GETROUND   
//      endif
// endelse
// endif 

 print "Beginning convolution of image"

 h = reass(fft(fft(image) * fft(center(resize(c,n_x,n_y)))))    //Convolve image with kernel "c"
 h /= nelements(h)

    h[1:nhalf,*] = 0 ; h[n_x-nhalf+1:n_x,*] = 0
    h[*,1:nhalf] = 0 ; h[*,n_y-nhalf+1:n_y] = 0

 print "Finished convolution of image"

 mask[middle+1,middle+1] = 0	//From now on we exclude the central pixel
 pixels = pixels -1      //so the number of valid pixels is reduced by 1
 ngood = nelements(where(mask!=0))      //"good" identifies position of valid pixels
 xx = yy = fits(ngood)
 mm = 0
 for i=1,naxis1(mask) {
   for j=1, naxis2(mask) {
     if (mask[i,j]!=0) {
       mm++
       xx[mm] = j
       yy[mm] = i
     }
   }
 }
 xx -= middle+1
 yy -= middle+1

// xx= (good mod nbox) - middle	//x and y coordinate of valid pixels 
// yy = fix(good/nbox) - middle    //relative to the center
 offset = yy*n_x + xx
//SEARCH: 			    ;Threshold dependent search begins here

 index = where(h >= hmin)  //Valid image pixels are greater than hmin
 nfound = nelements(index)
 if nfound == 0 {          //Any maxima found?

    print "ERROR - No maxima exceed input threshold of " + hmin
 } else {

 for i= 1, pixels {                   
        stars = fits(nelements(index))
  nfound = 0
	for m=1, nelements(index) {
	  ii = index[m] + offset[i]
		if (ii > 0 && ii <= nelements(h)) {
          if (h[index[m]] >= h[index[m] + offset[i]]) {
            nfound++
//            stars[nfound] = index[m]
stars[nfound] = m
          }
			}
	}
	stars = stars[1:nfound]
//	stars = where (h[index] >= h[index+offset[i]])
//	nfound = nelements(stars)
        if nfound < 0 { //then begin  ;Do valid local maxima exist?
             print "ERROR - No maxima exceed input threshold of " + hmin
//             goto,FINISH  
        }
	index = index[stars]

 } 
 
 ix = index/n_x 
 for i=1, nelements(ix) ix[i] = frac(ix[i])
 ix *= n_y // mod n_x              ;X index of local maxima
 iy = index/n_x //                 ;Y index of local maxima
 for i=1, nelements(ix) {
   ix[i] = round(ix[i])
   iy[i] = round(iy[i])+1
 }
 ngood = nelements(index)       
 print ngood+" local maxima located above threshold"

 nstar = 1 //       	;NSTAR counts all stars meeting selection criteria
 badround = 0 ; badsharp=0  ;  badcntrd=0
// if (npar GE 2) or (PRINT) then begin 	;Create output X and Y arrays? 
  	x = y = fltarr(ngood)
// endif

// if (npar GE 4) or (PRINT) then begin   ;Create output flux,sharpness arrays?
 	flux = x ; sharp = x ; roundness = x
// endif

/* if PRINT then begin	;Create output file?

         if ( datatype(print) NE 'STR' ) then file = 'find.prt' $
                                         else file = print
         message,'Results will be written to a file ' + file,/INF
         openw,lun,file,/GET_LUN
	printf,lun,' Program: FIND '+ systime()
	printf,lun,format='(/A,F7.1)',' Threshold above background:',hmin
	printf,lun,' Approximate FWHM:',fwhm
	printf,lun,format='(2(A,F6.2))',' Sharpness Limits: Low', $
                sharplim[0], '  High',sharplim[1]
	printf,lun,format='(2(A,F6.2))',' Roundness Limits: Low', $
                roundlim[0],'  High',roundlim[1]
	printf,lun,format='(/A,i6)',' No of sources above threshold',ngood

 endif                      
*/
/*
 if not SILENT then $
  print,format='(/8x,a)','     STAR      X      Y     FLUX     SHARP    ROUND'

;  Loop over star positions; compute statistics
*/
 for i = 1,ngood {// do begin  
 doit = 1 
     temp = image[ix[i]-nhalf:ix[i]+nhalf,iy[i]-nhalf:iy[i]+nhalf]
     d = h[ix[i],iy[i]]              //    ;"d" is actual pixel intensity        

//  Compute Sharpness statistic

     sharp1 = (temp[middle+1,middle+1] - (total(mask*temp))/pixels)/d
     if ( sharp1 < sharplim[1] ) || ( sharp1 > sharplim[2] ) {
	badsharp = badsharp + 1
//	goto, REJECT             ;Does not meet sharpness criteria
doit = 0
print "sharp"
     }
//   Compute Roundness statistic
if (doit == 1) {
     dx = total( collapse(temp,2)*c1)   
     dy = total( collapse(temp,1)*c1)
     if (dx <= 0) || (dy <= 0) {
         badround = badround + 1
//	 goto, REJECT           ;Cannot compute roundness
doit = 0
print "xround"
     }
}
if (doit == 1) {
     around = 2*(dx-dy) / ( dx + dy )    //Roundness statistic
     if ( around < roundlim[1] ) || ( around > roundlim[2] ) {
	badround = badround + 1
//	goto,REJECT           ;Does not meet roundness criteria
doit = 0
print "yround"
     }
}
if (doit == 1) {
// Find X centroid

     derivat = shift(temp,-1,0) - temp
     derivat = collapse( derivat[1:nbox-1,middle-ir+1:middle+ir+1],2)
     sumd = total(w*derivat)
     sumxd = total(w*dd*derivat)
     sumxsq = total(w*dd2) 

     if ( sumxd >= 0. ) {
	badcntrd = badcntrd + 1
//	goto,REJECT           ;Cannot compute X centroid
doit = 0
print "xcen"
     }
}
if (doit == 1) {
     dx =sumxsq*sumd/(sumc*sumxd)
     if abs(dx) > nhalf {
      	 badcntrd = badcntrd + 1
//	 goto,REJECT           ;X centroid too far from local X maxima
doit = 0
print "xcen"
     }

     xcen = ix[i]-dx               //Convert back to big image coordinates
}
// Find Y centroid                 
if (doit == 1) {
     derivat = shift(temp,0,-1) - temp 
     derivat = collapse( derivat[middle-ir+1:middle+ir+1,1:nbox-1], 1 )
     sumd = total( w*derivat )
     sumxd = total( w*dd*derivat )
     sumxsq = total( w*dd2 )
     if (sumxd >= 0) {
	  badcntrd = badcntrd + 1
//	  goto, REJECT  
doit = 0
print "ycen"
     }
}
if (doit == 1) {
     dy = sumxsq*sumd/(sumc*sumxd)
     if ( abs(dy) > nhalf ) {
	badcntrd = badcntrd + 1
//	goto,REJECT 
doit = 0
print "ycen"
     }
     
     ycen = iy[i] - dy
}
//  This star has met all selection criteria.  Print out and save results
if (doit == 1) {
//   if not SILENT then $
//      print,FORM = '(12x,i5,2f7.1,f9.1,2f9.2)', $ 
//            nstar, xcen, ycen, d, sharp1, around
print nstar + " " + xcen + " " + ycen + " " + d + " " + sharp1 + " " + around
//
//   if (npar GE 2) or (PRINT) then begin
              x[nstar] = xcen ; y[nstar] = ycen
//   endif

//   if ( npar GE 4 ) or (PRINT) then begin
	flux[nstar] = d ; sharp[nstar] = sharp1 ; roundness[nstar] = around
//   endif
   
   nstar = nstar+1
} else {
print nstar + " " + xcen + " " + ycen + " " + d + " " + sharp1 + " " + around
}
//REJECT: 
  
 }

 nstar = nstar-1		//NSTAR is now the index of last star found

 
  print," No. of sources rejected by SHARPNESS criteria " + badsharp
  print," No. of sources rejected by ROUNDNESS criteria " + badround
  print," No. of sources rejected by CENTROID  criteria " + badcntrd

//  if nstar LT 0 then return               ;Any stars found?

//  if (npar GE 2) or (PRINT) then begin
	x=x[1:nstar]  ; y = y[1:nstar]
//  endif

//  if (npar GE 4) or (PRINT) then begin
	flux= flux[1:nstar] ; sharp=sharp[1:nstar]  
        roundness = roundness[1:nstar]
//  endif

// if PRINT then begin                
//   printf,lun, $
//      format = '(/8x,a)','     STAR       X       Y     FLUX     SHARP    ROUND'
//	for i = 0, nstar do $
//	   printf,lun,format='(12x,i5,2f8.2,f9.1,2f9.2)', $
//	              i+1, x[i], y[i], flux[i], sharp[i], roundness[i]
 //       free_lun, lun
// endif

//FINISH:

/* if SILENT then return

 print,form='(A,F8.1)',' Threshold above background for this pass was',hmin
 ans = ''
 read,'Enter new threshold or [RETURN] to exit: ',ans
 ans = getopt(ans,'F')              
 if ans GT 0. then begin
       hmin = ans
       goto, SEARCH   
 endif

 return                                      
 end
 */
 }
}
