/*
 *  Brno University of Technology
 *
 *  Copyright (C) 2009-2010 by Brno University of Technology and the contributors
 *
 *  Complete list of developers available at our web site:
 *
 *       http://spl.utko.feec.vutbr.cz
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  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 the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
 */

/*
 * This class contains matrixes that can be used by Convolution Filter.
*/
package cz.vutbr.feec.utko.opencv.operators.imageTransforms;

import Jama.Matrix;

import com.rapidminer.operator.UserError;

public class ConvolutionMatrixes {
	
	//PREDEFINED FILTERS
	//******************************************************
	private static final int SHARPENING_1 = 0;
	private static final int SHARPENING_2 = 1;
	private static final int SHARPENING_3 = 2;
	private static final int SHARPENING_4 = 3;
	private static final int HIGH_BOOST_1 = 4;
	private static final int HIGH_BOOST_2 = 5;
	private static final int LAPLACE_1 = 6;
	private static final int LAPLACE_2 = 7;
	private static final int DIFFERENCE_OF_GAUSSIAN = 8;	
	//******************************************************
	
	//EDGEDETECTION FILTERS
	//******************************************************
	private static final int ROBERTS_HORIZONATAL = 0;
	private static final int ROBERTS_VERTICAL = 1;
	private static final int PREWITT_HORIZONATAL = 2;
	private static final int PREWITT_VERTICAL = 3;
	private static final int SOBEL_HORIZONATAL_1 = 4;
	private static final int SOBEL_VERTICAL_1 = 5;
	private static final int SOBEL_DIAGONAL_1 = 6;
	private static final int SOBEL_ANTIDIAGONAL_1 = 7;
	private static final int SOBEL_HORIZONATAL_2 = 8;
	private static final int SOBEL_VERTICAL_2 = 9;
	private static final int SOBEL_DIAGONAL_2 = 10;
	private static final int SOBEL_ANTIDIAGONAL_2 = 11;
	private static final int KIRSCH = 12;
	private static final int LAPLACIAN_OF_GAUSSIAN_9X9 = 13;
	private static final int LAPLACIAN_OF_GAUSSIAN_5X5 = 14;
	private static final int IMPROVED_SOBEL_HORIZONTAL = 15;
	private static final int IMPROVED_SOBEL_VERTICAL = 16;
	private static final int IMPROVED_SOBEL_DIAGONAL = 17;
	private static final int IMPROVED_SOBEL_ANTIDIAGONAL = 18;
	private static final int DN = 19;
	//******************************************************
	
	public static final String[] Kernels = { 
		"Sharpening 1",
		"Sharpening 2",
		"Sharpening 3",
		"Sharpening 4",
		"High-Boost 1",
		"High-Boost 2",
		"Laplace 1",
		"Laplace 2",
		"Difference of gaussian",
		
		// other gradient methods: http://fourier.eng.hmc.edu/e161/lectures/gradient/gradient.html
	}; 
	
	public static final String[] EdgeDetectionKernels = { 
		"Roberts Horizontal",
		"Roberts Vertical",
		"Prewitt Horizontal",
		"Prewitt Vertical",
		"Sobel Horizontal 1",
		"Sobel Vertical 1",
		"Sobel Diagonal 1",
		"Sobel AntiDiagonal 1",
		"Sobel Horizontal 2",
		"Sobel Vertical 2",
		"Sobel Diagonal 2",
		"Sobel AntiDiagonal 2",
		"Kirsch",
		"Laplacian of Gaussian 9x9",
		"Laplacian of Gaussian 5x5",
		"Improved Sobel Horizontal",
		"Improved Sobel Vertical",
		"Improved Sobel Diagonal",
		"Improved Sobel Anti-Diagonal",
		"DN",
		
		// other gradient methods: http://fourier.eng.hmc.edu/e161/lectures/gradient/gradient.html
	}; 
	
