#ifndef SINFO_IMAGE_OPS_H
#define SINFO_IMAGE_OPS_H
/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */
/*******************************************************************************
* E.S.O. - VLT project
*
* "@(#) $Id: sinfo_image_ops.h,v 1.9 2008-03-25 08:20:43 amodigli Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* amodigli  04/01/06  created
*/

/************************************************************************
 * sinfo_image_ops.h
 * image arithmetic routines
 *----------------------------------------------------------------------
 */
#include <cpl.h>

#include "sinfo_spiffi_types.h" 
#include "sinfo_spectrum_ops.h" 
#include "sinfo_recipes.h"
/*----------------------------------------------------------------------------
 *                        Function ANSI C prototypes
 *--------------------------------------------------------------------------*/



cpl_image *
sinfo_image_smooth_y(cpl_image * inp, const int r);

cpl_error_code
sinfo_image_line_corr(const int width,
		      const int filt_rad,
		      const int kappa,
		      cpl_image* ima,
		      cpl_image** ima_out);


/**
  @name     sinfo_new_shift_image
  @memo     Shift an image by a given (non-integer) 2d offset.
  @param    image_in        Image to shift.
  @param    shift_x         Shift in x.
  @param    shift_y         Shift in y.
  @param    interp_kernel   Interpolation kernel to use.
  @return   1 newly allocated image.
  @see      sinfo_generate_interpolation_kernel
  @doc This function shifts an image by a non-integer offset, using
  interpolation. You can either generate an interpolation kernel once and
  pass it to this function, or let it generate a default kernel. In the
  former case, use sinfo_generate_interpolation_kernel() to generate an
  appropriate kernel. In the latter case, pass NULL as last argument. A
  default interpolation kernel is then generated then discarded before this
  function returns.
 
  The returned image is a newly allocated object, it must be deallocated
  using cpl_image_delete().
 */

cpl_image *
sinfo_new_shift_image(
    cpl_image    *    image_in,
    double           shift_x,
    double           shift_y,
    double       *    interp_kernel) ;
/**
   @name  sinfo_new_mean_of_columns()
   @param im    input image
   @result  resulting row array
   @doc   takes the average of each image column
*/
Vector * 
sinfo_new_mean_of_columns( cpl_image * im ) ;


/**
   @name       sinfo_new_clean_mean_of_columns()
   @param      image, percentage of lowest and highest values to reject
   @result     resulting row image
   @doc        takes the average of each image column by sorting the
               column values and rejecting the given percentage of
               the highest and lowest values  [0...1]
*/

double 
sinfo_new_my_median_image(cpl_image* im);


cpl_image * 
sinfo_new_clean_mean_of_columns( cpl_image * im,
                               float lo_reject,
                               float hi_reject) ;


/**
   @name  sinfo_new_div_image_by_row()
   @memo      divides each image column by a row value
   @param im      input image
   @param row array
   @result resulting image
*/

cpl_image * 
sinfo_new_div_image_by_row( cpl_image * im, Vector * row ) ;

/**
   @name  sinfo_new_mult_row_to_image()
   @param im image
   @param row array
   @doc     resulting image
   @memo     multiplies each image column with a row value
*/

cpl_image * 
sinfo_new_mult_row_to_image( cpl_image *im, Vector *row ) ;

/**
   @memo     sinfo_new_col_tilt()
   @param    image input image 
   @param    sigmaFactor image factor of sigma noise limit to determine 
             pixels that are used for the fit.
   @return      image
   @doc      first calculates statistics for each column of an image.
             median value and standard deviation of columns are de-
             termined, blank values are excluded. Fits a straight 
             line through the pixel values of each column and subtracts
             the fit in order to remove the tilt of each column.
             Only those pixels are used for the fit that are within 
             a defined factor of sigma noise limit. The noise is 
             calculated from pixels between the 10percentil and 
             90percentil points. 
   @note    works only for raw or averaged raw images
*/

cpl_image * 
sinfo_new_col_tilt ( cpl_image * image, float sigmaFactor ) ;
/**
   @name     sinfo_new_median_image()
   @param    image a median threshold parameter
   @return   resulting image
   @doc      median filter, calculates the sinfo_median for an image
             by using the 8 closest pixels to each pixel.
   The values in the output image are determined according
   to the values of the input parameter. 
   If fmedian = 0: always replace by median
   if fmedian < 0: replace by sinfo_median if |pixel - sinfo_median| > -fmedian
   if fmedian > 0: replace by sinfo_median if (fmedian as a factor of
                   the square root of the sinfo_median itself
   if |pixel - sinfo_median| >= fmedian * sqrt ( sinfo_median )
   This can be used to consider photon noise.
   This considers a dependence of the differences on the pixel values 
   themselves.
   @note  it is assumed that most of the 8 nearest neighbor pixels are not 
          bad pixels! blank pixels are not replaced!
*/

