#include "mrilib.h"

/*----------------------------------------------------------------------*/
/*! Return a measure of the difference between 2 images bim and nim,
    possibly with a mask to indicate which voxels to include.

    The difference is defined as dd below:

    ss = min sum  [ bim[i] - a * nim[i] ]**2
          a   i

    dd = sqrt( ss / #voxels )  i.e., the RMS difference.

    That is, we least squares fit image nim to bim by a scale factor,
    and the residual determines the difference.  The minimizing value of
    'a' is given by

    a = BN / NN  where BN = sum [ bim[i]*nim[i] ]
                       NN = sum [ nim[i]**2     ]

    so the difference is given by

    diff = BB - (BN)**2/NN  where BB = sum[ bim[i]**2 ]

    - A negative return value indicates an error.
    - If bim=0, then the return value will be 0.
    - If bim!=0 and nim=0, then the return value is computed with a=0
      (that is, it will be the RMS value of bim)
------------------------------------------------------------------------*/

float mri_scaled_diff( MRI_IMAGE *bim , MRI_IMAGE *nim , MRI_IMAGE *msk )
{
   int nvox , ii , nmask=0 ;
   MRI_IMAGE *fim , *gim ;
   float     *far , *gar , sdif , ff,gg,fg ;
   byte      *mar=NULL ;

ENTRY("mri_scaled_diff") ;

   if( bim == NULL || nim == NULL ) RETURN(-1.0f) ;

   nvox = bim->nvox ; if( nim->nvox != nvox ) RETURN(-1.0f) ;

   if( msk != NULL && msk->kind == MRI_byte && msk->nvox == nvox ){
     mar   = MRI_BYTE_PTR(msk) ;
     nmask = THD_countmask( nvox , mar ) ;
     if( nmask < 3 ){ nmask = 0 ; mar = NULL ; }
   }

   fim = (bim->kind != MRI_float) ? mri_to_float(bim) : bim ;
   gim = (nim->kind != MRI_float) ? mri_to_float(nim) : nim ;

   far = MRI_FLOAT_PTR(fim) ; gar = MRI_FLOAT_PTR(gim) ;

   ff = gg = fg = 0.0f ;
   for( ii=0 ; ii < nvox ; ii++ ){
     if( nmask == 0 || mar[ii] != 0 ){
       ff += far[ii] * far[ii] ;
       gg += gar[ii] * gar[ii] ;
       fg += far[ii] * gar[ii] ;
     }
   }
   if( gg > 0.0f ){          /* normal case  */
     sdif = ff - fg*fg/gg ;
     if( sdif > 0.0f )
       sdif = sqrt( sdif / ((nmask > 0) ? nmask : nvox) ) ;

   } else if( ff <= 0.0f )   /* far=gar=0 */
     sdif =  0.0f ;
   else                      /* gar=0 far!=0 */
     sdif =  sqrt( ff / ((nmask > 0) ? nmask : nvox) ) ;

   /** done **/

   if( fim != bim ) mri_free(fim) ;
   if( gim != nim ) mri_free(gim) ;
   RETURN(sdif) ;
}
