/*
 * Copyright (C) 2010-2022 TunaCode Pvt. Ltd.  All rights reserved.
 *
 * NOTICE TO USER:
 *
 *
 * TUNACODE MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
 * CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
 * WARRANTY OF ANY KIND.  TUNACODE DISCLAIMS ALL WARRANTIES WITH REGARD TO`
 * THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY,
 * NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL
 * TUNACODE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
 * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS,  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION,  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOURCE CODE.
 * 
 * 
 * USAGE:
 * 
 * This file servers as a reference on usage of most functionalities in CUVI. 
 * Toggle Comments for testing the Required Functionality
 * 
 * 
 * Input: Reads 4 input images from path..\datasets\oneTest
 * Output: Each function outputs to the same folder
 * 
 * Output of one function can be the input of next function if it statifies the supported input type(s)
 * 
 * Specialized Input: Some functions take special input which are located in ..\datasets\ folder
 * 
 */


#include <cuvi.h>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string> 
#include <array>
#include <algorithm>

using namespace std;



CuviStatus abs(CuviImage& input, CuviImage& output) {
	//abs
	CuviStatus status = cuvi::arithmeticLogical::abs(input, output);
	return status;
}


CuviStatus absDiff(CuviImage& input, CuviImage& input2, CuviImage& output) {
	//absDiff
	CuviStatus status = cuvi::arithmeticLogical::absDiff(input, input2, output);
	return status;
}


CuviStatus add(CuviImage& input, CuviImage& input2, CuviImage& output) {
	//add
	CuviStatus status = cuvi::arithmeticLogical::add(input, input2, output);
	return status;
}


CuviStatus AND(CuviImage& input, CuviImage& input2, CuviImage& output) {
	//AND
	CuviStatus status = cuvi::arithmeticLogical::AND(input, input2, output);
	return status;
}


CuviStatus cbrt(CuviImage& input, CuviImage& output) {
	//cbrt
	CuviStatus status = cuvi::arithmeticLogical::cbrt(input, output);
	return status;
}

CuviStatus ceil(CuviImage& input,  CuviImage& output) {
	//ceil
	CuviStatus status = cuvi::arithmeticLogical::ceil(input, output);
	return status;
}


CuviStatus divide(CuviImage& input, CuviImage& input2, CuviImage& output) {
	//divide
	CuviStatus status = cuvi::arithmeticLogical::divide(input, input2, output);
	return status;
}


CuviStatus exp(CuviImage& input, CuviImage& output) {
	//exp
	CuviStatus status = cuvi::arithmeticLogical::exp(input, output);
	return status;
}

CuviStatus floor(CuviImage& input, CuviImage& output) {
	//floor
	CuviStatus status = cuvi::arithmeticLogical::floor(input, output);
	return status;
}


CuviStatus invert(CuviImage& input, CuviImage& output) {
	//invert
	CuviStatus status = cuvi::arithmeticLogical::invert(input, output);
	return status;
}





CuviStatus adjust(CuviImage& input, CuviImage& output) {
	//adjust Parameters:
	output = input; // The function works inplace
	CuviScalar low_in = { 0.0,0.0,0.0 };
	CuviScalar low_out = { 0.0,0.0,0.0 };
	CuviScalar high_in = { 0.9,0.9,0.9 };
	CuviScalar high_out = { 1.0,1.0,1.0 };
	//adjust
	CuviStatus status = cuvi::colorOperations::adjust(output,low_in,high_in,low_out,high_out);
	return status;
}


CuviStatus autoColor(CuviImage& input, CuviImage& output) {
	//autoColor
	CuviStatus status = cuvi::colorOperations::autoColor(input, output);
	return status;
}

CuviStatus borderMask(CuviImage& input, CuviImage& output) {
	//borderMask Parameters
	const Cuvi32s top = 50, bottom = 50, left = 50, right = 200;
	Cuvi32f mask[3] = { 244,144,192 }; //BGR
	//borderMask
	CuviStatus status = cuvi::colorOperations::borderMask(input, output, top,bottom,left,right,mask);
	return status;
}


CuviStatus channelMix(CuviImage& input, CuviImage& output) {
	//channelMix Parameters
	float coeffs[12] = {
					 1.05, -0.025f, -0.025f, 0.0f,
					 -0.45f, 1.975f, -0.525f, 0.0f,
					 0.225f, -1.05f, 1.825f, 0.0f
	};
	//channelMix
	CuviStatus status = cuvi::colorOperations::channelMix(input, output, coeffs);
	return status;
}


CuviStatus channelSplit(CuviImage& input, CuviImage& red, CuviImage& green, CuviImage& blue) {
	//channelSplit
	CuviStatus status = cuvi::colorOperations::channelSplit(input, red, green, blue);
	return status;
}



CuviStatus channelMerge(CuviImage& red, CuviImage& green, CuviImage& blue, CuviImage& output) {
	//channelMerge
	CuviStatus status = cuvi::colorOperations::channelMerge(red, green, blue, output);
	return status;
}