	public static Matrix getKernel(int type, double PARAM_BOOST) throws UserError {
		switch (type) {
		case SHARPENING_1: // sharpening 1
			return new Matrix(new double[][] {
					{0.0, -1.0/6.0, 0.0},
					{-1.0/6.0, 4.0/6.0, -1.0/6.0},
					{0.0, -1.0/6.0, 0.0}}
			);
		case SHARPENING_2: // sharpening 2
			return new Matrix(new double[][] {
					{-1.0/9.0, -1.0/9.0, -1.0/9.0},
					{-1.0/9.0, 8.0/9.0, -1.0/9.0},
					{-1.0/9.0, -1.0/9.0, -1.0/9.0}
			});
		case SHARPENING_3: // sharpening 3
			return new Matrix(new double[][] {
					{-1.0/9.0, -1.0/9.0, -1.0/9.0},
					{-1.0/9.0, 8.0/9.0, -1.0/9.0},
					{-1.0/9.0, -1.0/9.0, -1.0/9.0}
			});
		case SHARPENING_4: // sharpening 4
			return new Matrix(new double[][] {
					{-1.0/16.0, -2.0/16.0, -1.0/16.0},
					{-2.0/16.0, 12.0/16.0, -2.0/16.0},
					{-1.0/16.0, -2.0/16.0, -1.0/16.0}
			});
		case HIGH_BOOST_1: // High boost 1
			return new Matrix(new double[][] {
					{0.0, -1.0, -0.0},
					{-1.0, 4.0+PARAM_BOOST, -1.0},
					{0.0, -1.0, 0.0}
			});
			
		case HIGH_BOOST_2: // High boost 2
			return new Matrix(new double[][] {
					{-1.0,  -1.0, -1.0},
					{-1.0, 8.0+PARAM_BOOST, -1.0},
					{-1.0, -1.0, -1.0}
			});
		case LAPLACE_1: // Laplace 1
			return new Matrix(new double[][] {
					{0.0, 1.0, 0.0},
					{1.0, -4.0, 1.0},
					{0.0, 1.0, 0.0}
			});
			
		case LAPLACE_2: // Laplace 2
			return new Matrix(new double[][] {
					{1.0, 1.0, 1.0},
					{1.0, 8.0, 1.0},
					{1.0, 1.0, 1.0}
			});
		case DIFFERENCE_OF_GAUSSIAN: // Difference of Gaussian
			return new Matrix(new double[][] {
					{1.0, 1.0, 1.0},
					{1.0, 8.0, 1.0},
					{1.0, 1.0, 1.0}
			});
			
		default:
			return null;
		}
	}
	
