/*======================================================================================

	Program:		RITK Plugins
	Module:			CUDASeparableNormalizedConvolutionFilter.h
	Version:		$Revision: 898 $
	Date:			$Date: 2011-04-29 18:51:40 +0200 (Fri, 29 Apr 2011) $

	Copyright (c) 2010-2011
	Pattern Recognition Lab, 
    University Erlangen-Nuremberg, Germany
    All rights reserved.

	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 RITKCopyright.txt for more information.

	http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#ifndef CUDASEPARABLENORMALIZEDCONVOLUTIONIMAGEFILTER_H__
#define CUDASEPARABLENORMALIZEDCONVOLUTIONIMAGEFILTER_H__

#include <itkProcessObject.h>
#include <itkImageToImageFilter.h>

#include "ritkCudaContext.h"
#include "ritkCudaRegularMemoryImportImageContainer.h"
#include "ritkCudaPitchedMemoryImportImageContainer.h"

#include "CUDASeparableNormalizedConvolutionImageFilterInterfaces.h"

using namespace itk;

/**	@class	CUDASeparableNormalizedConvolutionFilter
 *	@author	Jakob Wasza
 *	@brief	Separable normalized convolution using CUDA
 *
 *	@details
 *	This class implements a fast separable normalized convolution method using the CUDA architecture.
 *	The filter is templated over the input, mask and output image type. This filter employs a gaussian
 *	for the certainty function.
 *	Note that this filter requires the RITK CUDA module!
 */
template<class TInput, class TMaskImage, class TOutput=TInput>
class CUDASeparableNormalizedConvolutionImageFilter : public itk::ImageToImageFilter<TInput,TOutput>
{
public:
	/** @name	Typedefs */
	//@{

	/** @name	Standard typedefs */
	//@{
	typedef CUDASeparableNormalizedConvolutionImageFilter	Self;
	typedef itk::ImageToImageFilter<TInput,TOutput>			Superclass;
	typedef itk::SmartPointer<Self>							Pointer;
	typedef itk::SmartPointer<const Self>					ConstPointer;
	typedef itk::DataObject::Pointer						DataObjectPointer;
	//@}

	/**	@name	Image typedefs */
	//@{
	typedef typename Superclass::InputImageType		InputImageType;
	typedef typename InputImageType::Pointer		InputImagePointer;
	typedef typename InputImageType::ConstPointer	InputImageConstPointer;
	typedef typename Superclass::OutputImageType	OutputImageType;
	typedef typename OutputImageType::Pointer		OutputImagePointer;
	typedef TMaskImage								MaskImageType;
	typedef typename MaskImageType::Pointer			MaskImagePointer;
	typedef typename MaskImageType::ConstPointer	MaskImageConstPointer;
	//@}

	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(CUDASeparableNormalizedConvolutionImageFilter, itk::ImageToImageFilter);

	/**	@name Set/get the mask image */
	//@{
	itkSetInputMacro(MaskImage, MaskImageType, 2);
	itkGetInputMacro(MaskImage, MaskImageType, 2);
	//@}

	/**	@name Access the output mask */
	//@{
	MaskImagePointer GetMaskImageOutput();
	MaskImageConstPointer GetMaskImageOutput() const;
	//@}

	/**	@name Set/get the sigma(variance) */
	//@{
	void SetSigma(double Sigma);
	double GetSigma() const;
	//@}

	/**	@name Set/get the kernel size */
	//@{
	void SetKernelSize(int Size);
	int GetKernelSize();
	//@}


protected:
	/// Constructor
	CUDASeparableNormalizedConvolutionImageFilter();
	/// Destructor
	virtual ~CUDASeparableNormalizedConvolutionImageFilter();

	/// Creates the itk::ProcessObject's output for the mask image
	virtual DataObjectPointer MakeOutput(unsigned int idx);

	/// Data generation
	void GenerateData();

	/// Allocate CUDA memory
	void AllocateCudaMemory();

	/// CUDA Precomputed gaussian
	CudaMethodMacro(CUDASeparableNormalizedConvolutionImageFilter, ComputeGaussianKernel);

	/// The actual filtering method
	CudaMethodMacro(CUDASeparableNormalizedConvolutionImageFilter, DoFiltering);


protected:
	/// Generic mutex
	itk::SimpleFastMutexLock m_Mutex;

	/// Variance of the gaussian
	double m_Sigma;
	/// Kernel size of the gaussian
	int m_KernelSize;

	/**	@name CUDA memory for input/mask and output*/
	//@{
	typename InputImageType::SizeType m_CurrentSize;
	typedef typename ritk::CudaPitchedMemoryImportImageContainer<typename OutputImageType::PixelContainer::ElementIdentifier, typename OutputImageType::PixelContainer::Element>	ImageDataContainerType;
	typedef typename ritk::CudaPitchedMemoryImportImageContainer<typename MaskImageType::PixelContainer::ElementIdentifier, typename MaskImageType::PixelContainer::Element>		MaskDataContainerType;
	typename ImageDataContainerType::Pointer m_InputImageDataContainer;
	typename ImageDataContainerType::Pointer m_OutputImageDataContainer;
	typename MaskDataContainerType::Pointer m_InputMaskDataContainer;
	typename MaskDataContainerType::Pointer m_OutputMaskDataContainer;
	SeparableNormalizedConvolutionPlan *m_Plan;
	//@}

	/**	@name CUDA memory and parameters for the precomputed gaussian */
	//@{
	typedef ritk::CudaRegularMemoryImportImageContainerF KernelContainerType;
	KernelContainerType::Pointer m_KernelContainer;
	//@}

private:
	/// purposely not implemented
	CUDASeparableNormalizedConvolutionImageFilter(Self&); 
	/// purposely not implemented
	void operator=(const Self&);

	/// The output index for the mask image
	unsigned int m_MaskImageOutputIdx;
};

/// Explicit template instantiation
typedef CUDASeparableNormalizedConvolutionImageFilter<itk::Image<float,2>, itk::Image<unsigned char,2>, itk::Image<float,2> > CUDASeparableNormalizedConvolutionImageFilterF2;

#endif // CUDASEPARABLENORMALIZEDCONVOLUTIONIMAGEFILTER_H__