CuviStatus colorPick(CuviImage& input, CuviImage& output) {
	//colorPick Parameters
	CuviColor color = CuviColor::CUVI_COLOR_BLUE;
	Cuvi32f threshold = 50.0f;

	//colorPick
	CuviStatus status = cuvi::colorOperations::colorPick(input, output, color, threshold);
	return status;
}



CuviStatus dehaze(CuviImage& input, CuviImage& output) {
	//dehaze Parameters
	int max0 = 255, max1 = 255, max2 = 255; 

	//dehaze
	CuviStatus status = cuvi::colorOperations::dehaze(input, output, max0, max1, max2);
	return status;
}


CuviStatus gammaCorrect(CuviImage& input, CuviImage& output) {
	//gammaCorrect Parameters
	Cuvi32f gamma = 1.65f;

	//gammaCorrect
	CuviStatus status = cuvi::colorOperations::gammaCorrect(input, output, gamma);
	return status;
}



CuviStatus gray2rgb(CuviImage& input, CuviImage& output) {
	//gray2rgb
	CuviStatus status = cuvi::colorOperations::gray2rgb(input, output);
	return status;
}



CuviStatus histEq(CuviImage& input, CuviImage& output) {
	//histEq
	CuviStatus status = cuvi::colorOperations::histEq(input, output);
	return status;
}


CuviStatus rgb2hsv(CuviImage& input, CuviImage& output) {
	//rgb2hsv
	CuviStatus status = cuvi::colorOperations::rgb2hsv(input, output);
	return status;
}

CuviStatus hsv2rgb(CuviImage& input, CuviImage& output) {
	//hsv2rgb
	CuviStatus status = cuvi::colorOperations::hsv2rgb(input, output);
	return status;
}


CuviStatus imageBinary(CuviImage& input, CuviImage& output) {
	//imageBinary parameters
	Cuvi32f threshold = 0.35f;
	//imageBinary
	CuviStatus status = cuvi::colorOperations::imageBinary(input, output, threshold);
	return status;
}



CuviStatus rgb2Lab(CuviImage& input, CuviImage& output) {
	//rgb2Lab
	CuviStatus status = cuvi::colorOperations::rgb2Lab(input, output);
	return status;
}

CuviStatus Lab2rgb(CuviImage& input, CuviImage& output) {
	//Lab2rgb
	CuviStatus status = cuvi::colorOperations::Lab2rgb(input, output);
	return status;
}


CuviStatus logTransform(CuviImage& input, CuviImage& output) {
	//logTransform parameters
	Cuvi32f c = 1.95f;
	//logTransform
	CuviStatus status = cuvi::colorOperations::logTransform(input, output);
	return status;
}


CuviStatus lowlight(CuviImage& input, CuviImage& output) {
	//lowlight
	CuviStatus status = cuvi::colorOperations::lowlight(input, output);
	return status;
}


CuviStatus LUT(CuviImage& input, CuviImage& output) {
	//LUT Parameters
	const int mappingSize = 256;
	unsigned char mappingValues[mappingSize];
	//Initialize LUT with values which invert the image values
	for (int i = 0; i < mappingSize; i++)
		mappingValues[i] = 255 - i;
	//Create and upload LUT matrix on device
	CuviImage mapping(mappingSize, 1, CUVI_8UC1);
	mapping.upload(mappingValues);
	//LUT
	CuviStatus status = cuvi::colorOperations::LUT(input, mapping, output);
	return status;
}


CuviStatus rgb2gray(CuviImage& input, CuviImage& output) {
	//rgb2gray
	CuviStatus status = cuvi::colorOperations::rgb2gray(input, output);
	return status;
}




CuviStatus rgb2ycbcr(CuviImage& input, CuviImage& output) {
	//rgb2ycbcr
	CuviStatus status = cuvi::colorOperations::rgb2ycbcr(input, output);
	return status;
}

CuviStatus ycbcr2rgb(CuviImage& input, CuviImage& output) {
	//ycbcr2rgb
	CuviStatus status = cuvi::colorOperations::ycbcr2rgb(input, output);
	return status;
}




CuviStatus rgb2yuv(CuviImage& input, CuviImage& output) {
	//rgb2yuv
	CuviStatus status = cuvi::colorOperations::rgb2yuv(input, output);
	return status;
}

CuviStatus yuv2rgb(CuviImage& input, CuviImage& output) {
	//yuv2rgb
	CuviStatus status = cuvi::colorOperations::yuv2rgb(input, output);
	return status;
}


