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

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

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

#include "GradientMagnitude.h"

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_MG;
	/*Device Variables*/
	uchar3 *Image_dev;
	int3 *ImageDx_dev;
	int3 *ImageDy_dev;
	float *ImageMG_dev;

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

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

	/*Size of Image*/
	imageW=frame_Original.cols;
	imageH=frame_Original.rows;
	size_t size=imageW*imageH*sizeof(uchar3);
	size_t sizei=imageW*imageH*sizeof(int3);
	size_t sizef=imageW*imageH*sizeof(float);

	/*Create host memory*/
	frame_MG.create(imageH,imageW,CV_32FC(1));

	/*Create device memory*/
	cudaMalloc((void **)&Image_dev,size);
	cudaMalloc((void **)&ImageDx_dev,sizei);
	cudaMalloc((void **)&ImageDy_dev,sizei);
	cudaMalloc((void **)&ImageMG_dev,sizef);

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

	/*Define the size of the grid and thread blocks*/
	dim3 threads(512,1,1);
	int N=imageW * imageH;
	dim3 grid(N/threads.x + (N%threads.x == 0 ? 0:1),1,1);

	/*Launch the Kernel Functions*/
	CUDA_Dx(ImageDx_dev,Image_dev,N,imageW,grid,threads);
	CUDA_Dy(ImageDy_dev,Image_dev,N,imageW,grid,threads);
	CUDA_MG(ImageMG_dev,ImageDx_dev,ImageDy_dev,N,grid,threads);

	/*Copy Memory (Device-->Host)*/
	cudaMemcpy(frame_MG.data,ImageMG_dev,sizef,cudaMemcpyDeviceToHost);

	cv::normalize(frame_MG,frame_MG,255,0);
	cv::imshow("Original Frame",frame_Original);
	cv::imshow("GradientMagnitude Frame",frame_MG);

	cv::waitKey(0);

	/*Clean Memory*/
	/*Host*/
	cv::destroyWindow("Original Frame");
	cv::destroyWindow("GradientMagnitude Frame");
	
	/*Device*/
	cudaFree(Image_dev);
	cudaFree(ImageDx_dev);
	cudaFree(ImageDy_dev);
	cudaFree(ImageMG_dev);

	return(0);
}
