// Image_Filters.cpp : Defines the entry point for the console application.
//

/*CUDA*/
#include <cuda_runtime.h>

/*OpenCV*/
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include "ImageFilters.h"

//División techo.
int iDivUp(int a, int b){
    return ((a % b) != 0) ? (a / b + 1) : (a / b);
}

//PARAMETERS
#define BLOCKDIM_X 16
#define BLOCKDIM_Y 16

int main(int argc, char **argv){
	cudaSetDevice(0);
	/*Host Variables*/
	int imageW, imageH;		  //Size of Image
	cv::Mat frame_Original;   //Original Image
	cv::Mat frame_Original4c;
	cv::Mat frame_Original1c;

	/*Device Variables*/
	uchar4 *Image_dev;
	float  *Imagef_dev;

	cv::namedWindow("Original Frame",CV_WINDOW_AUTOSIZE);
	cv::namedWindow("Filtered Frame",CV_WINDOW_AUTOSIZE);

	char name_imag[500];
	/*Load Image*/
	sprintf(name_imag,"../../Images/lena.jpg");
	frame_Original = cv::imread(name_imag,1);

	/*Size of Image*/
	imageW=frame_Original.cols;
	imageH=frame_Original.rows;
	size_t size=imageW*imageH*sizeof(uchar4);
	size_t sizef=imageW*imageH*sizeof(float);
	
	frame_Original4c.create(imageH,imageW,CV_8UC(4));
	cv::cvtColor(frame_Original,frame_Original4c,CV_BGR2BGRA,0);

	frame_Original1c.create(imageH,imageW,CV_32FC(1));

	/*Create device memory*/
	cudaMalloc((void **)&Image_dev,size);
	cudaMalloc((void **)&Imagef_dev,sizef);
	CUDA_CreateMemoryArray(imageW,imageH);

	/*Copy Memory (Host-->Device)*/
	cudaMemcpy(Image_dev,frame_Original4c.data,size,cudaMemcpyHostToDevice);
	
	/*Define the size of the grid and thread blocks*/
	dim3 threads(BLOCKDIM_X, BLOCKDIM_Y,1);
	dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y),1);

	CUDA_MemcpyToArray(Image_dev,imageW,imageH);
	CUDA_BindTextureToArray();

	/*Launch the Kernel Function*/
	//Mean Filter
	CUDA_MeanFilter(Image_dev,imageW,imageH,grid,threads);
	//CUDA_LaplacianFilter(Imagef_dev,imageW,imageH,grid,threads);
	//CUDA_GaussianFilter(Image_dev,imageW,imageH,grid,threads);

	/*Copy Memory (Device-->Host)*/
	cudaMemcpy(frame_Original4c.data,Image_dev,size,cudaMemcpyDeviceToHost);

	//cudaMemcpy(frame_Original1c.data,Imagef_dev,sizef,cudaMemcpyDeviceToHost);
	//cv::normalize(frame_Original1c,frame_Original1c,255,0);

	cv::imshow("Original Frame",frame_Original);
	cv::imshow("Filtered Frame",frame_Original4c);
	//cv::imshow("Filtered Frame",frame_Original1c);
	cv::waitKey(0);

	/*Clean Memory*/
	/*Host*/
	cv::destroyWindow("Original Frame");
	cv::destroyWindow("Filtered Frame");
	/*Device*/
	cudaFree(Image_dev);
	cudaFree(Imagef_dev);
	CUDA_FreeArrays();

	return(0);
}