CuviStatus blackGammaLUT(CuviImage& input, CuviImage& output) {
	//blackGammaLUT Parameters
	const int mappingSize = 256;
	Cuvi16u redLUT[mappingSize], greenLUT[mappingSize], blueLUT[mappingSize];
	for (int i = 0; i < mappingSize; i++) {
		redLUT[i] = 255 - i;
		greenLUT[i] =  i;
		blueLUT[i] =  i;
	}
	//blackGammaLUT
	CuviStatus status = cuvi::colorOperations::blackGammaLUT(input, output, redLUT, greenLUT, blueLUT);
	return status;
}



CuviStatus rgb2yuv422(CuviImage& input, CuviImage& output) {
	//rgb2yuv422
	CuviStatus status = cuvi::colorOperations::rgb2yuv422(input, output);
	return status;
}

CuviStatus YUV422TOV210(CuviImage& input,  CuviImage& output) {
	//YUV422TOV210
	CuviStatus status = cuvi::colorOperations::YUV422TOV210(input, output);
	return status;
}


CuviStatus V210TOYUV444(CuviImage& input,  CuviImage& output) {
	//V210TOYUV444
	CuviStatus status = cuvi::colorOperations::V210TOYUV444(input, output);
	return status;
}

CuviStatus YUV444TOV210(CuviImage& input, CuviImage& output) {
	//YUV444TOV210
	CuviStatus status = cuvi::colorOperations::YUV444TOV210(input, output);
	return status;
}


CuviStatus bitConversion(CuviImage& input, CuviImage& output) {
	//bitConversion Parameters:
	CuviStatus status = output.create(input.width(), input.height(), CuviType::CUVI_16UC3);
	input.setDataBits(8);
	output.setDataBits(15);
	if (status != CUVI_SUCCESS) return status;
	//bitConversion
	 status = cuvi::dataExchange::bitConversion(input, output);
	return status;
}


CuviStatus convertScale(CuviImage& input, CuviImage& output) {
	//convertScale Parameters:
	CuviStatus status = output.create(input.width(), input.height(), CuviType::CUVI_16UC3);
	Cuvi32f scale = 127.0f;
	Cuvi32f offset = 15000.0f;
	if (status != CUVI_SUCCESS) return status;
	//convertScale
	status = cuvi::dataExchange::convertScale(input, output, scale, offset);
	return status;
}


CuviStatus getChannel(CuviImage& input, CuviImage& output) {
	//getChannel Parameter
	Cuvi32s channel= 2; //0,1,2 for BGR
	//getChannel
	CuviStatus status = cuvi::dataExchange::getChannel(input, output, channel);
	return status;
}


CuviStatus padImage(CuviImage& input, CuviImage& output) {
	//padImage Parameter
	Cuvi32s top = 50, bottom = 50, left = 100, right = 100;
	Cuvi32f values[] = {33.0f,33.0f,33.0f};
	//padImage
	CuviStatus status = cuvi::dataExchange::padImage(input, output, top,bottom,left,right,values);
	return status;
}


CuviStatus rectangle(CuviImage& input, CuviImage& output) {
	//rectangle Parameter
	output = input;
	CuviRect rect(10, 10, 100, 100);
	CuviScalar color(0, 0, 255);
	//rectangle
	CuviStatus status = cuvi::dataExchange::rectangle(output, rect, color);
	return status;
}


CuviStatus threshold(CuviImage& input, CuviImage& output) {
	//threshold Parameter
	CuviScalar minThresh(10, 20, 20);
	CuviScalar maxThresh(100, 200, 150);
	//threshold
	CuviStatus status = cuvi::dataExchange::threshold(input, output, minThresh, maxThresh);
	return status;
}


CuviStatus crop(CuviImage& input, CuviImage& output) {
	//Crop Parameters:
	const Cuvi32s top = 50, bottom = 50, left = 50, right = 200;
	//Crop
	CuviStatus status = cuvi::geometryTransforms::crop(input, output, top, bottom, left, right);
	return status;
}

CuviStatus flipImage(CuviImage& input, CuviImage& output) {
	//Crop Parameters:
	CuviFlipType type = CuviFlipType::CUVI_FLIP_LEFT_RIGHT;
	//Crop
	CuviStatus status = cuvi::geometryTransforms::flipImage(input, output, type);
	return status;
}

CuviStatus resize(CuviImage& input, CuviImage& output) {
	//Crop Parameters:
	CuviInterpolationType type = CuviInterpolationType::CUVI_INTER_LINEAR;
	//Crop
	CuviStatus status = cuvi::geometryTransforms::resize(input, output, type);
	return status;
}


CuviStatus rotate(CuviImage& input, CuviImage& output) {
	//Rotate Parameters:
	CuviPoint2D<int> anchor(0, 0);
	//Rotate
	CuviStatus status = cuvi::geometryTransforms::rotate(input, output, 3.76, anchor);
	return status;
}

CuviStatus rotateNoCrop(CuviImage& input, CuviImage& output) {
	//Rotate
	CuviStatus status = cuvi::geometryTransforms::rotateNoCrop(input, output, -3.76);
	return status;
}

