content: {-# LANGUAGE BangPatterns
             , FlexibleContexts
             , TypeFamilies #-}
  
  -- | Provides high level filtering functions for images.
  --
  -- Use 'Vision.Image.Filter.Internal' if you want to create new image filters.
  --
  -- Filters are operations on images on which the surrounding of each processed
  -- pixel is considered according to a kernel.
  --
  -- See <http://en.wikipedia.org/wiki/Kernel_(image_processing)> for details.
  --
  -- The @radius@ argument of some filters is used to determine the kernel size.
  -- A radius as of 1 means a kernel of size 3, 2 a kernel of size 5 and so on.
  --
  -- /Note:/ filters are currently not supported on multi-channel images (RGB,
  -- RGBA ...) are currently not supported.
  module Vision.Image.Filter (
      -- * Classes and type
        Filterable, Filter, SeparatelyFiltrable
      -- * Morphological operators
      , dilate, erode
      -- * Blur
      , blur, gaussianBlur
      -- * Derivation
      , DerivativeType (..), scharr, sobel
      -- * Others
      , mean
      ) where
  
  import Data.Int
  import Foreign.Storable (Storable)
  
  import Vision.Image.Class (MaskedImage (..), Image (..), FromFunction (..))
  import Vision.Image.Filter.Internal (
        Filterable, Filter, SeparatelyFiltrable (..)
      , DerivativeType
      )
  import Vision.Primitive (Size)
  
  import qualified Vision.Image.Filter.Internal as Internal
  
  -- Morphological operators -----------------------------------------------------
  
  dilate, erode :: ( Image src, Ord (ImagePixel src)
                   , FromFunction res, FromFunctionPixel res ~ ImagePixel src
                   , SeparatelyFiltrable src res (ImagePixel src))
         => Int           -- ^ Kernel radius.
         -> src
         -> res
  
  dilate radius img = Internal.dilate radius `Internal.apply` img
  {-# INLINABLE dilate #-}
  
  erode  radius img = Internal.erode radius `Internal.apply` img
  {-# INLINABLE erode #-}
  
  -- Blur ------------------------------------------------------------------------
  
  -- | Blurs the image by averaging the pixel inside the kernel.
  --
  -- Uses an 'Int32' as accumulator during the averaging operation.
  blur :: ( Image src, Integral (ImagePixel src)
          , FromFunction res, Num (FromFunctionPixel res)
          , SeparatelyFiltrable src res Int32)
         => Int           -- ^ Blur radius.
         -> src
         -> res
  blur radius img =
      let filt :: (Integral src, Num res) => Internal.Blur src Int32 res
          filt = Internal.blur radius
      in filt `Internal.apply` img
  {-# INLINABLE blur #-}
  
  -- | Blurs the image by averaging the pixel inside the kernel using a Gaussian
  -- function.
  --
  -- See <http://en.wikipedia.org/wiki/Gaussian_blur>
  gaussianBlur :: ( Image src, Integral (ImagePixel src)
                  , FromFunction res, Integral (FromFunctionPixel res)
                  , Floating acc, RealFrac acc, Storable acc
                  , SeparatelyFiltrable src res acc)
               => Int     -- ^ Blur radius.
               -> Maybe acc
               -- ^ Sigma value of the Gaussian function. If not given, will be
               -- automatically computed from the radius so that the kernel
               -- fits 3σ of the distribution.
               -> src
               -> res
  gaussianBlur radius mSig img =
      Internal.gaussianBlur radius mSig `Internal.apply` img
  {-# INLINABLE gaussianBlur #-}
  
  -- Derivation ------------------------------------------------------------------
  
  -- | Estimates the first derivative using the Scharr's 3x3 kernel.
  --
  -- Convolves the following kernel for the X derivative:
  --
  -- @
  --  -3   0   3
  -- -10   0  10
  --  -3   0   3
  -- @
  --
  -- And this kernel for the Y derivative:
  --
  -- @
  --  -3 -10  -3
  --   0   0   0
  --   3  10   3
  -- @
  --
  -- Uses an 'Int32' as accumulator during kernel application.
  scharr :: ( Image src, Integral (ImagePixel src)
            , FromFunction res, Integral (FromFunctionPixel res)
            , Storable (FromFunctionPixel res)
            , SeparatelyFiltrable src res (FromFunctionPixel res))
         => DerivativeType -> src -> res
  scharr der img = Internal.scharr der `Internal.apply` img
  {-# INLINABLE scharr #-}
  
  -- | Estimates the first derivative using a Sobel's kernel.
  --
  -- Prefer 'scharr' when radius equals @1@ as Scharr's kernel is more accurate
  -- and is implemented faster.
  --
  -- Uses an 'Int32' as accumulator during kernel application.
  sobel :: ( Image src, Integral (ImagePixel src)
            , FromFunction res, Integral (FromFunctionPixel res)
            , Storable (FromFunctionPixel res)
            , SeparatelyFiltrable src res (FromFunctionPixel res))
        => Int            -- ^ Kernel radius.
        -> DerivativeType
        -> src
        -> res
  sobel radius der img = Internal.sobel radius der `Internal.apply` img
  {-# INLINABLE sobel #-}
  
  -- Others ----------------------------------------------------------------------
  
  -- | Computes the average of a kernel of the given size.
  --
  -- This is similar to 'blur' but with a rectangular kernel and a 'Fractional'
  -- result.
  --
  -- Uses an 'Int32' as accumulator during the averaging operation.
  mean :: ( Image src, Integral (ImagePixel src)
          , FromFunction res, Fractional (FromFunctionPixel res)
          , SeparatelyFiltrable src res Int32)
       => Size -> src -> res
  mean size img =
      let filt :: (Integral src, Fractional res) => Internal.Mean src Int32 res
          filt = Internal.mean size
      in filt `Internal.apply` img
  {-# INLINABLE mean #-}
  