/*====================================================================*
 -  Copyright (C) 2001 Leptonica.  All rights reserved.
 -
 -  Redistribution and use in source and binary forms, with or without
 -  modification, are permitted provided that the following conditions
 -  are met:
 -  1. Redistributions of source code must retain the above copyright
 -     notice, this list of conditions and the following disclaimer.
 -  2. Redistributions in binary form must reproduce the above
 -     copyright notice, this list of conditions and the following
 -     disclaimer in the documentation and/or other materials
 -     provided with the distribution.
 -
 -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
 -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *====================================================================*/

#ifndef  LEPTONICA_BILATERAL_H
#define  LEPTONICA_BILATERAL_H

/*
 *  Contains the following struct
 *      struct L_Bilateral
 *
 *
 *  For a tutorial introduction to bilateral filters, which apply a
 *  gaussian blur to smooth parts of the image while preserving edges, see
 *    http://people.csail.mit.edu/sparis/bf_course/slides/03_definition_bf.pdf
 *
 *  We give an implementation of a bilateral filtering algorithm given in:
 *    "Real-Time O(1) Bilateral Filtering," by Yang, Tan and Ahuja, CVPR 2009
 *  which is at:
 *    http://vision.ai.uiuc.edu/~qyang6/publications/cvpr-09-qingxiong-yang.pdf
 *  This is based on an earlier algorithm by Sylvain Paris and Frédo Durand:
 *    http://people.csail.mit.edu/sparis/publi/2006/eccv/
 *               Paris_06_Fast_Approximation.pdf
 *
 *  The kernel of the filter is a product of a spatial gaussian and a
 *  monotonically decreasing function of the difference in intensity
 *  between the source pixel and the neighboring pixel.  The intensity
 *  part of the filter gives higher influence for pixels with intensities
 *  that are near to the source pixel, and the spatial part of the
 *  filter gives higher weight to pixels that are near the source pixel.
 *  This combination smooths in relatively uniform regions, while
 *  maintaining edges.
 *
 *  The advantage of the appoach of Yang et al is that it is separable,
 *  so the computation time is linear in the gaussian filter size.
 *  Furthermore, it is possible to do much of the computation as a reduced
 *  scale, which gives a good approximation to the full resolution version
 *  but greatly speeds it up.
 *
 *  The bilateral filtered value at x is:
 *
 *            sum[y in N(x)]: spatial(|y - x|) * range(|I(x) - I(y)|) * I(y)
 *    I'(x) = --------------------------------------------------------------
 *            sum[y in N(x)]: spatial(|y - x|) * range(|I(x) - I(y)|)
 *
 *  where I() is the input image, I'() is the filtered image, N(x) is the
 *  set of pixels around x in the filter support, and spatial() and range()
 *  are gaussian functions:
 *          spatial(x) = exp(-x^2 / (2 * s_s^2))
 *          range(x) = exp(-x^2 / (2 * s_r^2))
 *  and s_s and s_r and the standard deviations of the two gaussians.
 *
 *  Yang et al use a separable approximation to this, by defining a set
 *  of related but separable functions J(k,x), that we call Principal
 *  Bilateral Components (PBC):
 *
 *             sum[y in N(x)]: spatial(|y - x|) * range(|k - I(y)|) * I(y)
 *    J(k,x) = -----------------------------------------------------------
 *             sum[y in N(x)]: spatial(|y - x|) * range(|k - I(y)|)
 *
 *  which are computed quickly for a set of n values k[p], p = 0 ... n-1.
 *  Then each output pixel is found using a linear interpolation:
 *
 *    I'(x) = (1 - q) * J(k[p],x) + q * J(k[p+1],x)
 *
 *  where J(k[p],x) and J(k[p+1],x) are PBC for which
 *    k[p] <= I(x) and k[p+1] >= I(x), and
 *    q = (I(x) - k[p]) / (k[p+1] - k[p]).
 *
 *  We can also subsample I(x), create subsampled versions of J(k,x),
 *  which are then interpolated between for I'(x).
 *
 *  We generate 'pixsc', by optionally downscaling the input image
 *  (using area mapping by the factor 'reduction'), and then adding
 *  a mirrored border to avoid boundary cases.  This is then used
 *  to compute 'ncomps' PBCs.
 *
 *  The 'spatial_stdev' is also downscaled by 'reduction'.  The size
 *  of the 'spatial' array is 4 * (reduced 'spatial_stdev') + 1.
 *  The size of the 'range' array is 256.
 */


/*------------------------------------------------------------------------*
 *                          Bilateral filter                              *
 *------------------------------------------------------------------------*/
struct L_Bilateral
{
    struct Pix      *pixs;           /* clone of source pix                  */
    struct Pix      *pixsc;          /* downscaled pix with mirrored border  */
    l_int32          reduction;      /* 1, 2 or 4x for intermediates         */
    l_float32        spatial_stdev;  /* stdev of spatial gaussian            */
    l_float32        range_stdev;    /* stdev of range gaussian              */
    l_float32       *spatial;        /* 1D gaussian spatial kernel           */
    l_float32       *range;          /* one-sided gaussian range kernel      */
    l_int32          minval;         /* min value in 8 bpp pix               */
    l_int32          maxval;         /* max value in 8 bpp pix               */
    l_int32          ncomps;         /* number of intermediate results       */
    l_int32         *nc;             /* set of k values (size ncomps)        */
    l_int32         *kindex;         /* mapping from intensity to lower k    */
    l_float32       *kfract;         /* mapping from intensity to fract k    */
    struct Pixa     *pixac;          /* intermediate result images (PBC)     */
    l_uint32      ***lineset;        /* lineptrs for pixac                   */
};
typedef struct L_Bilateral  L_BILATERAL;


#endif  /* LEPTONICA_BILATERAL_H */