CuviStatus taper(CuviImage& input, CuviImage& output) {
	//Taper Parameters:
	const Cuvi32s left = 50, right = 200, top = 50, bottom = 50;
	//taper
	CuviStatus status = cuvi::geometryTransforms::taper(input, output,left, right, top, bottom);
	return status;
}

CuviStatus transpose(CuviImage& input, CuviImage& output) {
	//transpose
	CuviStatus status = cuvi::geometryTransforms::transpose(input, output);
	return status;
}


CuviStatus warpAffine(CuviImage& input, CuviImage& output) {
	//warpAffine transformation matrix
	Cuvi64f coeffs[2][3] = {
							 {1.5, 0.1, 0.0},
							 {0.0, 0.9, .2}
	};
	//warpAffine
	CuviStatus status = cuvi::geometryTransforms::warpAffine(input, output,coeffs);
	return status;
}

CuviStatus warpAffineBack(CuviImage& input, CuviImage& output) {
	//warpAffineBack transformation matrix
	Cuvi64f coeffs[2][3] = {
							 {1.5, 0.1, 0.0},
							 {0.0, 0.9, .2}
	};
	//warpAffineBack
	CuviStatus status = cuvi::geometryTransforms::warpAffineBack(input, output, coeffs);
	return status;
}


CuviStatus warpPerspective(CuviImage& input, CuviImage& output) {
	//Set warpPerspective  matrix
	Cuvi64f wp_coeffs[3][3] =
	{
		{ 1, 0, 0.1},
		{ 0.1, 1, 0.2},
		{0, 0, 1}
	};
	//warpAffineBack
	CuviStatus status = cuvi::geometryTransforms::warpPerspective(input, output, wp_coeffs);
	return status;
}


CuviStatus warpPerspectiveBack(CuviImage& input, CuviImage& output) {
	//Set warpPerspectiveBack  matrix
	Cuvi64f wp_coeffs[3][3] =
	{
		{ 1, 0, 0.1},
		{ 0.1, 1, 0.2},
		{0, 0, 1}
	};
	//warpPerspectiveBack
	CuviStatus status = cuvi::geometryTransforms::warpPerspectiveBack(input, output, wp_coeffs);
	return status;
}


CuviStatus imageFilter(CuviImage& input, CuviImage& output) {
	//Filter - Average
	Cuvi32f coeffs[9] = {
					  1 / 9.0f, 1 / 9.0f, 1 / 9.0f,
					  1 / 9.0f, 1 / 9.0f, 1 / 9.0f,
					  1 / 9.0f, 1 / 9.0f, 1 / 9.0f,
	};
	CuviFilter Average(3, 3, coeffs);

	//Filter - Sharp
	float ls_coefs[] = {
				0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
				0.0f, -2.0f / 16, -1.0f / 16, -1.0f / 16, -2.0f / 16,
				0.0f, -1.0f / 16, 1.0f, 5.0f / 16, -1.0f / 16,
				0.0f, -1.0f / 16, 5.0f / 16, 6.0f / 16, -1.0f / 16,
				0.0f, -2.0f / 16, -1.0f / 16, -1.0f / 16, -2.0f / 16
			};
	CuviFilter LumaSharpMat(5, 5, ls_coefs);        //    5x5 Filter for Luma Sharpening



	//imageFilter
	CuviStatus status = cuvi::imageFiltering::imageFilter(input, output, LumaSharpMat);
	return status;
}


CuviStatus imageGradients(CuviImage& input, CuviImage& gradX, CuviImage& gradY) {
	//imageGradients
	CuviStatus status = cuvi::imageFiltering::imageGradients(input, gradX, gradY, CuviGradientKernelType::CUVI_GRADIENT_SCHARR_3x3);
	return status;
}


CuviStatus maxFilter(CuviImage& input, CuviImage& output) {
	//maxFilter Parameters
	CuviRect roi(0, 0, input.width(), input.height());
	CuviSize  fSize(5, 5);

	//maxFilter
	CuviStatus status = cuvi::imageFiltering::maxFilter(input, output, roi, fSize);
	return status;
}


CuviStatus minFilter(CuviImage& input, CuviImage& output) {
	//minFilter Parameters
	CuviRect roi(0, 0, input.width(), input.height());
	CuviSize  fSize(3, 3);

	//minFilter
	CuviStatus status = cuvi::imageFiltering::minFilter(input, output, roi, fSize);
	return status;
}

CuviStatus medianFilter(CuviImage& input, CuviImage& output) {
	//medianFilter Parameters
	CuviRect roi(0, 0, input.width(), input.height());
	CuviSize  fSize(3, 3);

	//medianFilter
	CuviStatus status = cuvi::imageFiltering::medianFilter(input, output, roi, fSize);
	return status;
}


