java 程式碼實現卷積計算
阿新 • • 發佈:2018-12-01
簡單的寫一下卷積到底是一個什麼計算過程。
假設有一個卷積核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(); } }