cpl_image * 
sinfo_new_median_image( cpl_image * im, float fmedian ) ;

/**
   @name    sinfo_new_compare_images()
   @param   im1 original image
   @param   im2 image to be compared 
   @return  resulting image
   @doc if a pixel value of one image (im1) equals the pixel value of the 
        other image keep the pixel value of the original image otherwise 
        replace it with ZEROs
*/

cpl_image * 
sinfo_new_compare_images(cpl_image * im1, cpl_image * im2, cpl_image * origim);
/**
   @name   sinfo_threshImage()
   @param  im image
   @param  lo_cut low cut pixel value
   @param  hi_cut high cut pixel value
   @result resulting image
   @doc    simple search for static bad pixels for a flat field or dark frame, 
           values below and above the threshold values are set to BLANK.
*/

cpl_image * 
sinfo_new_thresh_image ( cpl_image * im, float lo_cut, float hi_cut ) ;

/**
   @name sinfo_new_promote_image_to_mask()
   @param  image with ZERO indicating bad pixels
   @param  n_badpixels: number of bad pixels
   @result resulting mask image that means 1 for good pixels
           and ZEROS for bad pixel positions
   @doc    changes an image with ZERO indicated bad pixels to
           a bad pixel mask image, that means the returned
           image has values 1 at positions of good pixels and
           ZEROs at positions of bad pixels.
*/
cpl_image * 
sinfo_new_promote_image_to_mask(cpl_image * im, int * n_badpixels ) ;
/**
   @name sinfo_new_mult_image_by_mask()
   @param  im   input image
   @param  mask mask image
   @result resulting image that means the input image with marked
           static bad pixels (ZERO values)
   @doc    changes an image to an image that has ZERO indicated static bad 
           pixels
*/

cpl_image * sinfo_new_mult_image_by_mask ( cpl_image * im, cpl_image * mask ) ;

/**
   @name  sinfo_new_interpol_image()
   @param im   raw image
   @param mask bad pixel mask
   @param max_radius maximum x and y distance in pixels from the
                     bad pixel within which valid pixels for
                     interpolation are searched.
   @param n_pixels   minimal number of pixels with which the bad
                     pixel is interpolated if not enough
                     valid nearest neighbors are found.
   @result resulting interpolated image without any ZEROS
   @doc    interpolates all bad pixels indicated by the bad pixel mask.
           Therefore, the mean of at least 2 valid values of
           the nearest 8 neighbors is taken. If too much neighbors are also 
           bad pixels the neighbor radius is increased to a maximum of
           max_radius until n_pixels valid pixels are found.
           The valid neighbors are searched by going through the columns and 
           rows around the central square that was already searched.
           The bad pixel is interpolated by the mean of these valid pixels 
           (less than 9) or by the sinfo_median of them (more than 8).
*/

cpl_image * 
sinfo_new_interpol_image ( cpl_image * im,
                           cpl_image * mask,
                           int        max_radius,
                           int        n_pixels ) ;

/**
   @name  sinfo_interpol_source_image()
   @param im         source raw image
   @param mask       bad pixel mask
   @param max_rad    maximum pixel distance from the bad pixel to
                     interpolate where valid pixel values are searched for.
   @param slit_edges array of the edges of the slitlets.
   @result resulting interpolated image hopefully without any ZEROS
   @doc    interpolates all bad pixels indicated by the bad pixel mask.
           Therefore, the mean of the nearest 4 neighbors is taken,
           two in spectral direction and 2 in spatial direction.
           The routine cares about the image and slitlet edges.
           If there are no good pixel found within the nearest neighbors,
           the next 4 nearest neighbors in spatial and spectral direction
           are searched for valid pixels until a limit of max_rad.
          A maximum of 4 valid pixels are used for interpolation by their mean.
*/

cpl_image * 
sinfo_interpol_source_image ( cpl_image * im,
                                 cpl_image * mask,
                                 int        max_rad,
                                 float   ** slit_edges ) ;

/**
   @name    sinfo_new_stack_row_to_image()
   @memo   stack a given image row to build a whole image
   @param   row one image row as sinfo_vector data structure
   @param   ly  image length
   @return  resulting image
*/


cpl_image * 
sinfo_new_stack_row_to_image ( Vector * row, int ly ) ;