CuviStatus underwaterFilter(CuviImage& input, CuviImage& output) {
	//underwaterFilter Parameters
	CuviEnhancementParams p;
		p.autoColor = true;
		p.filterStrength = 2;
		p.deGalreAmount =  0.657;

	//medianFilter
	CuviStatus status = cuvi::imageFiltering::underwaterFilter(input, output, p);
	return status;
}


CuviStatus calcHist(CuviImage& input) {
	//calcHist
	CuviHistogram histogram(input.type());
	CuviStatus status = cuvi::imageStatistics::calcHist(input, histogram);
	if (status != CUVI_SUCCESS)	return status;

	else {
		cout << "Bin Count: " << histogram.binCount() << endl;
		for (int i = 0; i < histogram.binCount() / input.channels(); i++)
		{
			cout << i << ": ( ";
			for (int c = 0; c < input.channels(); c++)
				cout << histogram.hist()[i + (c * 256)] << " ";
			cout << ")" << endl;
		}
	}

	return status;
}



CuviStatus countInRange(CuviImage& input) {
	//countInRange Parameters
	CuviScalar count(0.0,0.0,0.0);
	const CuviScalar lowerBound(25.0, 10.0, 10.0);
	const CuviScalar upperBound(255.0, 200.0, 150.0);
	
	//countInRange
	CuviStatus status = cuvi::imageStatistics::countInRange(input, count, lowerBound, upperBound);
	if (status != CUVI_SUCCESS)	return status;

	else 
		for (int i = 0; i < input.channels(); i++)
			cout << "Values In Range = " << count.vals()[i] << endl;
	return status;
}


CuviStatus max(CuviImage& input) {
	//max Parameters
	CuviScalar maxs(0.0, 0.0, 0.0);


	//max
	CuviStatus status = cuvi::imageStatistics::max(input, maxs);
	if (status != CUVI_SUCCESS)	return status;

	else
		for (int i = 0; i < input.channels(); i++)
			cout << "Max Value of Channel " <<i+1<<" = " << maxs.vals()[i] << endl;
	return status;
}


CuviStatus mean(CuviImage& input) {
	//mean Parameters
	CuviScalar means(0.0, 0.0, 0.0);


	//mean
	CuviStatus status = cuvi::imageStatistics::mean(input, means);
	if (status != CUVI_SUCCESS)	return status;

	else
		for (int i = 0; i < input.channels(); i++)
			cout << "Mean Value of Channel " << i + 1 << " = " << means.vals()[i] << endl;
	return status;
}



CuviStatus meanStdDev(CuviImage& input) {
	//meanStdDev Parameters
	CuviScalar means(0.0, 0.0, 0.0);
	CuviScalar stdDevs(0.0, 0.0, 0.0);


	//meanStdDev
	CuviStatus status = cuvi::imageStatistics::meanStdDev(input, means, stdDevs);
	if (status != CUVI_SUCCESS)	return status;

	else
		for (int i = 0; i < input.channels(); i++) {
			cout << "Mean of Channel " << i + 1 << " = " << means.vals()[i];
			cout << " Standard Deviation of Channel " << i + 1 << " = " << stdDevs.vals()[i] << endl;
		}
	return status;
}


CuviStatus min(CuviImage& input) {
	//min Parameters
	CuviScalar mins(0.0, 0.0, 0.0);


	//min
	CuviStatus status = cuvi::imageStatistics::min(input, mins);
	if (status != CUVI_SUCCESS)	return status;

	else
		for (int i = 0; i < input.channels(); i++)
			cout << "Min Value of Channel " << i + 1 << " = " << mins.vals()[i] << endl;
	return status;
}


CuviStatus minMax(CuviImage& input) {
	//minMax Parameters
	CuviScalar mins(0.0, 0.0, 0.0);
	CuviScalar maxs(0.0, 0.0, 0.0);


	//minMax
	CuviStatus status = cuvi::imageStatistics::minMax(input, mins, maxs);
	if (status != CUVI_SUCCESS)	return status;

	else
		for (int i = 0; i < input.channels(); i++) {
			cout << "Min Value of Channel " << i + 1 << " = " << mins.vals()[i];
			cout << " Max Value of Channel " << i + 1 << " = " << maxs.vals()[i] << endl;
		}
	return status;
}



CuviStatus sum(CuviImage& input) {
	//sum Parameters
	CuviScalar sums(0.0, 0.0, 0.0);


	//sum
	CuviStatus status = cuvi::imageStatistics::sum(input, sums);
	if (status != CUVI_SUCCESS)	return status;

	else
		for (int i = 0; i < input.channels(); i++)
			cout << "Sum of Values of Channel " << i + 1 << " = " << sums.vals()[i] << endl;
	return status;
}



CuviStatus haarFwd(CuviImage& input, CuviImage& approx, CuviImage& detailX, CuviImage& detailY, CuviImage& detailXY) {
	//haarFwd
	CuviStatus status = cuvi::imageTransforms::haarFwd(input, approx, detailX, detailY, detailXY);
	return status;
}