	public static Matrix getEdgeDetectionKernel(int type) throws UserError {
		switch (type) {
		case ROBERTS_HORIZONATAL:
			return new Matrix(new double[][] {
					{0, 1}, 
					{-1, 0}
			});
		case ROBERTS_VERTICAL:
			return new Matrix(new double[][] {
					{1, 0}, 
					{0, -1}
			});
		case PREWITT_HORIZONATAL:
			return new Matrix(new double[][] {
					{-2, -2, -2, -2, -2},
					{-1, -1, -1, -1, -1},
					{0, 0, 0, 0, 0},
					{1, 1, 1, 1, 1},
					{2, 2, 2, 2, 2}
			});
		case PREWITT_VERTICAL:
			return new Matrix(new double[][] {
					{-2, -1, 0, 1, 2},
					{-2, -1, 0, 1, 2},
					{-2, -1, 0, 1, 2},
					{-2, -1, 0, 1, 2},
					{-2, -1, 0, 1, 2}
			});
		case SOBEL_HORIZONATAL_1:
			return new Matrix(new double[][] {
					{-1.0, -2.0, -1.0},
					{0, 0, 0},
					{1.0, 2.0, 1.0}
			});
		case SOBEL_VERTICAL_1:
			return new Matrix(new double[][] {
					{-1, 0, 1},
					{-2, 0, 2},
					{-1, 0, 1}
			});
		case SOBEL_DIAGONAL_1:
			return new Matrix(new double[][] {
					{0, -1, -2},
					{1, 0, -1},
					{2, 1, 0}
			});
		case SOBEL_ANTIDIAGONAL_1:
			return new Matrix(new double[][] {
					{-2, -1, 0},
					{-1, 0, 1},
					{0, 1, 2}
			});
		case SOBEL_HORIZONATAL_2:
			return new Matrix(new double[][] {
					{1.0, 2.0, 1.0},
					{0, 0, 0},
					{-1.0, -2.0, -1.0}
			});
		case SOBEL_VERTICAL_2:
			return new Matrix(new double[][] {
					{1, 0, -1},
					{2, 0, -2},
					{1, 0, -1}
			});
		case SOBEL_DIAGONAL_2:
			return new Matrix(new double[][] {
					{0, 1, 2},
					{-1, 0, 1},
					{-2, -1, 0}
			});
		case SOBEL_ANTIDIAGONAL_2:
			return new Matrix(new double[][] {
					{2, 1, 0},
					{1, 0, -1},
					{0, -1, -2}
			});
		case KIRSCH:
			return new Matrix(new double[][] {
					{5, 5, 5},
					{-3, 0, -3},
					{-3, -3, -3}
			});
		case LAPLACIAN_OF_GAUSSIAN_9X9: // Laplacian of Gaussian (LoG) 9x9
			return new Matrix(new double[][] {
					{ 0.0, 1.0, 1.0, 2.0, 2.0, 2.0, 1.0, 1.0, 0.0}, 
					{ 1.0, 2.0, 4.0, 5.0, 5.0, 5.0, 4.0, 2.0, 1.0}, 
					{ 1.0, 4.0, 5.0, 3.0, 0.0, 3.0, 5.0, 4.0, 1.0}, 
					{ 2.0, 5.0, 3.0, -12.0, -24.0, -12.0, 3.0, 5.0, 2.0}, 
					{ 2.0, 5.0, 0.0, -24.0, -40.0, -24.0, 0.0, 5.0, 2.0}, 
					{ 2.0, 5.0, 3.0, -12.0, -24.0, -12.0, 3.0, 5.0, 2.0}, 
					{ 1.0, 4.0, 5.0, 3.0, 0.0, 3.0, 5.0, 4.0, 1.0}, 
					{ 1.0, 2.0, 4.0, 5.0, 5.0, 5.0, 4.0, 2.0, 1.0}, 
					{ 0.0, 1.0, 1.0, 2.0, 2.0, 2.0, 1.0, 1.0, 0.0 } });
		case LAPLACIAN_OF_GAUSSIAN_5X5: // Laplacian of Gaussian (LoG) 5x5
			return new Matrix(new double[][] {
					 {0.0, 0.0, 1.0, 0.0, 0.0}, 
					 {0.0, 1.0, 2.0, 1.0, 0.0} ,
					 {1.0, 2.0, -16.0, 2.0, 1.0}, 
					 {0.0, 1.0, 2.0, 1.0, 0.0}, 
					 {0.0, 0.0, 1.0, 0.0, 0.0}, 
			});
		case IMPROVED_SOBEL_HORIZONTAL: 
			return new Matrix(new double[][] {
					{2.0, 3.0, 6.0, 3.0, 2.0},
					{3.0, 4.0, 6.0, 4.0, 3.0},
					{0.0, 0.0, 0.0, 0.0, 0.0},
					{-3.0, -4.0, -6.0, -4.0, -3.0},
					{-2.0, -3.0, -6.0, -3.0, -2.0},
			});
		case IMPROVED_SOBEL_VERTICAL: 
			return new Matrix(new double[][] {
					{2.0, 3.0, 0.0, -3.0, -2.0},
					{3.0, 4.0, 0.0, -4.0, -3.0},
					{6.0, 6.0, 0.0, -6.0, -6.0},
					{3.0, 4.0, 0.0, -4.0, -3.0},
					{2.0, 3.0, 0.0, -3.0, -2.0},
			});
		case IMPROVED_SOBEL_DIAGONAL: 
			return new Matrix(new double[][] {
					{0.0, -2.0, -3.0, -2.0, -6.0},
					{2.0, 0.0, -4.0, -6.0, -2.0},
					{3.0, 4.0, 0.0, -4.0, -3.0},
					{2.0, 6.0, 4.0, 0.0, -2.0},
					{6.0, 2.0, 3.0, 2.0, 0.0},
			});
		case IMPROVED_SOBEL_ANTIDIAGONAL: 
			return new Matrix(new double[][] {
					{-6.0, -2.0, -3.0, -2.0, -0.0},
					{-2.0, -6.0, -4.0, 0.0, 2.0},
					{-3.0, -4.0, 0.0, 4.0, 3.0},
					{-2.0, 0.0, 4.0, 6.0, 2.0},
					{0.0, 2.0, 3.0, 2.0, 6.0},
			});
		case DN: 
			return new Matrix(new double[][] {
					{-2.0, -2.0, -2.0, -2.0, -2.0},
					{-2.0, -3.0, -3.0, -3.0, -2.0},
					{-2.0, -3.0, 53.0, -1.0, -2.0},
					{-2.0, -3.0, -3.0, -3.0, -2.0},
					{-2.0, -2.0, -2.0, -2.0, -2.0},
			});
			
		default:
			return null;
		}
	}

}
