/** \file
 * \brief Image Processing
 *
 * See Copyright Notice in im_lib.h
 * $Id: Exp $
 */

#ifndef __IM_PROCESS_H
#define __IM_PROCESS_H

#include "im_image.h"

#if	defined(__cplusplus)
extern "C" {
#endif



/** \defgroup process Image Processing
 * \par
 * Several image processing functions based on the \ref imImage structure.
 * \par
 * You must link the application with "im_process.lib/.a/.so". \n
 * Some complex operations use the \ref Counter.\n
 * There is no check on the input/output image properties, 
 * check each function documentation before using it.
 * \par
 * See \ref im_process.h
 */




/** \defgroup resize Image Resize
 * \par
 * Operations to change the image size.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Only reduze the image size using the given decimation order. \n
 * Supported interpolation orders:
 * \li 0 - zero order (mean) 
 * \li 1 - first order (bilinear decimation)
 * Images must be of the same type. \n
 * Returns zero if the counter aborted.
 * \ingroup resize */
int imProcessReduce(const imImage* src_image, imImage* dst_image, int order);

/** Change the image size using the given interpolation order. \n
 * Supported interpolation orders:
 * \li 0 - zero order (near neighborhood) 
 * \li 1 - first order (bilinear interpolation) 
 * \li 3 - third order (bicubic interpolation)
 * Images must be of the same type. \n
 * Returns zero if the counter aborted.
 * \ingroup resize */
int imProcessResize(const imImage* src_image, imImage* dst_image, int order);

/** Reduze the image area by 4 (w/2,h/2). \n
 * Images must be of the same type. Destiny image size must be source image width/2, height/2.
 * \ingroup resize */
void imProcessReduceBy4(const imImage* src_image, imImage* dst_image);

/** Reduze the image size by removing pixels. \n
 * Images must be of the same type. Destiny image size must be smaller than source image width-xmin, height-ymin.
 * \ingroup resize */
void imProcessCrop(const imImage* src_image, imImage* dst_image, int xmin, int ymin);

/** Increase the image size by adding pixels with zero value. \n
 * Images must be of the same type. Destiny image size must be greatter than source image width+xmin, height+ymin.
 * \ingroup resize */
void imProcessAddMargins(const imImage* src_image, imImage* dst_image, int xmin, int ymin);



/** \defgroup arithm Arithmetic Operations 
 * \par
 * Simple math operations for images.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Unary Arithmetic Operations.
 * \ingroup arithm */
enum imUnaryOp {
  IM_UN_EQL,    /**< equal             =     a        */
  IM_UN_ABS,    /**< abssolute         =    |a|       */
  IM_UN_LESS,   /**< less              =    -a        */
  IM_UN_INC,    /**< increment        +=     a        */
  IM_UN_INV,    /**< invert            =   1/a        */
  IM_UN_SQR,    /**< square            =     a*a      */
  IM_UN_SQRT,   /**< square root       =     a^(1/2)  */
  IM_UN_LOG,    /**< natural logarithm =  ln(a)       */
  IM_UN_EXP,    /**< exponential       = exp(a)       */
  IM_UN_SIN,    /**< sine              = sin(a)       */
  IM_UN_COS,    /**< cosine            = cos(a)       */
  IM_UN_CONJ,   /**< complex conjugate =     ar - ai*i                   */
  IM_UN_CPXNORM /**< complex normalization by magnitude = a / cpxmag(a)  */
};

/** Apply an arithmetic unary operation. \n
 * Can be done in place, images must match size, does not need to match type.
 * \ingroup arithm */
void imProcessUnArithmeticOp(const imImage* src_image, imImage* dst_image, int op);

/** Binary Arithmetic Operations.
 * \ingroup arithm */
enum imBinaryOp {
  IM_BIN_ADD,    /**< add         =    a+b            */
  IM_BIN_SUB,    /**< subtract    =    a-b            */
  IM_BIN_MUL,    /**< multiply    =    a*b            */
  IM_BIN_DIV,    /**< divide      =    a/b            */
  IM_BIN_DIFF,   /**< difference  =    |a-b|          */
  IM_BIN_POW,    /**< power       =    a^b            */
  IM_BIN_MIN,    /**< minimum     =    (a < b)? a: b  */
  IM_BIN_MAX     /**< maximum     =    (a > b)? a: b  */
};

/** Apply a binary arithmetic operation. \n
 * Can be done in place, images must match size. \n
 * Source images must match type, destiny image can be: \n
 * \li byte -> byte, ushort, int, float
 * \li ushort -> ushort, int, float
 * \li int -> int, float
 * \li float -> float
 * \li complex -> complex
 * One exception is that you can combine complex with float resulting complex.
 * \ingroup arithm */
void imProcessArithmeticOp(const imImage* src_image1, const imImage* src_image2, imImage* dst_image, int op);

/** Apply a binary arithmetic operation with a constant value. \n
 * Can be done in place, images must match size. \n
 * Destiny image can be: \n
 * \li byte -> byte, ushort, int, float
 * \li ushort -> byte, ushort, int, float
 * \li int -> byte, ushort, int, float
 * \li float -> float
 * \li complex -> complex
 * The constant value is type casted to an apropriate type before the operation.
 * \ingroup arithm */
void imProcessArithmeticConstOp(const imImage* src_image, float src_const, imImage* dst_image, int op);

/** Blend two images using an alpha value = [a * alpha + b * (1 - alpha)]. \n
 * Can be done in place, images must match size and type.
 * \ingroup arithm */
void imProcessBlend(const imImage* src_image1, imImage* src_image2, imImage* dst_image, float alpha);

/** Split a complex image into two images with real and imaginary parts \n
 * or magnitude and phase parts (polar = 1). \n
 * Source image must be IM_COMPLEX, destiny images must be IM_FLOAT.
 * \ingroup arithm */
void imProcessSplitComplex(const imImage* src_image, imImage* dst_image1, imImage* dst_image2, int polar);

/** Merges two images as the real and imaginary parts of a complex image, \n
 * or as magnitude and phase parts (polar = 1). \n
 * Source images must be IM_FLOAT, destiny image must be IM_COMPLEX.
 * \ingroup arithm */
void imProcessMergeComplex(const imImage* src_image1, const imImage* src_image2, imImage* dst_image, int polar);

/** Calculates the mean of multiple images. \n
 * Images must match size and type.
 * \ingroup arithm */
void imProcessMultipleMean(const imImage** src_image_list, int src_image_count, imImage* dst_image);

/** Calculates the standard deviation of multiple images. \n
 * Images must match size and type.
 * \ingroup arithm */
void imProcessMultipleStdDev(const imImage** src_image_list, int src_image_count, const imImage *mean_image, imImage* dst_image);

/** Calculates the auto-covariance of an image with the mean of a set of images. \n
 * Images must match size and type. Returns zero if the counter aborted.
 * \ingroup arithm */
int imProcessAutoCovariance(const imImage* src_image, const imImage* mean_image, imImage* dst_image);

/** Multiplies the conjugate of one complex image with another complex image. \n
 * Images must match size. Conj(img1) * img2 \n
 * Can be done in-place.
 * \ingroup arithm */
void imProcessMultiplyConj(const imImage* src_image1, const imImage* src_image2, imImage* dst_image);


/** \defgroup geom Geometric Operations
 * \par
 * Operations to change the shape of the image.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Calculates the size of the new image after rotation.
 * \ingroup geom */
void imProcessCalcRotateSize(int width, int height, int *new_width, int *new_height, double cos0, double sin0);

/** Rotates the image using the given interpolation order (see imProcessResize). \n
 * Images must be of the same type. The destiny size can be calculated using \ref imProcessCalcRotateSize. \n
 * Returns zero if the counter aborted.
 * \ingroup geom */
int imProcessRotate(const imImage* src_image, imImage* dst_image, double cos0, double sin0, int order);

/** Rotate the image in 90 degrees counterclockwise or clockwise. Swap columns by lines. \n
 * Images must be of the same type. Destiny width and height must be source height and width. 
 * \ingroup geom */
void imProcessRotate90(const imImage* src_image, imImage* dst_image, int dir);

/** Rotate the image in 180 degrees. Swap columns and swap lines. \n
 * Images must be of the same type and size.
 * \ingroup geom */
void imProcessRotate180(const imImage* src_image, imImage* dst_image);

/** Mirrors the image in a horizontal flip. Swap columns. \n
 * Images must be of the same type and size.
 * \ingroup geom */
void imProcessMirror(const imImage* src_image, imImage* dst_image);

/** Apply a vertical flip. Swap lines. \n
 * Images must be of the same type and size.
 * \ingroup geom */
void imProcessFlip(const imImage* src_image, imImage* dst_image);

/** Apply a radial distortion using the given interpolation order (see imProcessResize). \n
 * Images must be of the same type and size. Returns zero if the counter aborted.
 * \ingroup geom */
int imProcessRadial(const imImage* src_image, imImage* dst_image, float k1, int order);



/** \defgroup stats Image Statistics Calculations
 * \par
 * Operations to calculate some statistics over images.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Calculates the RMS error between 2 images (Root Mean Square Error).
 * \ingroup stats */
float imCalcRMSError(const imImage* image1, const imImage* image2);

/** Calculates the SNR of an image and its noise (Signal Noise Ratio).
 * \ingroup stats */
float imCalcSNR(const imImage* src_image, const imImage* noise_image);

/** Count the number of different colors in an image. \n
 * Image must be IM_BYTE, but all color spaces except IM_CMYK.
 * \ingroup stats */
unsigned long imCalcCountColors(const imImage* src_image);

/** Calculates the histogram of a IM_BYTE data. \n
 * Histogram is always 256 positions long. \n
 * When accum is different from zero it calculates the accumulated histogram.
 * \ingroup stats */
void imCalcHistogram(const unsigned char* data, int count, unsigned long* histo, int accum);

/** Calculates the gray histogram of an image. \n
 * Image must be IM_BYTE/(IM_RGB, IM_GRAY, IM_BINARY or IM_MAP). \n
 * If the image is IM_RGB then the histogram of the luma component is calculated. \n
 * Histogram is always 256 positions long. \n
 * When accum is different from zero it calculates the accumulated histogram.
 * \ingroup stats */
void imCalcGrayHistogram(const imImage* src_image, unsigned long* histo, int accum);

/** Numerical Statistics Structure
 * \ingroup stats */
typedef struct _imStats
{
  float max;                /**< Maximum value              */
  float min;                /**< Minimum value              */
  unsigned long positive;   /**< Number of Positive Values  */
  unsigned long negative;   /**< Number of Negative Values  */
  unsigned long zeros;      /**< Number of Zeros            */
  float mean;               /**< Mean                       */
  float stddev;             /**< Standard Deviation         */
} imStats;

/** Calculates the statistics about the image data. \n
 * There is one stats for each depth plane. For ex: stats[0]=red stats, stats[0]=green stats, ... \n
 * Supports all data types except IM_COMPLEX. \n
 * \ingroup stats */
void imCalcImageStatistics(const imImage* src_image, imStats* stats);

/** Calculates the statistics about the image histogram data.\n
 * There is one stats for each depth plane. For ex: stats[0]=red stats, stats[0]=green stats, ... \n
 * Only IM_BYTE images are supported.
 * \ingroup stats */
void imCalcHistogramStatistics(const imImage* src_image, imStats* stats);

/** Calculates some extra statistics about the image histogram data.\n
 * There is one stats for each depth plane. \n
 * Only IM_BYTE images are supported. \n
 * mode will be -1 if more than one max is found.
 * \ingroup stats */
void imCalcHistoImageStatistics(const imImage* src_image, int* median, int* mode);



/** \defgroup quantize Additional Image Quantization Operations
 * \par
 * Additionally operations to the \ref imConvertColorSpace function.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Converts a RGB image to a MAP image using uniform quantization 
 * with an optional 8x8 ordered dither. The RGB image must have data type IM_BYTE.
 * \ingroup quantize */
void imProcessQuantizeRGBUniform(const imImage* src_image, imImage* dst_image, int dither);

/** Quantizes a gray scale image in less that 256 grays using uniform quantization. \n
 * Both images must be IM_BYTE/IM_GRAY. Can be done in place. 
 * \ingroup quantize */
void imProcessQuantizeGrayUniform(const imImage* src_image, imImage* dst_image, int grays);



/** \defgroup histo Histogram Based Operations
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Performs an histogram expansion. \n
 * Percentage defines an amount of pixels to include at start and end.
 * If its is zero only empty counts of the histogram will be considered. \n
 * Images must be IM_BYTE/(IM_RGB, IM_GRAY, IM_BINARY or IM_MAP). Can be done in place. 
 * \ingroup histo */
void imProcessExpandHistogram(const imImage* src_image, imImage* dst_image, float percent);

/** Performs an histogram equalization. \n
 * Images must be IM_BYTE/(IM_RGB, IM_GRAY, IM_BINARY or IM_MAP). Can be done in place. 
 * \ingroup histo */
void imProcessEqualizeHistogram(const imImage* src_image, imImage* dst_image);



/** \defgroup transform Domain Transform Operations
 * \par
 * FFT, Wavelts, Hough.
 * \par
 * FFTW Copyright Matteo Frigo, Steven G. Johnson and the MIT. \n
 * http://www.fftw.org                                         \n
 * See fftw.h or fftw3.h
 * \par
 * Must link with "im_fftw.lib" for FFTW version 2.1.5, and "im_fftw3.lib" for version 3.0.1. \n
 * Both libraries are available because version 3 was not that fast from version 2, 
 * and its file size is 3x bigger than version 2. But version 3 was not compiled using hardware 
 * otimizations.
 * \par
 * The FFTW lib has a GPL license. The license of the "im_fftw.lib" library is automatically the GPL.
 * So you cannot use it for commercial applications without contacting the authors. 
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Forward FFT. \n
 * The result has its lowest frequency at the center of the image. \n
 * This is an unnormalized fft. \n
 * Images must be of the same size. Destiny image must be of type complex.
 * \ingroup transform */
void imProcessFFT(const imImage* src_image, imImage* dst_image);

/** Inverse FFT. \n
 * The image has its lowest frequency restored to the origin before the transform. \n
 * The result is normalized by (width*height). \n
 * Images must be of the same size and both must be of type complex.
 * \ingroup transform */
void imProcessIFFT(const imImage* src_image, imImage* dst_image);

/** Raw in-place FFT (forward or inverse). \n
 * The lowest frequency can be centered after forward, or
 * can be restored to the origin before inverse. \n
 * The result can be normalized after the transform by sqrt(w*h) [1] or by (w*h) [2], 
 * or left unnormalized [0]. \n
 * Images must be of the same size and both must be of type complex.
 * \ingroup transform */
void imProcessFFTraw(imImage* src_image, int inverse, int center, int normalize);

/** Auxiliary function for the raw FFT. \n 
 * This is the function used internally to change the lowest frequency position in the image. \n
 * If the image size has even dimensions the flag "center2origin" is useless. But if it is odd, 
 * you must specify if its from center to origin (usually used before inverse) or
 * from origin to center (usually used after forward). \n
 * Notice that this function is used for images in the the frequency domain. \n
 * Image type must be complex.
 * \ingroup transform */
void imProcessSwapQuadrants(imImage* src_image, int center2origin);

/** Hough Lines Transform. \n
 * It will detect white lines in a black background. So the source image must be a IM_BINARY image 
 * with the white lines of interest enhanced. The better the threshold with the white lines the better 
 * the line detection. \n
 * The destiny image must have IM_GRAY, IM_INT, width=180, height=2*rmax+1, where rmax is the image diagonal/2. \n
 * Returns zero if the counter aborted. \n
 * Inspired from ideas in XITE, Copyright 1991, Blab, UiO \n
 * http://www.ifi.uio.no/~blab/Software/Xite/
 * \ingroup transform */
int imProcessHoughLines(const imImage* src_image, imImage* dst_image);

/** Draw detected hough lines. \n
 * The source image must be IM_GRAY and IM_BYTE. The destiny image can be a clone of the source image or 
 * it can be the source image for in place processing. \n
 * The hough points image is a hough transform image that was thresholded to a IM_BINARY image, 
 * usually using a Local Max threshold operation. Again the better the threshold the better the results. \n
 * The destiny image will be set to IM_MAP, and the detected lines will be drawn using a red color. \n
 * Returns the number of detected lines.
 * \ingroup transform */
int imProcessHoughLinesDraw(const imImage* src_image, const imImage* hough_points, imImage* dst_image);

/** Calculates the Cross Correlation in the frequency domain. \n 
 * CrossCorr(a,b) = IFFT(Conj(FFT(a))*FFT(b)) \n
 * Images must be of the same size and only destiny image must be of type complex.
 * \ingroup transform */
void imProcessCrossCorrelation(const imImage* src_image1, const imImage* src_image2, imImage* dst_image);

/** Calculates the Auto Correlation in the frequency domain. \n 
 * Uses the cross correlation.
 * Images must be of the same size and only destiny image must be of type complex.
 * \ingroup transform */
void imProcessAutoCorrelation(const imImage* src_image, imImage* dst_image);



/** \defgroup effects Special Effects
 * \par
 * Operations to change image appearance.
 * \par
 * See \ref im_process.h
 * \ingroup process */


/** Generates a zoom in effect averaging colors inside a square region. \n
 * Operates only on IM_BYTE images.
 * \ingroup effects */
void imProcessPixelate(const imImage* src_image, imImage* dst_image, int box_size);

/** A simple Posterize effect. It reduces the number of color in the image eliminating 
 * less significant bit planes. Can have 1 to 7 levels. See \ref imProcessBitMask. \n
 * Image data type must be integer.
 * \ingroup effects */
void imProcessPosterize(const imImage* src_image, imImage* dst_image, int level);

/** A negative effect. Uses \ref imProcessToneGamut with IM_GAMUT_INVERT for non MAP images. \n
 * Supports all color spaces and all data types except IM_COMPLEX.
 * \ingroup effects */
void imProcessNegative(const imImage* src_image, imImage* dst_image);

/** Replaces the source color by the destiny color. \n
 * The color will be type casted to the image data type. \n
 * The colors must have the same number of components of the images. \n
 * Supports all color spaces and all data types except IM_COMPLEX.
 * \ingroup effects */
void imProcessReplaceColor(const imImage* src_image, imImage* dst_image, float* src_color, float* dst_color);


/** \defgroup colorproc Color Processing Operations
 * \par
 * Operations to change the color components configuration.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Split a RGB image into luma and chroma. \n
 * Chroma is calculated as R-Y,G-Y,B-Y. Source image must be IM_RGB/IM_BYTE. \n
 * luma image is IM_GRAY/IM_BYTE and chroma is IM_RGB/IM_BYTE. \n
 * Source and destiny have the same size. 
 * \ingroup colorproc */
void imProcessSplitYChroma(const imImage* src_image, imImage* y_image, imImage* chroma_image);

/** Split a RGB image into HSI planes. \n
 * Source image must be IM_RGB/IM_BYTE. Destiny images are all IM_GRAY/IM_BYTE. \n
 * Source and destiny have the same size. See \ref hsi .
 * \ingroup colorproc */
void imProcessSplitHSI(const imImage* src_image, imImage* h_image, imImage* s_image, imImage* i_image);

/** Merge HSI planes into a RGB image. \n
 * Source images must be IM_GRAY/IM_BYTE. Destiny image is all IM_RGB/IM_BYTE. \n
 * Source and destiny have the same size. See \ref hsi .
 * \ingroup colorproc */
void imProcessMergeHSI(const imImage* h_image, const imImage* s_image, const imImage* i_image3, imImage* dst_image);

/** Split a multicomponent image into separate components.\n
 * Destiny images must be IM_GRAY. Size and data types must be all the same.\n
 * The number of destiny images must match the depth of the source image.
 * \ingroup colorproc */
void imProcessSplitComponents(const imImage* src_image, imImage** dst_image);

/** Merges separate components into a multicomponent image.\n
 * Destiny images must be IM_GRAY. Size and data types must be all the same.\n
 * The number of source images must match the depth of the destiny image.
 * \ingroup colorproc */
void imProcessMergeComponents(const imImage** src_image_list, imImage* dst_image);



/** \defgroup logic Logical Arithmetic Operations 
 * \par
 * Logical binary math operations for images.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Logical Operations.
 * \ingroup logic */
enum imLogicOp {
  IM_BIT_AND,   /**< and  =   a & b   */
  IM_BIT_OR,    /**< or   =   a | b   */
  IM_BIT_XOR,   /**< xor  = ~(a | b)  */
  IM_BIT_NOT    /**< not  =   ~(a)    */
};

/** Apply a logical operation.\n
 * For the IM_BIT_NOT operation the second image is ignored. \n
 * Images must have data type IM_BYTE, IM_USHORT or IM_INT. Can be done in place. 
 * \ingroup logic */
void imProcessBitwiseOp(const imImage* src_image1, const imImage* src_image2, imImage* dst_image, int op);

/** Apply a bit mask. \n
 * The same as imProcessBitwiseOp but the second image is replaced by a fixed mask. \n
 * Images must have data type IM_BYTE. It is valid only for AND, OR and XOR. Can be done in place.
 * \ingroup logic */
void imProcessBitMask(const imImage* src_image, imImage* dst_image, unsigned char mask, int op);

/** Extract or Reset a bit plane. For ex: 000X0000 or XXX0XXXX (plane=3).\n
 * Images must have data type IM_BYTE. Can be done in place. 
 * \ingroup logic */
void imProcessBitPlane(const imImage* src_image, imImage* dst_image, int plane, int reset);



/** \defgroup render Synthetic Image Render
 * \par
 * Renders some 2D mathematical functions as images. All the functions operates in place 
 * and supports all data types except IM_COMPLEX.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Render Funtion.
 * \ingroup render */
typedef float (*imRenderFunc)(int x, int y, int d, float* param);

/** Render Conditional Funtion.
 * \ingroup render */
typedef float (*imRenderCondFunc)(int x, int y, int d, int *cond, float* param);

/** Render a synthetic image using a render function. \n
 * plus will make the render be added to the current image data, 
 * or else all data will be replaced. All the render functions use this or the conditional function. \n
 * Returns zero if the counter aborted.
 * \ingroup render */
int imProcessRenderOp(imImage* image, imRenderFunc render_func, char* render_name, float* param, int plus);

/** Render a sintetic image using a conditional render function. \n
 * Data will be rendered only if the condional param is true. \n
 * Returns zero if the counter aborted.
 * \ingroup render */
int imProcessRenderCondOp(imImage* image, imRenderCondFunc render_func, char* render_name, float* param);

/** Render speckle noise on existing data. Can be done in place.
 * \ingroup render */
int imProcessRenderAddSpeckleNoise(const imImage* src_image, imImage* dst_image, float percent);

/** Render gaussian noise on existing data. Can be done in place.
 * \ingroup render */
int imProcessRenderAddGaussianNoise(const imImage* src_image, imImage* dst_image, float mean, float stddev);

/** Render uniform noise on existing data. Can be done in place.
 * \ingroup render */
int imProcessRenderAddUniformNoise(const imImage* src_image, imImage* dst_image, float mean, float stddev);

/** Render random noise.
 * \ingroup render */
int imProcessRenderRandomNoise(imImage* image);

/** Render a constant. The number of values must match the depth of the image.
 * \ingroup render */
int imProcessRenderConstant(imImage* image, float* value);

/** Render a centered wheel.
 * \ingroup render */
int imProcessRenderWheel(imImage* image, int int_radius, int ext_radius);

/** Render a centered cone.
 * \ingroup render */
int imProcessRenderCone(imImage* image, int radius);

/** Render a centered tent.
 * \ingroup render */
int imProcessRenderTent(imImage* image, int width, int height);

/** Render a ramp. Direction can be vertical (1) or horizontal (0).
 * \ingroup render */
int imProcessRenderRamp(imImage* image, int start, int end, int dir);

/** Render a centered box.
 * \ingroup render */
int imProcessRenderBox(imImage* image, int width, int height);

/** Render a centered sinc.
 * \ingroup render */
int imProcessRenderSinc(imImage* image, float xperiod, float yperiod);

/** Render a centered gaussian.
 * \ingroup render */
int imProcessRenderGaussian(imImage* image, float stddev);

/** Render the laplacian of a centered gaussian.
 * \ingroup render */
int imProcessRenderLapOfGaussian(imImage* image, float stddev);

/** Render a centered cosine.
 * \ingroup render */
int imProcessRenderCosine(imImage* image, float xperiod, float yperiod);




/** \defgroup tonegamut Tone Gamut Operations
 * \par
 * Operations that try to preserve the min-max interval in the output (the dynamic range).
 * \par
 * See \ref im_process.h
 * \ingroup process */


/** Tone Gamut Operations.
 * \ingroup render */
enum imToneGamut {
  IM_GAMUT_NORMALIZE, /**< normalize = (a-min) / (max-min)     (destiny image must be IM_FLOAT)   */
  IM_GAMUT_POW,       /**< pow       = ((a-min) / (max-min))^gamma * (max-min) + min                  \n
                                       param[0]=gamma                                             */
  IM_GAMUT_LOG,       /**< log       = log(K * (a-min) / (max-min) + 1))*(max-min)/log(K+1) + min     \n
                                       param[0]=K     (K>0)                                       */
  IM_GAMUT_EXP,       /**< exp       = (exp(K * (a-min) / (max-min)) - 1))*(max-min)/(exp(K)-1) + min \n
                                       param[0]=K                                                 */
  IM_GAMUT_INVERT,    /**< invert    = max - (a-min)                                              */
  IM_GAMUT_ZEROSTART, /**< zerostart = a - min                                                    */
  IM_GAMUT_SOLARIZE,  /**< solarize  = a < level ?  a:  (level * (max-min) - a * (level-min)) / (max-level) \n
                                       param[0]=level percentage (0-100) relative to min-max      \n
                                       photography solarization effect. */
  IM_GAMUT_SLICE,     /**< slice     = start < a < end ?  min:  binarize?  max: a                      \n
                                       param[0]=start,  param[1]=end,  param[2]=binarize          */
  IM_GAMUT_EXPAND,    /**< expand    = a < start ?  start: a > end ? end :  (a-start)*(max-min)/(end-start) + min  \n
                                       param[0]=start,  param[1]=end                              */
  IM_GAMUT_CROP,      /**< crop      = a < start ?  start: a > end ? end : a                                        \n
                                       param[0]=start,  param[1]=end                              */
  IM_GAMUT_BRIGHTCONT /**< brightcont = a < min ?  min:  a > max ?  max:  a * tan(c_a) + b_s + (max-min)*(1 - tan(c_a))/2  \n
                                        param[0]=bright_shift,  param[1]=contrast_angle (-90..+90)   \n
                                        change brightness and contrast simultaneously. */
};

/** Apply a gamut operation with arguments. \n
 * Supports all data types except IM_COMPLEX. \n
 * The linear operation do a special convertion when min > 0 and max < 1, it forces min=0 and max=1. \n
 * IM_BYTE images have min=0 and max=255 always. \n
 * Can be done in place. When there is no extra params use NULL.
 * \ingroup tonegamut */
void imProcessToneGamut(const imImage* src_image, imImage* dst_image, int op, float* param);

/** Converts from (0-1) to (0-255), crop out of bounds values. \n
 * Source image must be IM_FLOAT, and destiny image must be IM_BYTE.
 * \ingroup tonegamut */
void imProcessUnNormalize(const imImage* src_image, imImage* dst_image);

/** Directly converts IM_USHORT, IM_INT and IM_FLOAT into IM_BYTE images. \n
 * This can also be done using \ref imConvertDataType with IM_CAST_DIRECT.
 * \ingroup tonegamut */
void imProcessDirectConv(const imImage* src_image, imImage* dst_image);



/** \defgroup threshold Threshold Operations
 * \par
 * Operations that converts a IM_GRAY/IM_BYTE image into a IM_BINARY image using several threshold techniques.
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Apply a manual threshold. \n
 * threshold = a <= level ? 0: value \n
 * Usually value is 1 but another common value is 255. Can be done in place. 
 * \ingroup threshold */
void imProcessThreshold(const imImage* src_image, imImage* dst_image, int level, unsigned char value);

/** Apply a threshold by the difference of two images. \n
 * threshold = a1 <= a2 ? 0: 1   \n
 * Can be done in place. 
 * \ingroup threshold */
void imProcessThresholdByDiff(const imImage* src_image1, const imImage* src_image2, imImage* dst_image);

/** Apply a threshold by the Hysteresis method. \n
 * Hysteresis thersholding of edge pixels. Starting at pixels with a
 * value greater than the HIGH threshold, trace a connected sequence
 * of pixels that have a value greater than the LOW threhsold. \n
 * Note: could not find the original source code author name.
 * \ingroup threshold */
void imProcessHysteresisThreshold(const imImage* src_image, imImage* dst_image, int low_thres, int high_thres);

/** Estimates hysteresis low and high threshold levels.
 * \ingroup threshold */
void imProcessHysteresisThresEstimate(const imImage* src_image, int *low_thres, int *high_thres);

/** Calculates the threshold level for manual threshold using an uniform error approach. \n
 * Extracted from XITE, Copyright 1991, Blab, UiO \n
 * http://www.ifi.uio.no/~blab/Software/Xite/
\verbatim
  Reference:
    S. M. Dunn & D. Harwood & L. S. Davis:
    "Local Estimation of the Uniform Error Threshold"
    IEEE Trans. on PAMI, Vol PAMI-6, No 6, Nov 1984.
  Comments: It only works well on images whith large objects.
  Author: Olav Borgli, BLAB, ifi, UiO
  Image processing lab, Department of Informatics, University of Oslo
\endverbatim
 * Returns the used level.
 * \ingroup threshold */
int imProcessUniformErrThreshold(const imImage* src_image, imImage* dst_image);

/** Apply a threshold by using a difusion error method. \n
 * It can be applied on IM_RGB/IM_BYTE images.
 * \ingroup threshold */
void imProcessDifusionErrThreshold(const imImage* src_image, imImage* dst_image, int level);

/** Calculates the threshold level for manual threshold using a percentage of pixels
 * that should stay bellow the threshold. \n
 * Returns the used level.
 * \ingroup threshold */
int imProcessPercentThreshold(const imImage* src_image, imImage* dst_image, float percent);

/** Calculates the threshold level for manual threshold using the Otsu approach. \n
 * Returns the used level. \n
 * Original implementation by Flavio Szenberg.
 * \ingroup threshold */
int imProcessOtsuThreshold(const imImage* src_image, imImage* dst_image);

/** Calculates the threshold level for manual threshold using (max-min)/2. \n
 * Returns the used level.
 * \ingroup threshold */
int imProcessMinMaxThreshold(const imImage* src_image, imImage* dst_image);

/** Estimates Local Max threshold level.
 * \ingroup threshold */
void imProcessLocaMaxThresEstimate(const imImage* src_image, int *thres);



/** \defgroup morphgray Morphology Operations for Gray Images
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Base gray morphology convolution. \n
 * Supports all data types except IM_COMPLEX. Can be applied on color images. \n
 * Kernel is always IM_INT. Use kernel size odd for better results. \n
 * You can use the maximum value or else the minimum value. \n
 * The border is mirrored when the kernel reaches it. All the gray morphology operations use this function. \n
 * If the kernel image attribute "Description" exists it is used by the counter.
 * \ingroup morphgray */
int imProcessGrayMorphConvolve(const imImage* src_image, imImage* dst_image, const imImage* kernel, int ismax);

/** Gray morphology convolution with a kernel full of "0"s and use minimum value.
 * \ingroup morphgray */
int imProcessGrayMorphErode(const imImage* src_image, imImage* dst_image, int kernel_size);

/** Gray morphology convolution with a kernel full of "0"s and use maximum value.
 * \ingroup morphgray */
int imProcessGrayMorphDilate(const imImage* src_image, imImage* dst_image, int kernel_size);

/** Erode+Dilate.
 * \ingroup morphgray */
int imProcessGrayMorphOpen(const imImage* src_image, imImage* dst_image, int kernel_size);

/** Dilate+Erode.
 * \ingroup morphgray */
int imProcessGrayMorphClose(const imImage* src_image, imImage* dst_image, int kernel_size);

/** Open+Difference.
 * \ingroup morphgray */
int imProcessGrayMorphTopHat(const imImage* src_image, imImage* dst_image, int kernel_size);

/** Close+Difference.
 * \ingroup morphgray */
int imProcessGrayMorphWell(const imImage* src_image, imImage* dst_image, int kernel_size);

/** Difference(Erode, Dilate).
 * \ingroup morphgray */
int imProcessGrayMorphGradient(const imImage* src_image, imImage* dst_image, int kernel_size);



/** \defgroup morphbin Morphology Operations for Binary Images
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Base binary morphology convolution. \n
 * Images are all IM_BINARY. Kernel is IM_INT. Use kernel size odd for better results. \n
 * Hit white means hit=1 and miss=0, or else hit=0 and miss=1. \n
 * Use -1 for don't care positions in kernel. \n
 * The operation can be repeated by a number of iterations. The border is mirrored when the kernel reaches it. \n
 * Almost all the binary morphology operations use this function.\n
 * If the kernel image attribute "Description" exists it is used by the counter.
 * \ingroup morphbin */
int imProcessBinMorphConvolve(const imImage* src_image, imImage* dst_image, const imImage* kernel, int hit_white, int iter);

/** Binary morphology convolution with a kernel full of "1"s and hit white.
 * \ingroup morphbin */
int imProcessBinMorphErode(const imImage* src_image, imImage* dst_image, int kernel_size, int iter);

/** Binary morphology convolution with a kernel full of "0"s and hit black.
 * \ingroup morphbin */
int imProcessBinMorphDilate(const imImage* src_image, imImage* dst_image, int kernel_size, int iter);

/** Erode+Dilate.
 * When iteration is more than one it means Erode+Erode+Erode+...+Dilate+Dilate+Dilate+...
 * \ingroup morphbin */
int imProcessBinMorphOpen(const imImage* src_image, imImage* dst_image, int kernel_size, int iter);

/** Dilate+Erode.
 * \ingroup morphbin */
int imProcessBinMorphClose(const imImage* src_image, imImage* dst_image, int kernel_size, int iter);

/** Erode+Difference. \n
 * The difference from the source image is applied only once.
 * \ingroup morphbin */
int imProcessBinMorphOutline(const imImage* src_image, imImage* dst_image, int kernel_size, int iter);

/** Thins the supplied binary image using Rosenfeld's parallel thinning algorithm. \n
 * Reference: \n
 * "Efficient Binary Image Thinning using Neighborhood Maps" \n
 * by Joseph M. Cychosz, 3ksnn64@ecn.purdue.edu              \n
 * in "Graphics Gems IV", Academic Press, 1994
 * \ingroup morphbin */
void imProcessBinMorphThin(const imImage* src_image, imImage* dst_image);



/** \defgroup rank Rank Convolution Operations
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Rank convolution using the median value. \n
 * Returns zero if the counter aborted. \n
 * Supports all data types except IM_COMPLEX. Can be applied on color images.
 * \ingroup rank */
int imProcessMedianConvolve(const imImage* src_image, imImage* dst_image, int ks);

/** Rank convolution using (maximum-minimum) value. \n
 * Returns zero if the counter aborted. \n
 * Supports all data types except IM_COMPLEX. Can be applied on color images.
 * \ingroup rank */
int imProcessRangeConvolve(const imImage* src_image, imImage* dst_image, int ks);

/** Rank convolution using the closest maximum or minimum value. \n
 * Returns zero if the counter aborted. \n
 * Supports all data types except IM_COMPLEX. Can be applied on color images.
 * \ingroup rank */
int imProcessRankClosestConvolve(const imImage* src_image, imImage* dst_image, int ks);

/** Rank convolution using the maximum value. \n
 * Returns zero if the counter aborted. \n
 * Supports all data types except IM_COMPLEX. Can be applied on color images.
 * \ingroup rank */
int imProcessRankMaxConvolve(const imImage* src_image, imImage* dst_image, int ks);

/** Rank convolution using the minimum value. \n
 * Returns zero if the counter aborted. \n
 * Supports all data types except IM_COMPLEX. Can be applied on color images.
 * \ingroup rank */
int imProcessRankMinConvolve(const imImage* src_image, imImage* dst_image, int ks);

/** Threshold using a rank convolution with a range contrast function. \n
 * Supports only IM_BYTE/IM_GRAY to IM_BINARY. \n
 * Local variable threshold by the method of Bernsen. \n
 * Extracted from XITE, Copyright 1991, Blab, UiO \n
 * http://www.ifi.uio.no/~blab/Software/Xite/
\verbatim
  Reference:	
    Bernsen, J: "Dynamic thresholding of grey-level images"
		Proc. of the 8th ICPR, Paris, Oct 1986, 1251-1255.
  Author:     Oivind Due Trier
\endverbatim
 * Returns zero if the counter aborted.
 * \ingroup threshold */
int imProcessRangeContrastThreshold(const imImage* src_image, imImage* dst_image, int ks, int min_range);

/** Threshold using a rank convolution with a local max function.  \n
 * Returns zero if the counter aborted. \n
 * Supports only IM_BYTE/IM_GRAY to IM_BINARY.
 * \ingroup threshold */
int imProcessLocalMaxThreshold(const imImage* src_image, imImage* dst_image, int ks, int min_thres);



/** \defgroup convolve Convolution Operations
 * \par
 * See \ref im_process.h
 * \ingroup process */

/** Base Convolution with a kernel. \n
 * Kernel can be IM_INT or IM_FLOAT, but always IM_GRAY. Use kernel size odd for better results. \n
 * Supports all data types. The border is mirrored when the kernel reaches it. \n
 * Returns zero if the counter aborted. Most of the convolutions use this function.\n
 * If the kernel image attribute "Description" exists it is used by the counter.
 * \ingroup convolve */
int imProcessConvolve(const imImage* src_image, imImage* dst_image, const imImage* kernel);

/** Repeats the convolution a number of times. \n
 * Returns zero if the counter aborted.\n
 * If the kernel image attribute "Description" exists it is used by the counter.
 * \ingroup convolve */
int imProcessConvolveRep(const imImage* src_image, imImage* dst_image, const imImage* kernel, int count);

/** Convolve with a kernel rotating it 8 times and getting the maximum value. \n
 * Kernel must be square. \n
 * The rotation is implemented only for kernel sizes 3x3, 5x5 and 7x7. \n
 * Supports all data types except IM_COMPLEX.
 * Returns zero if the counter aborted.\n
 * If the kernel image attribute "Description" exists it is used by the counter.
 * \ingroup convolve */
int imProcessCompassConvolve(const imImage* src_image, imImage* dst_image, imImage* kernel);

/** Utility function to rotate a kernel one time.
 * \ingroup convolve */
void imProcessRotateKernel(imImage* kernel);

/** Difference(Gaussian1, Gaussian2). \n
 * Supports all data types, 
 * but if source is IM_BYTE or IM_USHORT destiny image must be of type IM_INT.
 * \ingroup convolve */
int imProcessDiffOfGaussianConvolve(const imImage* src_image, imImage* dst_image, float stddev1, float stddev2);

/** Convolution with a laplacian of a gaussian kernel. \n
 * Supports all data types, 
 * but if source is IM_BYTE or IM_USHORT destiny image must be of type IM_INT.
 * \ingroup convolve */
int imProcessLapOfGaussianConvolve(const imImage* src_image, imImage* dst_image, float stddev);

/** Convolution with a kernel full of "1"s inside a circle. \n
 * Supports all data types.
 * \ingroup convolve */
int imProcessMeanConvolve(const imImage* src_image, imImage* dst_image, int ks);

/** Convolution with a gaussian kernel. The gaussian in obtained by repetition of a base 3x3 IM_INT kernel. \n
 * Supports all data types.
 * \ingroup convolve */
int imProcessGaussianConvolve(const imImage* src_image, imImage* dst_image, float stddev);

/** Magnitude of the sobel convolution. \n
 * Supports all data types except IM_COMPLEX.
 * \ingroup convolve */
int imProcessSobelConvolve(const imImage* src_image, imImage* dst_image);

/** Finds the zero crossings of IM_INT and IM_FLOAT images. Crossings are marked with non zero values
 * indicating the intensity of the edge. It is usually used after a second derivative, laplace. \n
 * Extracted from XITE, Copyright 1991, Blab, UiO \n
 * http://www.ifi.uio.no/~blab/Software/Xite/
 * \ingroup convolve */
void imProcessZeroCrossing(const imImage* src_image, imImage* dst_image);

/** First part of the Canny edge detector. Includes the gaussian filtering and the nonmax suppression. \n
 * After using this you could apply a Hysteresis Threshold, see \ref imProcessHysteresisThreshold. \n
 * Image must be IM_BYTE/IM_GRAY. \n
 * Implementation from the book:
 \verbatim
    J. R. Parker
    "Algoritms for Image Processing and Computer Vision"
    WILEY
 \endverbatim
 * \ingroup convolve */
void imProcessCanny(const imImage* im, imImage* NewImage, float stddev);


#if defined(__cplusplus)
}
#endif

#endif