CuviStatus haarInv(CuviImage& approx, CuviImage& detailX, CuviImage& detailY, CuviImage& detailXY, CuviImage& output) {
	//haarInv
	CuviStatus status = cuvi::imageTransforms::haarInv(approx, detailX, detailY, detailXY, output);
	return status;
}




int main()
{

	Cuvi32s device = cuvi::device::getCurentDevice();
	if (device < 0) {
		cout << "Error: None or Unsupported CUDA Device Found. Check Drivers!" << endl;
		system("pause");
		return 0;
	}

	CuviImage p720, p7202, p1080, k4, k8, specializedInput;
	CuviImage result, result2, result3, result4, result5;
	CuviStatus status; 

	status = p720.create("datasets/oneTest/720p.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);

	status = p7202.create("datasets/oneTest/720p.jpg", CUVI_LOAD_IMAGE_GRAYSCALE);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);

	status = p1080.create("datasets/oneTest/1080p.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);

	status = k4.create("datasets/oneTest/4k.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);

	status = k8.create("datasets/oneTest/8k.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);

	



	///////////////   Arithmetic& Logical ///////////////


	/*//absDiff
	status = absDiff(k8, k8, result); if (status != CUVI_SUCCESS)	printf("\nabsDiff Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/absDiff.jpg");
	*/

	
	/*//abs
	status = abs(p720, result); if (status != CUVI_SUCCESS)	printf("\nabs Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/abs.jpg");
	*/

	/*//add
	status = add(k8, k8, result); if (status != CUVI_SUCCESS)	printf("\nadd Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/add.jpg");
	*/

	/*//AND
	status = AND(k8, k8, result); if (status != CUVI_SUCCESS)	printf("\nAND Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/AND.jpg");
	*/

	/*//cbrt
	status = cbrt(p720, result); if (status != CUVI_SUCCESS)	printf("\ncbrt Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/cbrt.jpg");
	*/

	



	/////////////// Color Operations Transforms //////////////

	/*//adjust
	status = adjust(k8, result); if (status != CUVI_SUCCESS)	printf("\nadjust Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/adjust.jpg");
	*/

	/*//autoColor
	status = autoColor(p720, result); if (status != CUVI_SUCCESS)	printf("\nautoColor Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/autoColor.jpg");
	*/

	/*//borderMask
	status = borderMask(k8, result); if (status != CUVI_SUCCESS)	printf("\nborderMask Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/borderMask.jpg");
	*/

	/*//channelMix
	status = channelMix(p720, result); if (status != CUVI_SUCCESS)	printf("\nchannelMix Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/channelMix.jpg");
	*/

	/*//channelSplit and channelMerge
	status = channelSplit(k8, result, result2, result3); if (status != CUVI_SUCCESS)	printf("\nchannelSplit Error: %d", status); 
	else {
		cuvi::io::saveImage(result, "datasets/oneTest/channelSplitR.jpg");  
		cuvi::io::saveImage(result2, "datasets/oneTest/channelSplitG.jpg");
		cuvi::io::saveImage(result3, "datasets/oneTest/channelSplitB.jpg");
	}
	status = channelMerge(result, result2, result3, result4); if (status != CUVI_SUCCESS)	printf("\nchannelMerge Error: %d", status); else cuvi::io::saveImage(result4, "datasets/oneTest/channelMerge.jpg");
	*/


	/*//colorPick
	status = colorPick(p720, result); if (status != CUVI_SUCCESS)	printf("\ncolorPick Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/colorPick.jpg");
	*/


	/*//dehaze
	status = specializedInput.create("datasets/dehaze.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);
	status = dehaze(specializedInput, result); if (status != CUVI_SUCCESS)	printf("\ndehaze Error: %d", status); else cuvi::io::saveImage(result, "datasets/dehaze_out.jpg");
	*/

	/*//gammaCorrect
	status = gammaCorrect(p720, result); if (status != CUVI_SUCCESS)	printf("\ngammaCorrect Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/gammaCorrect.jpg");
	*/
	
	/*//gray2rgb
	//// IMPORTANT: Set image load flag to CUVI_LOAD_IMAGE_GRAYSCALE otherwise will get an error
	status = gray2rgb(k8, result); if (status != CUVI_SUCCESS)	printf("\ngray2rgb Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/gray2rgb.jpg");
	*/

	/*//histEq
	//// IMPORTANT: Set image load flag to CUVI_LOAD_IMAGE_GRAYSCALE otherwise will get an error
	status = histEq(p720, result); if (status != CUVI_SUCCESS)	printf("\nhistEq Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/histEq.jpg");
	*/

	/*//rgb2hsv and hsv2rgb
	status = rgb2hsv(k8, result); if (status != CUVI_SUCCESS)	printf("\nrgb2hsv Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rgb2hsv.jpg");
	status = hsv2rgb(result, result2); if (status != CUVI_SUCCESS)	printf("\nhsv2rgb Error: %d", status); else cuvi::io::saveImage(result2, "datasets/oneTest/hsv2rgb.jpg");
	*/


	/*//imageBinary
	status = imageBinary(k8, result); if (status != CUVI_SUCCESS)	printf("\nimageBinary Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/imageBinary.jpg");
	*/
	

	/*//rgb2Lab and Lab2rgb
	status = rgb2Lab(p720, result); if (status != CUVI_SUCCESS)	printf("\nrgb2lab Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rgb2Lab.jpg");
	status = Lab2rgb(result, result2); if (status != CUVI_SUCCESS)	printf("\nlab2rgb Error: %d", status); else cuvi::io::saveImage(result2, "datasets/oneTest/Lab2rgb.jpg");
	*/

	/*//logTransform
	status = logTransform(p720, result); if (status != CUVI_SUCCESS)	printf("\nlogTransform Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/logTransform.jpg");
	*/
	

	/*//lowlight
	status = specializedInput.create("datasets/lowlight.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);
	status = lowlight(specializedInput, result); if (status != CUVI_SUCCESS)	printf("\nlowlight Error: %d", status); else cuvi::io::saveImage(result, "datasets/lowlight_out.jpg");
	*/
	
	
	/*//LUT
	status = LUT(k8, result); if (status != CUVI_SUCCESS)	printf("\nLUT Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/LUT.jpg");
	*/
	
	/*//rgb2gray
	status = rgb2gray(p720, result); if (status != CUVI_SUCCESS)	printf("\nrgb2gray Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rgb2gray.jpg");
	*/


	/*//rgb2ycbcr and ycbcr2rgb
	status = rgb2ycbcr(k8, result); if (status != CUVI_SUCCESS)	printf("\nrgb2ycbcr Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rgb2ycbcr.jpg");
	status = ycbcr2rgb(result, result2); if (status != CUVI_SUCCESS)	printf("\nycbcr2rgb Error: %d", status); else cuvi::io::saveImage(result2, "datasets/oneTest/ycbcr2rgb.jpg");
	*/
	
	/*//rgb2yuv and yuv2rgb
	status = rgb2yuv(p720, result); if (status != CUVI_SUCCESS)	printf("\nrgb2yuv Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rgb2yuv.jpg");
	status = yuv2rgb(result, result2); if (status != CUVI_SUCCESS)	printf("\nyuv2rgb Error: %d", status); else cuvi::io::saveImage(result2, "datasets/oneTest/yuv2rgb.jpg");
	*/

	/*//blackGammaLUT
	status = blackGammaLUT(p720, result); if (status != CUVI_SUCCESS)	printf("\nblackGammaLUT Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/blackGammaLUT.jpg");
	*/



	/////////////// Data Exchange /////////////////

	/*//bitConversion
	status = bitConversion(p720,result); if (status != CUVI_SUCCESS)	printf("\nbitConversion Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/bitConversion.png");
	*/

	/*//convertScale
	status = convertScale(p720,result); if (status != CUVI_SUCCESS)	printf("\nconvertScale Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/convertScale.png");
	*/

	/*//getChannel
	//result = k4[1]; //The same can be achieved by using the channel fetch operator
	status = getChannel(k8,result); if (status != CUVI_SUCCESS)	printf("\ngetChannel Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/getChannel.jpg");
	*/
	


	/*//padImage
	status = padImage(p720, result); if (status != CUVI_SUCCESS)	printf("\npadImage Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/padImage.jpg");
	*/


	/*//rectangle
	status = rectangle(k8, result); if (status != CUVI_SUCCESS)	printf("\nrectangle Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rectangle.jpg");
	*/


	/*//threshold
	status = threshold(p720, result); if (status != CUVI_SUCCESS)	printf("\nthreshold Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/threshold.jpg");
	*/














	/////////////// Geometric Transforms //////////////
	
	/*//crop
	status = crop(p720,result); if (status != CUVI_SUCCESS)	printf("\ncrop Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/crop.jpg");
	*/
	
	
	/*//flipImage 
	status = specializedInput.create("datasets/flip.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);
	status = flipImage(specializedInput, result); if (status != CUVI_SUCCESS)	printf("\nflipImage Error: %d", status); else cuvi::io::saveImage(result, "datasets/flipped.jpg");
	*/
	
	/*//resize
	result.create(p720.width()*0.8, p720.height()*0.8, p720.type());
	status = resize(p720, result); if (status != CUVI_SUCCESS)	printf("\nresize Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/resize.jpg");
	*/

	/*//rotate
	status = rotate(p720, result); if (status != CUVI_SUCCESS)	printf("\nrotate Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rotate.jpg");
	*/


	/*//rotateNoCrop
	status = rotateNoCrop(k8, result); if (status != CUVI_SUCCESS)	printf("\nrotateNoCrop Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/rotateNoCrop.jpg");
	*/


	/*//taper
	status = taper(p720, result); if (status != CUVI_SUCCESS)	printf("\ntaper Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/taper.jpg");
	*/

	/*//transpose
	status = transpose(p720, result); if (status != CUVI_SUCCESS)	printf("\ntranspose Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/transpose.jpg");
	*/


	/*//warpAffine
	status = warpAffine(k8, result); if (status != CUVI_SUCCESS)	printf("\nwarpAffine Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/warpAffine.jpg");
	*/
	
	/*//warpAffineBack
	status = warpAffineBack(p720, result); if (status != CUVI_SUCCESS)	printf("\nwarpAffineBack Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/warpAffineBack.jpg");
	*/


	/*//warpPerspective
	status = warpPerspective(k8, result); if (status != CUVI_SUCCESS)	printf("\nwarpPerspective Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/warpPerspective.jpg");
	*/

	/*//warpPerspectiveBack
	status = warpPerspectiveBack(p720, result); if (status != CUVI_SUCCESS)	printf("\nwarpPerspectiveBack Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/warpPerspectiveBack.jpg");
	*/




	//////////////////////////  Image Filtering   /////////////////////////////



	/*//imageFilter
	status = imageFilter(k8, result); if (status != CUVI_SUCCESS)	printf("\nimageFilter Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/imageFilter.jpg");
	*/

	/*//imageGradients
	status = imageGradients(k8, result, result2); if (status != CUVI_SUCCESS)	printf("\nimageGradients Error: %d", status); else { cuvi::io::saveImage(result, "datasets/oneTest/imageGradientX.jpg"); cuvi::io::saveImage(result2, "datasets/oneTest/imageGradientY.jpg"); }
	*/

	/*//maxFilter
	status = maxFilter(p720, result); if (status != CUVI_SUCCESS)	printf("\nmaxFilter Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/maxFilter.jpg");
	*/

	/*//minFilter
	status = minFilter(k8, result); if (status != CUVI_SUCCESS)	printf("\nminFilter Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/minFilter.jpg");
    */

	/*//medianFilter
	status = medianFilter(k8, result); if (status != CUVI_SUCCESS)	printf("\nmedianFilter Error: %d", status); else cuvi::io::saveImage(result, "datasets/oneTest/medianFilter.jpg");
	*/

	/*//underwaterFilter
	status = specializedInput.create("datasets/underwater.jpg", CUVI_LOAD_IMAGE_COLOR);
	if (status != CUVI_SUCCESS)	printf("\nImage load Error: %d", status);
	status = underwaterFilter(specializedInput, result); if (status != CUVI_SUCCESS)	printf("\nunderwaterFilter Error: %d", status); else cuvi::io::saveImage(result, "datasets/underwater_out.jpg");
	*/
	


	//////////////////////////  Image Statistics   /////////////////////////////
	

	/*//calcHist
	status = calcHist(k8); if (status != CUVI_SUCCESS)	printf("\ncalcHist Error: %d", status);
	*/

	/*//countInRange
	status = countInRange(p720); if (status != CUVI_SUCCESS)	printf("\ncountInRange Error: %d", status);
	*/

	/*//max
	status = max(k8); if (status != CUVI_SUCCESS)	printf("\nmax Error: %d", status);
	*/

	/*//mean
	status = mean(p720); if (status != CUVI_SUCCESS)	printf("\nmean Error: %d", status);
	*/

	/*//meanStdDev
	status = meanStdDev(k8); if (status != CUVI_SUCCESS)	printf("\nmeanStdDev Error: %d", status);
	*/
	
	/*//min
	status = min(p720); if (status != CUVI_SUCCESS)	printf("\nmin Error: %d", status);
	*/

	/*//minMax
	status = minMax(k8); if (status != CUVI_SUCCESS)	printf("\nminMax Error: %d", status);
	*/

	/*//sum
	status = sum(p720); if (status != CUVI_SUCCESS)	printf("\nsum Error: %d", status);
	*/



	//////////////////////////  Image Transforms   /////////////////////////////

	/*//haarFwd and haarInv
	status = haarFwd(p720, result, result2, result3, result4); if (status != CUVI_SUCCESS)	printf("\nhaarFwd Error: %d", status);
		else {
			cuvi::io::saveImage(result, "datasets/oneTest/haarFwdApp.jpg");
			cuvi::io::saveImage(result2, "datasets/oneTest/haarFwdDetailX.jpg");
			cuvi::io::saveImage(result3, "datasets/oneTest/haarFwdDetailY.jpg");
			cuvi::io::saveImage(result4, "datasets/oneTest/haarFwdDetailXY.jpg");
		}
	status = haarInv(result, result2, result3, result4, result5); if (status != CUVI_SUCCESS)	printf("\nhaarInv Error: %d", status); else cuvi::io::saveImage(result5, "datasets/oneTest/haarInv.jpg");
	*/

	if (status == CUVI_SUCCESS)	printf("\nProgram successfully executed!\n");
	else	printf("\nCUVI Error: %d\n", status);


	return 0;

	
	
}