/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's 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.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// 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 the Intel Corporation or 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.
//
//M*/

#ifndef OPENCV_CUDAFILTERS_HPP
#define OPENCV_CUDAFILTERS_HPP

#ifndef __cplusplus
#  error cudafilters.hpp header must be compiled as C++
#endif

#include "opencv2/core/cuda.hpp"
#include "opencv2/imgproc.hpp"

/**
  @addtogroup cuda
  @{
    @defgroup cudafilters Image Filtering

Functions and classes described in this section are used to perform various linear or non-linear
filtering operations on 2D images.

@note
   -   An example containing all basic morphology operators like erode and dilate can be found at
        opencv_source_code/samples/gpu/morphology.cpp

  @}
 */

namespace cv { namespace cuda {

//! @addtogroup cudafilters
//! @{

/** @brief Common interface for all CUDA filters :
 */
class CV_EXPORTS_W Filter : public Algorithm
{
public:
    /** @brief Applies the specified filter to the image.

    @param src Input image.
    @param dst Output image.
    @param stream Stream for the asynchronous version.
     */
    CV_WRAP virtual void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()) = 0;
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Box Filter

/** @brief Creates a normalized 2D box filter.

@param srcType Input image type. Only CV_8UC1, CV_8UC4 and CV_32FC1 are supported for now.
@param dstType Output image type. Only the same type as src is supported for now.
@param ksize Kernel size.
@param anchor Anchor point. The default value Point(-1, -1) means that the anchor is at the kernel
center.
@param borderMode Pixel extrapolation method. For details, see borderInterpolate .
@param borderVal Default border value.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa boxFilter
 */
CV_EXPORTS_W Ptr<Filter> createBoxFilter(int srcType, int dstType, Size ksize, Point anchor = Point(-1, -1),
                                       int borderMode = BORDER_DEFAULT, Scalar borderVal = Scalar::all(0));

////////////////////////////////////////////////////////////////////////////////////////////////////
// Linear Filter

/** @brief Creates a non-separable linear 2D filter.

@param srcType Input image type. Supports CV_8U , CV_16U and CV_32F one and four channel image.
@param dstType Output image type. Only the same type as src is supported for now.
@param kernel 2D array of filter coefficients.
@param anchor Anchor point. The default value Point(-1, -1) means that the anchor is at the kernel
center.
@param borderMode Pixel extrapolation method. For details, see borderInterpolate .
@param borderVal Default border value.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa filter2D
 */
CV_EXPORTS_W Ptr<Filter> createLinearFilter(int srcType, int dstType, InputArray kernel, Point anchor = Point(-1, -1),
                                          int borderMode = BORDER_DEFAULT, Scalar borderVal = Scalar::all(0));

////////////////////////////////////////////////////////////////////////////////////////////////////
// Laplacian Filter

/** @brief Creates a Laplacian operator.

@param srcType Input image type. Supports CV_8U , CV_16U and CV_32F one and four channel image.
@param dstType Output image type. Only the same type as src is supported for now.
@param ksize Aperture size used to compute the second-derivative filters (see getDerivKernels). It
must be positive and odd. Only ksize = 1 and ksize = 3 are supported.
@param scale Optional scale factor for the computed Laplacian values. By default, no scaling is
applied (see getDerivKernels ).
@param borderMode Pixel extrapolation method. For details, see borderInterpolate .
@param borderVal Default border value.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa Laplacian
 */
CV_EXPORTS_W Ptr<Filter> createLaplacianFilter(int srcType, int dstType, int ksize = 1, double scale = 1,
                                             int borderMode = BORDER_DEFAULT, Scalar borderVal = Scalar::all(0));

////////////////////////////////////////////////////////////////////////////////////////////////////
// Separable Linear Filter

/** @brief Creates a separable linear filter. In-place processing is supported.

@param srcType Source array type.
@param dstType Destination array type.
@param rowKernel Horizontal filter coefficients. Support kernels with size \<= 32 .
noArray() is supported to ignore the row filtering.
@param columnKernel Vertical filter coefficients. Support kernels with size \<= 32 .
noArray() is supported to ignore the column filtering.
@param anchor Anchor position within the kernel. Negative values mean that anchor is positioned at
the aperture center.
@param rowBorderMode Pixel extrapolation method in the vertical direction For details, see
borderInterpolate.
@param columnBorderMode Pixel extrapolation method in the horizontal direction.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa sepFilter2D
 */
CV_EXPORTS_W Ptr<Filter> createSeparableLinearFilter(int srcType, int dstType, InputArray rowKernel, InputArray columnKernel,
                                                   Point anchor = Point(-1,-1), int rowBorderMode = BORDER_DEFAULT, int columnBorderMode = -1);

////////////////////////////////////////////////////////////////////////////////////////////////////
// Deriv Filter

/** @brief Creates a generalized Deriv operator.

@param srcType Source image type.
@param dstType Destination array type.
@param dx Derivative order in respect of x.
@param dy Derivative order in respect of y.
@param ksize Aperture size. See getDerivKernels for details.
@param normalize Flag indicating whether to normalize (scale down) the filter coefficients or not.
See getDerivKernels for details.
@param scale Optional scale factor for the computed derivative values. By default, no scaling is
applied. For details, see getDerivKernels .
@param rowBorderMode Pixel extrapolation method in the vertical direction. For details, see
borderInterpolate.
@param columnBorderMode Pixel extrapolation method in the horizontal direction.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.
 */
CV_EXPORTS_W Ptr<Filter> createDerivFilter(int srcType, int dstType, int dx, int dy,
                                         int ksize, bool normalize = false, double scale = 1,
                                         int rowBorderMode = BORDER_DEFAULT, int columnBorderMode = -1);

/** @brief Creates a Sobel operator.

@param srcType Source image type.
@param dstType Destination array type.
@param dx Derivative order in respect of x.
@param dy Derivative order in respect of y.
@param ksize Size of the extended Sobel kernel. Possible values are 1, 3, 5 or 7.
@param scale Optional scale factor for the computed derivative values. By default, no scaling is
applied. For details, see getDerivKernels .
@param rowBorderMode Pixel extrapolation method in the vertical direction. For details, see
borderInterpolate.
@param columnBorderMode Pixel extrapolation method in the horizontal direction.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa Sobel
 */
CV_EXPORTS_W Ptr<Filter> createSobelFilter(int srcType, int dstType, int dx, int dy, int ksize = 3,
                                         double scale = 1, int rowBorderMode = BORDER_DEFAULT, int columnBorderMode = -1);

/** @brief Creates a vertical or horizontal Scharr operator.

@param srcType Source image type.
@param dstType Destination array type.
@param dx Order of the derivative x.
@param dy Order of the derivative y.
@param scale Optional scale factor for the computed derivative values. By default, no scaling is
applied. See getDerivKernels for details.
@param rowBorderMode Pixel extrapolation method in the vertical direction. For details, see
borderInterpolate.
@param columnBorderMode Pixel extrapolation method in the horizontal direction.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa Scharr
 */
CV_EXPORTS_W Ptr<Filter> createScharrFilter(int srcType, int dstType, int dx, int dy,
                                          double scale = 1, int rowBorderMode = BORDER_DEFAULT, int columnBorderMode = -1);

////////////////////////////////////////////////////////////////////////////////////////////////////
// Gaussian Filter

/** @brief Creates a Gaussian filter.

@param srcType Source image type.
@param dstType Destination array type.
@param ksize Aperture size. See getGaussianKernel for details.
@param sigma1 Gaussian sigma in the horizontal direction. See getGaussianKernel for details.
@param sigma2 Gaussian sigma in the vertical direction. If 0, then
\f$\texttt{sigma2}\leftarrow\texttt{sigma1}\f$ .
@param rowBorderMode Pixel extrapolation method in the vertical direction. For details, see
borderInterpolate.
@param columnBorderMode Pixel extrapolation method in the horizontal direction.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa GaussianBlur
 */
CV_EXPORTS_W Ptr<Filter> createGaussianFilter(int srcType, int dstType, Size ksize,
                                            double sigma1, double sigma2 = 0,
                                            int rowBorderMode = BORDER_DEFAULT, int columnBorderMode = -1);

////////////////////////////////////////////////////////////////////////////////////////////////////
// Morphology Filter

/** @brief Creates a 2D morphological filter.

@param op Type of morphological operation. The following types are possible:
-   **MORPH_ERODE** erode
-   **MORPH_DILATE** dilate
-   **MORPH_OPEN** opening
-   **MORPH_CLOSE** closing
-   **MORPH_GRADIENT** morphological gradient
-   **MORPH_TOPHAT** "top hat"
-   **MORPH_BLACKHAT** "black hat"
@param srcType Input/output image type. Only CV_8UC1, CV_8UC4, CV_32FC1 and CV_32FC4 are supported.
@param kernel 2D 8-bit structuring element for the morphological operation.
@param anchor Anchor position within the structuring element. Negative values mean that the anchor
is at the center.
@param iterations Number of times erosion and dilation to be applied.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.

@sa morphologyEx
 */
CV_EXPORTS_W Ptr<Filter> createMorphologyFilter(int op, int srcType, InputArray kernel, Point anchor = Point(-1, -1), int iterations = 1);

////////////////////////////////////////////////////////////////////////////////////////////////////
// Image Rank Filter

/** @brief Creates the maximum filter.

@param srcType Input/output image type. Only CV_8UC1 and CV_8UC4 are supported.
@param ksize Kernel size.
@param anchor Anchor point. The default value (-1) means that the anchor is at the kernel center.
@param borderMode Pixel extrapolation method. For details, see borderInterpolate .
@param borderVal Default border value.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.
 */
CV_EXPORTS_W Ptr<Filter> createBoxMaxFilter(int srcType, Size ksize,
                                          Point anchor = Point(-1, -1),
                                          int borderMode = BORDER_DEFAULT, Scalar borderVal = Scalar::all(0));

/** @brief Creates the minimum filter.

@param srcType Input/output image type. Only CV_8UC1 and CV_8UC4 are supported.
@param ksize Kernel size.
@param anchor Anchor point. The default value (-1) means that the anchor is at the kernel center.
@param borderMode Pixel extrapolation method. For details, see borderInterpolate .
@param borderVal Default border value.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.
 */
CV_EXPORTS_W Ptr<Filter> createBoxMinFilter(int srcType, Size ksize,
                                          Point anchor = Point(-1, -1),
                                          int borderMode = BORDER_DEFAULT, Scalar borderVal = Scalar::all(0));

////////////////////////////////////////////////////////////////////////////////////////////////////
// 1D Sum Filter

/** @brief Creates a horizontal 1D box filter.

@param srcType Input image type. Only CV_8UC1 type is supported for now.
@param dstType Output image type. Only CV_32FC1 type is supported for now.
@param ksize Kernel size.
@param anchor Anchor point. The default value (-1) means that the anchor is at the kernel center.
@param borderMode Pixel extrapolation method. For details, see borderInterpolate .
@param borderVal Default border value.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.
 */
CV_EXPORTS_W Ptr<Filter> createRowSumFilter(int srcType, int dstType, int ksize, int anchor = -1, int borderMode = BORDER_DEFAULT, Scalar borderVal = Scalar::all(0));

/** @brief Creates a vertical 1D box filter.

@param srcType Input image type. Only CV_8UC1 type is supported for now.
@param dstType Output image type. Only CV_32FC1 type is supported for now.
@param ksize Kernel size.
@param anchor Anchor point. The default value (-1) means that the anchor is at the kernel center.
@param borderMode Pixel extrapolation method. For details, see borderInterpolate .
@param borderVal Default border value.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.
 */
CV_EXPORTS_W Ptr<Filter> createColumnSumFilter(int srcType, int dstType, int ksize, int anchor = -1, int borderMode = BORDER_DEFAULT, Scalar borderVal = Scalar::all(0));

//! @}

///////////////////////////// Median Filtering //////////////////////////////

/** @brief Performs median filtering for each point of the source image.

@param srcType type of of source image. Only CV_8UC1 if CUDA_VERSION < 11. CV_8UC1, CV_8UC3, CV_8UC4, CV_16UC1, CV_16UC3, CV_16UC4, CV_32FC1, CV_32FC3 or CV_32FC4 if CUDA_VERSION >= 11.
@param windowSize Size of the kernerl used for the filtering. Uses a (windowSize x windowSize) filter.
@param partition Specifies the parallel granularity of the workload. Only used if CUDA_VERSION < 11.

Outputs an image that has been filtered using a median-filtering formulation.

If compiled with CUDA 11 or greater, a wavelet based algorithm is used as described at:
https://cgenglab.github.io/en/publication/sigga22_wmatrix_median/
Yuji Moroto, Nobuyuki Umetani, 2022, "Constant Time Median Filter Using 2D Wavelet Matrix",
                                     ACM Transactions on Graphics, Volume 41, Issue 6.

For earlier versions of CUDA, details on the algorithm used can be found in:
Green, O., 2017. "Efficient scalable median filtering using histogram-based operations",
                  IEEE Transactions on Image Processing, 27(5), pp.2217-2228.

@note
If applied in a CUDA Stream, a distinct filter instance must be created for each Stream. Sharing a single instance across multiple streams is unsupported and may lead to undefined behavior due to stream-specific internal state.
 */
CV_EXPORTS_W Ptr<Filter> createMedianFilter(int srcType, int windowSize, int partition = 128);

}} // namespace cv { namespace cuda {

#endif /* OPENCV_CUDAFILTERS_HPP */
