java 代码实现卷积计算

简单的写一下卷积到底是一个什么计算过程。

假设有一个卷积核h,就一般为3*3的矩阵:

有一个待处理矩阵x:

h*x的计算过程分为三步

第一步,将卷积核翻转180°,也就是成为了

第二步,将卷积核h的中心对准x的第一个元素,然后对应元素相乘后相加,没有元素的地方补0。

这样结果Y中的第一个元素值Y11=1*0+2*0+1*0+0*0+0*1+0*2+-1*0+-2*5+-1*6=-16

第三步每个元素都像这样计算出来就可以得到一个输出矩阵,就是卷积结果

……………………

像这样计算,其他过程略了。

最后结果

注意:

我这里是用0补全原矩阵的,但我们不一定选择0。在Opencv的cvFilter2D函数中,就没有使用0来补全矩阵,而是用了边缘拷贝的方式,下一篇我会介绍Opencv的CvFilter2D函数卷积运算过程。

根据以上过程,java代码如下

public class test {
	    public double[][] datas;//数据元素
	    public int rows;//行数
	    public int cols;//列数
	    public test(int r, int c){
	        datas = new double[r][c];//创建一个二维数组对象,行和列共同构成一个数据元素
	        this.rows = r;
	        this.cols = c;
	    }
	    //卷积运算
	    public test conv(test Kernel){
	    	int width =Kernel.rows/2;//核函数的1/2宽度
	    	int length=Kernel.cols/2;//核函数的1/2宽度
	        test temp = new test(this.rows+2*width,this.cols+2*length);//构建一个新的矩阵,用于卷积计算————核矩阵为偶数?如何处理
	        //构建一个矩阵,用来进行计算
	        for(int i = width; i<this.rows+width;i++){//矩阵要乘的行数
	            for(int j = length;j<this.cols+length;j++){//每一行要乘的列数
	            	temp.datas[i][j]=datas[i-width][j-length];//构建上下边缘为空的矩阵,上下距离width length
	            }
	        }
	        //循环计算结果矩阵中的值
	        for(int i = width; i<this.rows+width;i++){//矩阵要乘的行数
	        	for(int j = length;j<this.cols+length;j++){//每一行要乘的列数
	                this.datas[i-width][j-length]=mutiKernel(Kernel,temp,i,j,width,length);//计算数值
	            }
	        }
	        return this;
	    }
	    //使用核函数计算结果矩阵中每一个位置的值,
	    public int mutiKernel(test Kernel,test temp,int i,int j,int width,int length) {
	    	int number =0;
	    	 for(int m = 0; m<Kernel.rows;m++){//矩阵要乘的行数
		            for(int n = 0;n<Kernel.cols;n++){//每一行要乘的列数
		            	number+=Kernel.datas[m][n]*temp.datas[i-width+m][j-length+n];//循环计算结果
		            }
		        }	
	    	return number;
	    }
	    public void display(){//打印矩阵                                                                                                                                                                                                
	        if(this == null) return;
	        for(int i = 0;i<this.rows;i++){
	            for(int j = 0;j<this.cols;j++){
	                System.out.print(this.datas[i][j]+"\t");
	            }
	            System.out.println();
	        }

	    } 
	    public test turn(){//翻转矩阵  180度                                                                                                                                                                                             
	        double temp=0;
	        //水平翻转
	        for (int i = 0; i < this.rows / 2; i++) {
	            for (int j = 0; j < this.cols; j++) {
	                temp = this.datas[i][j];
	                this.datas[i][j] = this.datas[this.rows - 1 - i][j];
	                this.datas[this.rows - 1 - i][j] = temp;
	            }
	        }
	        //垂直翻转
	        for (int i = 0; i < this.rows; i++) {
	            for (int j = 0; j < this.cols / 2; j++) {
	                temp = this.datas[i][j];
	                this.datas[i][j] = this.datas[i][this.cols - 1 - j];
	                this.datas[i][this.cols - 1 - j] = temp;
	            }
	        }
	        return this;
	    }
	    public static void main(String[] args) {
	    	//输入数值
	    	System.out.println("第一个矩阵元素。。。");
	        test m = new test(3,3);
	        for(int i = 0; i<3;i++){
	            m.datas[1][i] = 0;
	        }
	        m.datas[0][0]=-1;
	        m.datas[0][1]=-2;
	        m.datas[0][2]=-1;
	        m.datas[2][0]=1;
	        m.datas[2][1]=2;
	        m.datas[2][2]=1;
	        m.display();
	        //核函数翻转
	        m.turn();
	        test m1 = new test(4,4);
	        int count=1;
	        System.out.println("第二个矩阵元素。。。");
	        for(int i = 0; i<4;i++){
	            for(int j = 0; j<4;j++){
	                m1.datas[i][j] = count++;
	            }
	        }
	        m1.display();
	        System.out.println("卷积的结果是: ");
	        //核矩阵 Kernel=m
	        m1.conv(m).display();
	    }
}


 

猜你喜欢

转载自blog.csdn.net/zuokaopuqingnian/article/details/84486522