1. 程式人生 > >java 程式碼實現卷積計算

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();
	    }
}