/**
   @name sinfo_new_image_stats_on_rectangle()
   @param im: flatfield image to search for bad pix
   @param loReject
   @param hiReject: percentage (0...100) of extrem values that should not be 
                    considered
   @param llx
   @param lly lower left pixel position of rectangle
   @param urx
   @param ury upper right pixel position of rectangle
   @return data structure giving the mean and standard deviation
   @doc  computes the mean and standard deviation of a given rectangle on an 
         image by leaving the extreme intensity values.
*/


Stats * 
sinfo_new_image_stats_on_rectangle ( cpl_image * im,
                                float      loReject,
                                float      hiReject,
                                int        llx,
                                int        lly,
                                int        urx,
                                int        ury ) ;

/**
   @name   sinfo_new_normalize_to_central_pixel()
   @memo normalizes a raw flatfield image by dividing by the median of the 
         central spectral pixels to produce a master flatfield
   @param  image: image to normalize
   @result resulting image
 */


cpl_image * 
sinfo_new_normalize_to_central_pixel ( cpl_image * image ) ;

/**
  @name         sinfo_new_shift_image
  @memo         Shift an image by a given (non-integer) 2d offset.
  @param        image_in                Image to shift.
  @param        shift_x                 Shift in x.
  @param        shift_y                 Shift in y.
  @param        interp_kernel   Interpolation kernel to use.
  @return       1 newly allocated image.
  @see          sinfo_generate_interpolation_kernel
  @doc

  This function is a conversion to CPL of the ECLIPSE function shift_image()
  but slightly changed. If a blank (ZERO) pixel appears the blank pixel
  is shifted but preserved as blank.
  If a blank (ZERO) pixel appears within the
  interpolation kernel the blank pixel is set to 0.

  This function shifts an image by a non-integer offset, using
  interpolation. You can either generate an interpolation kernel once and
  pass it to this function, or let it generate a default kernel. In the
  former case, use sinfo_generate_interpolation_kernel() to generate an
  appropriate kernel. In the latter case, pass NULL as last argument. A
  default interpolation kernel is then generated then discarded before this
  function returns.

  The returned image is a newly allocated object, it must be deallocated
  using cpl_image_delete().
 */


cpl_image *
sinfo_new_mpe_shift_image(
    cpl_image    *    image_in,
    double           shift_x,
    double           shift_y,
    double       *   interp_kernel) ;

/**
@name sinfo_new_shift_image_in_cube
@param shift_x  image shift along X
@param shift_y  image shift along Y
@param interp_kernel interolation kernel
@param shifted resulting shifted image
@param firs_pass low pass band filter
*/

void
sinfo_new_shift_image_in_cube(
    cpl_image     *   image_in,
    double           shift_x,
    double           shift_y,
    double       *   interp_kernel,
    cpl_image     *   shifted,
    pixelvalue   *   first_pass) ;


void sinfo_new_del_Stats (Stats *) ;


/**
   @name   sinfo_new_combine_masks()
   @memo    combines two bad pixel mask to one using an or relation
   @param  firstMask bad pixel mask to combine
   @param  secondMask bad pixel masks to combine
   @result resulting image
*/

cpl_image * 
sinfo_new_combine_masks ( cpl_image * firstMask, cpl_image * secondMask ) ;

/**
   @name    sinfo_new_slice_cube()
   @memo   slices a data cube in x or y direction
   @param   cube: input reduced data cube
   @param   x x slice pixel value 
   @param   y y slice pixel value
   @result  resulting slice image
*/


cpl_image * 
sinfo_new_slice_cube (cpl_imagelist * cube, int x, int y ) ;


/**
   @name  sinfo_new_div_images_robust()
   @param im1 input image im1
   @param im2 input image im2
   @result resulting divided image
   @doc divides two images by considering blanks and calculating first 1/im2 by
        cutting the very high values and setting to 1,then multiplying 
        im1 * 1/im2.
*/

cpl_image * 
sinfo_new_div_images_robust ( cpl_image * im1, cpl_image * im2 ) ;



cpl_image * 
sinfo_new_null_edges ( cpl_image * image) ;



void 
sinfo_new_used_cor_map( cpl_image *im, cpl_image *map);


cpl_image *
sinfo_image_smooth_mean_y(cpl_image * inp,const int r);

cpl_image *
sinfo_image_smooth_median_y(cpl_image * inp,const int r);

cpl_image *
sinfo_image_hermite_interpol(cpl_image * inp);

cpl_image *
sinfo_image_smooth_fft(cpl_image * inp, const int r);

#endif
