├── .gitignore ├── LICENSE ├── README.md ├── src ├── ndArray │ ├── Filters.java │ ├── Lab.java │ ├── NdCommonMathFunc.java │ ├── NdImageIO.java │ ├── NdImagePro.java │ ├── NdMath.java │ └── NdUtils.java ├── ndCommon │ ├── CommonMisc.java │ ├── DoubleArrayIndexComparator.java │ └── StringArrayIndexComparator.java └── tests │ ├── testCommonMath.java │ ├── testFilters.java │ ├── testIO.java │ ├── testMatrix.java │ └── testStraighten.java └── test.jpeg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mingxiang Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | J4darrays offers comprehensive mathematical functions, random number generators, linear algebra routines, Fourier transforms, and more. It is also a powerful tool to perform n-dimensional array computations such as convolution, matrix multiplication and so on. 4 | 5 | ## Quick Start 6 | -------------------------------------------------------------------------------- /src/ndArray/Filters.java: -------------------------------------------------------------------------------- 1 | package ndArray; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class Filters { 6 | public Filters() {} 7 | 8 | public static double[][] averaging2d(int size) { 9 | double[][] result = new double[size][size]; 10 | double value = 1.0/(size*size); 11 | for (int i = 0; i < size; i++) { 12 | for (int j = 0; j < size; j++) { 13 | result[i][j] = value; 14 | } 15 | } 16 | return result; 17 | } 18 | 19 | public static double[] gaussian1d(int size, double sigma) { 20 | double[] y = new double[size*2+1]; 21 | double _sum = 0; 22 | for (int i = 0; i < y.length; i++) { 23 | double x = i-size; 24 | y[i] = Math.exp(- x * x / (2 * sigma * sigma)); 25 | _sum += y[i]; 26 | } 27 | for (int i = 0; i < y.length; i++) { 28 | y[i] /= _sum; 29 | } 30 | return y; 31 | } 32 | 33 | public static double[][] gaussian2d(int size, double sigma) { 34 | double[][] y = new double[size*2+1][size*2+1]; 35 | double _sum = 0; 36 | for (int i = 0; i < y.length; i++) { 37 | for (int j = 0; j < y[0].length; j++) { 38 | double x0 = i-size; 39 | double x1 = j-size; 40 | y[i][j] = Math.exp(-(x0 * x0 + x1 * x1) / (2 * sigma * sigma)) / (2 * Math.PI * sigma * sigma); 41 | _sum += y[i][j]; 42 | } 43 | } 44 | for (int i = 0; i < y.length; i++) { 45 | for (int j = 0; j < y[0].length; j++) { 46 | y[i][j] /= _sum; 47 | } 48 | } 49 | return y; 50 | } 51 | 52 | public static ArrayList sobel2d(int size) { 53 | if (size<1) { 54 | throw new IllegalArgumentException("Invalid size."); 55 | } 56 | double[][] gx = new double[size*2+1][size*2+1]; 57 | double[][] gy = new double[size*2+1][size*2+1]; 58 | 59 | for (int row = 0 ; row<(size*2+1) ; row++) { 60 | for (int col = 0 ; col<(size*2+1) ; col++) { 61 | int i = row-size; 62 | int j = col-size; 63 | gx[row][col] = j / Math.max((i*i+j*j), 1e-6); 64 | gy[row][col] = i / Math.max((i*i+j*j), 1e-6); 65 | } 66 | } 67 | 68 | ArrayList result = new ArrayList(); 69 | result.add(gx); 70 | result.add(gy); 71 | 72 | return result; 73 | } 74 | 75 | public static double[] laplacian1d3() { 76 | double[] result = new double[]{1,-2,1}; 77 | return result; 78 | } 79 | 80 | public static double[][] laplacian2d3_five() { 81 | double[][] result = new double[][]{ 82 | new double[]{0, 1,0}, 83 | new double[]{1,-4,1}, 84 | new double[]{0, 1,0} 85 | }; 86 | return result; 87 | } 88 | 89 | public static double[][] laplacian2d3_nine() { 90 | double[][] result = new double[][]{ 91 | new double[]{0.25,0.5,0.25}, 92 | new double[]{ 0.5, -3, 0.5}, 93 | new double[]{0.25,0.5,0.25} 94 | }; 95 | return result; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/ndArray/Lab.java: -------------------------------------------------------------------------------- 1 | package ndArray; 2 | 3 | /* 4 | Lab class 的主要作用是存放一些实验中的功能。有一些功能未必有 paper 的支持,因此使用应当谨慎。 5 | */ 6 | 7 | import java.awt.image.BufferedImage; 8 | import java.util.ArrayList; 9 | 10 | public class Lab { 11 | 12 | public Lab() {} 13 | 14 | public static double sharpness(int[][][] img, double T1, double T2, String mode) { 15 | mode = mode.toLowerCase(); 16 | if (!( mode.equals("chw1") || mode.equals("cwh1") || mode.equals("hwc1") || mode.equals("whc1") || 17 | mode.equals("chw255") || mode.equals("cwh255") || mode.equals("hwc255") || mode.equals("whc255") )) { 18 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: chw1, cwh1, hwc1, whc1, " + 19 | "chw255, cwh255, hwc255, whc255."); 20 | } 21 | 22 | double[][][] img_d = NdUtils.cast(img); // 改变格式到 double 23 | if (!mode.substring(0,1).equals("c")) { 24 | img_d = NdUtils.transpose(img_d, new int[]{2, 0, 1}); // 转置 25 | } 26 | if (mode.substring(3,4).equals("2")) { 27 | NdMath.elementwiseDivide(img_d, 255); // 归一化 28 | } 29 | return sharpness(img_d, T1, T2, "chw1"); 30 | } 31 | 32 | // 推荐 T1 = 0.2, T2 = 0.1 33 | public static double sharpness(double[][][] img_d, double T1, double T2, String mode) { 34 | mode = mode.toLowerCase(); 35 | if (!( mode.equals("chw1") || mode.equals("cwh1") || mode.equals("hwc1") || mode.equals("whc1") || 36 | mode.equals("chw255") || mode.equals("cwh255") || mode.equals("hwc255") || mode.equals("whc255") )) { 37 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: chw1, cwh1, hwc1, whc1, " + 38 | "chw255, cwh255, hwc255, whc255."); 39 | } 40 | if (!mode.substring(0,1).equals("c")) { 41 | img_d = NdUtils.transpose(img_d, new int[]{2, 0, 1}); // 转置 42 | } 43 | if (mode.substring(3,4).equals("2")) { 44 | NdMath.elementwiseDivide(img_d, 255); // 归一化 45 | } 46 | 47 | // 使用 Laplacian 做卷积 48 | double[][][] lap_result = new double[][][]{ 49 | NdMath.convolve(img_d[0], Filters.laplacian2d3_nine()), 50 | NdMath.convolve(img_d[1], Filters.laplacian2d3_nine()), 51 | NdMath.convolve(img_d[2], Filters.laplacian2d3_nine()), 52 | }; 53 | NdMath.ndAbs(lap_result); // 绝对值 54 | double[][] lap_result_ = NdMath.reduce(lap_result); // 各 channel 的平均 55 | 56 | ArrayList lap_values = NdUtils.flatten(lap_result_); 57 | 58 | double[] thresholds = new double[]{T1, T2}; 59 | double[] percentages = new double[2]; 60 | for (int i = 0; i < 2; i++) { 61 | double percentage = 0; 62 | for (double d : lap_values) { 63 | if (d>thresholds[i]) percentage+=1; 64 | } 65 | percentage /= lap_values.size(); 66 | percentages[i] = percentage; 67 | } 68 | 69 | return percentages[0]/percentages[1]; 70 | } 71 | 72 | private static double aligness_legacy(double[][] img_) { 73 | ArrayList sobels = Filters.sobel2d(3); 74 | double[][] sobelx = NdMath.convolve(img_, sobels.get(0)); 75 | NdMath.ndAbs(sobelx); 76 | double[][] sobely = NdMath.convolve(img_, sobels.get(1)); 77 | NdMath.ndAbs(sobely); 78 | double result = 0; 79 | for (int i = 0; i < sobelx.length; i++) { 80 | for (int j = 0; j < sobelx[0].length; j++) { 81 | result += Math.max(sobelx[i][j], sobely[i][j]); 82 | } 83 | } 84 | return result; 85 | } 86 | 87 | public static double straighten_legacy(int[][][] img_, String mode) { 88 | int w = 0; 89 | int h = 0; 90 | switch (mode) { 91 | case "chw": 92 | w = img_[0][0].length; 93 | h = img_[0].length; 94 | break; 95 | case "cwh": 96 | w = img_[0].length; 97 | h = img_[0][0].length; 98 | break; 99 | case "hwc": 100 | w = img_[0].length; 101 | h = img_.length; 102 | break; 103 | case "whc": 104 | w = img_.length; 105 | h = img_[0].length; 106 | break; 107 | default: 108 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: chw, cwh, hwc, whc."); 109 | } 110 | 111 | double side_length = 128; 112 | double ratio = 2*side_length/(w+h); 113 | int newWidth = Math.max(3, (int)(w*ratio)); // 因为 sobel filter 边长是 3 114 | int newHeight = Math.max(3, (int)(h*ratio)); 115 | 116 | BufferedImage bi = NdImageIO.convert(img_, mode); 117 | bi = NdImagePro.resize(bi, newWidth, newHeight); 118 | int[][][] img = NdImageIO.convert(bi, "cwh"); 119 | double[][] img_bw = NdMath.reduce(NdUtils.cast(img)); 120 | 121 | double[] gaps = new double[]{30,10,3.3,1.1}; 122 | double[] best_angle = new double[]{0, aligness_legacy(img_bw)}; 123 | for (double gap : gaps) { 124 | double base_angle = best_angle[0]; 125 | for (double delta : new double[]{-gap, gap}) { 126 | double angle = base_angle+delta; 127 | BufferedImage bi_ = NdImagePro.rotate(bi, angle); 128 | img = NdImageIO.convert(bi_, "cwh"); 129 | img_bw = NdMath.reduce(NdUtils.cast(img)); 130 | double _aligness = aligness_legacy(img_bw); 131 | if (_aligness>best_angle[1]) { 132 | best_angle = new double[]{angle, _aligness}; 133 | } 134 | } 135 | } 136 | return best_angle[0]; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/ndArray/NdCommonMathFunc.java: -------------------------------------------------------------------------------- 1 | package ndArray; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.ArrayList; 5 | 6 | public class NdCommonMathFunc { 7 | 8 | public NdCommonMathFunc() {} 9 | 10 | public static void softmax(Object array) { 11 | if (!array.getClass().isArray()) { 12 | throw new IllegalArgumentException("Invalid input. Not an array"); 13 | } 14 | int _length = Array.getLength(array); 15 | if (_length==0) { 16 | return; 17 | } 18 | double maximum = NdMath.max(array); 19 | NdMath.elementwiseSubtract(array, maximum); 20 | NdMath.ndExp(array); 21 | double summation = NdMath.sum(array); 22 | NdMath.elementwiseDivide(array, summation); 23 | } 24 | 25 | public static void sigmoid(Object array) { 26 | if (!array.getClass().isArray()) { 27 | throw new IllegalArgumentException("Invalid input. Not an array"); 28 | } 29 | int _length = Array.getLength(array); 30 | if (_length==0) { 31 | return; 32 | } 33 | NdMath.elementwiseMultiply(array, -1); 34 | NdMath.ndExp(array); 35 | NdMath.elementwiseAdd(array, 1); 36 | NdMath.elementwiseDivide(1, array); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/ndArray/NdImageIO.java: -------------------------------------------------------------------------------- 1 | package ndArray; 2 | 3 | import java.awt.*; 4 | import java.awt.image.BufferedImage; 5 | import java.io.File; 6 | import java.io.IOException; 7 | import javax.imageio.ImageIO; 8 | 9 | public class NdImageIO { 10 | 11 | public NdImageIO() {} 12 | 13 | public static BufferedImage convert(int[][][] _data, String mode) { 14 | mode = mode.toLowerCase(); 15 | int[][][] data; 16 | switch (mode) { 17 | case "chw": 18 | data = NdUtils.transpose(_data, new int[]{2,1,0}); 19 | break; 20 | case "cwh": 21 | data = NdUtils.transpose(_data, new int[]{1,2,0}); 22 | break; 23 | case "hwc": 24 | data = NdUtils.transpose(_data, new int[]{1,0,2}); 25 | break; 26 | case "whc": 27 | data = _data; 28 | default: 29 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: chw, cwh, hwc, whc."); 30 | } 31 | 32 | BufferedImage image = new BufferedImage(data.length, data[0].length, 1); 33 | 34 | for(int x = 0; x < data.length; ++x) { 35 | for(int y = 0; y < data[0].length; ++y) { 36 | int alpha = data[x][y].length>3?data[x][y][3]:255; 37 | Color c = new Color(data[x][y][0], data[x][y][1], data[x][y][2], alpha); 38 | int rgb = c.getRGB(); 39 | image.setRGB(x, y, rgb); 40 | } 41 | } 42 | 43 | return image; 44 | } 45 | 46 | public static int[][][] convert(BufferedImage bi, String mode) { 47 | mode = mode.toLowerCase(); 48 | if (mode.equals("chw") && mode.equals("cwh") && mode.equals("hwc") && mode.equals("whc")) { 49 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: chw, cwh, hwc, whc."); 50 | } 51 | int[][][] result = new int[0][][]; 52 | if (mode.equals("chw")) { 53 | result = new int[3][bi.getHeight()][bi.getWidth()]; 54 | } else if (mode.equals("cwh")) { 55 | result = new int[3][bi.getWidth()][bi.getHeight()]; 56 | } else if (mode.equals("hwc")) { 57 | result = new int[bi.getHeight()][bi.getWidth()][3]; 58 | } else if (mode.equals("whc")) { 59 | result = new int[bi.getWidth()][bi.getHeight()][3]; 60 | } 61 | 62 | for(int x = 0; x < bi.getWidth(); ++x) { 63 | for(int y = 0; y < bi.getHeight(); ++y) { 64 | int color = bi.getRGB(x, y); 65 | int blue = color & 255; 66 | int green = (color & '\uff00') >> 8; 67 | int red = (color & 16711680) >> 16; 68 | if (mode.equals("chw")) { 69 | result[0][y][x] = red; 70 | result[1][y][x] = green; 71 | result[2][y][x] = blue; 72 | } else if (mode.equals("cwh")) { 73 | result[0][x][y] = red; 74 | result[1][x][y] = green; 75 | result[2][x][y] = blue; 76 | } else if (mode.equals("hwc")) { 77 | result[y][x][0] = red; 78 | result[y][x][1] = green; 79 | result[y][x][2] = blue; 80 | } else if (mode.equals("whc")) { 81 | result[x][y][0] = red; 82 | result[x][y][1] = green; 83 | result[x][y][2] = blue; 84 | } 85 | 86 | } 87 | } 88 | 89 | return result; 90 | } 91 | 92 | public static int[][][] readImage(String path, String mode) { 93 | File f = new File(path); 94 | return readImage(f, mode); 95 | } 96 | 97 | public static int[][][] readImage(File f, String mode) { 98 | mode = mode.toLowerCase(); 99 | if (mode.equals("chw") && mode.equals("cwh") && mode.equals("hwc") && mode.equals("whc")) { 100 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: chw, cwh, hwc, whc."); 101 | } 102 | try { 103 | BufferedImage image = ImageIO.read(f); 104 | return convert(image, mode); 105 | } catch (IOException var9) { 106 | var9.printStackTrace(); 107 | return (int[][][])null; 108 | } 109 | } 110 | 111 | public static void writeImage(String path, double[][] _data, String mode) { 112 | mode = mode.toLowerCase(); 113 | if (!(mode.equals("wh") || mode.equals("hw"))) { 114 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: wh, hw."); 115 | } 116 | double[][][] data = new double[][][]{_data, _data, _data}; 117 | writeImage(path, data, "c"+mode); 118 | } 119 | 120 | public static void writeImage(File f, double[][] _data, String mode) { 121 | mode = mode.toLowerCase(); 122 | if (!(mode.equals("wh") || mode.equals("hw"))) { 123 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: wh, hw."); 124 | } 125 | double[][][] data = new double[][][]{_data, _data, _data}; 126 | writeImage(f, data, "c"+mode); 127 | } 128 | 129 | public static void writeImage(String path, int[][] _data, String mode) { 130 | mode = mode.toLowerCase(); 131 | if (!(mode.equals("wh") || mode.equals("hw"))) { 132 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: wh, hw."); 133 | } 134 | int[][][] data = new int[][][]{_data, _data, _data}; 135 | writeImage(path, data, "c"+mode); 136 | } 137 | 138 | public static void writeImage(File f, int[][] _data, String mode) { 139 | mode = mode.toLowerCase(); 140 | if (!(mode.equals("wh") || mode.equals("hw"))) { 141 | throw new IllegalArgumentException("Illegal Mode. Please choose the mode from: wh, hw."); 142 | } 143 | int[][][] data = new int[][][]{_data, _data, _data}; 144 | writeImage(f, data, "c"+mode); 145 | } 146 | 147 | public static void writeImage(String path, double[][][] _data, String mode) { 148 | writeImage(path, NdUtils.cast(_data),mode); 149 | } 150 | 151 | public static void writeImage(File f, double[][][] _data, String mode) { 152 | writeImage(f, NdUtils.cast(_data),mode); 153 | } 154 | 155 | public static void writeImage(String path, int[][][] _data, String mode) { 156 | File f = new File(path); 157 | writeImage(f, _data, mode); 158 | } 159 | 160 | public static void writeImage(File f, int[][][] _data, String mode) { 161 | BufferedImage image = convert(_data, mode); 162 | try { 163 | ImageIO.write(image, "jpg", f); 164 | } catch (IOException var7) { 165 | var7.printStackTrace(); 166 | } 167 | 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/ndArray/NdImagePro.java: -------------------------------------------------------------------------------- 1 | package ndArray; 2 | 3 | import java.awt.*; 4 | import java.awt.image.BufferedImage; 5 | 6 | public class NdImagePro { 7 | 8 | public NdImagePro() {} 9 | 10 | public static BufferedImage resize(BufferedImage bi, int newWidth, int newHeight) { 11 | Image newImage = bi.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT); 12 | BufferedImage bimage = new BufferedImage( 13 | newImage.getWidth(null), 14 | newImage.getHeight(null), 15 | bi.getType() 16 | ); 17 | 18 | // Draw the image on to the buffered image 19 | Graphics2D bGr = bimage.createGraphics(); 20 | bGr.drawImage(newImage, 0, 0, null); 21 | bGr.dispose(); 22 | 23 | // Return the buffered image 24 | return bimage; 25 | } 26 | 27 | public static int[][][] resize(int[][][] _data, int newWidth, int newHeight, String mode) { 28 | BufferedImage bi = NdImageIO.convert(_data, mode); 29 | bi = resize(bi, newWidth, newHeight); 30 | int[][][] image = NdImageIO.convert(bi, mode); 31 | return image; 32 | } 33 | 34 | // public static int[][] resize(int[][] _data, int newWidth, int newHeight, String mode) {} 35 | 36 | public static BufferedImage rotate(BufferedImage bi, double angle, boolean padded) { 37 | int w = bi.getWidth(); 38 | int h = bi.getHeight(); 39 | double toRad = Math.toRadians(angle); 40 | if (padded) { 41 | int hPrime = (int) (w * Math.abs(Math.sin(toRad)) + h * Math.abs(Math.cos(toRad))); 42 | int wPrime = (int) (h * Math.abs(Math.sin(toRad)) + w * Math.abs(Math.cos(toRad))); 43 | 44 | BufferedImage rotated = new BufferedImage(wPrime, hPrime, bi.getType()); 45 | Graphics2D g = rotated.createGraphics(); 46 | g.setColor(Color.BLACK); 47 | g.fillRect(0, 0, wPrime, hPrime); // fill entire area 48 | g.translate(wPrime/2, hPrime/2); 49 | g.rotate(toRad); 50 | g.translate(-w/2, -h/2); 51 | g.drawImage(bi, 0, 0, null); 52 | g.dispose(); // release used resources before g is garbage-collected 53 | return rotated; 54 | } else { 55 | BufferedImage rotated = new BufferedImage(w, h, bi.getType()); 56 | Graphics2D g = rotated.createGraphics(); 57 | g.rotate(toRad, w/2, h/2); 58 | g.drawImage(bi, null, 0, 0); 59 | g.dispose(); 60 | return rotated; 61 | } 62 | } 63 | 64 | public static BufferedImage rotate(BufferedImage bi, double angle) { 65 | return rotate(bi, angle, true); 66 | } 67 | 68 | public static int[][][] rotate(int[][][] _data, double angle, String mode) { 69 | BufferedImage bi = NdImageIO.convert(_data, mode); 70 | bi = rotate(bi, angle); 71 | int[][][] image = NdImageIO.convert(bi, mode); 72 | return image; 73 | } 74 | 75 | // public static int[][] rotate(int[][] _data, double angle) {} 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/ndArray/NdMath.java: -------------------------------------------------------------------------------- 1 | package ndArray; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.ArrayList; 5 | 6 | public class NdMath { 7 | 8 | public NdMath() {} 9 | 10 | public static double[] convolve(double[] array, double[] filter, boolean isFilterSymmetrical) { 11 | if (filter.length>array.length) { 12 | throw new IllegalArgumentException("Filter size: "+filter.length+ 13 | " is larger than the size of the array: "+array.length+"."); 14 | } 15 | double[] result = new double[array.length-filter.length+1]; 16 | 17 | int n_filters = filter.length; 18 | // 如果滤波器是对称的 19 | if (isFilterSymmetrical) { 20 | // 判断滤波器尺寸是否是双数 21 | if (filter.length/2*2 == filter.length) { 22 | n_filters = n_filters/2; 23 | } else { 24 | n_filters = n_filters/2+1; 25 | } 26 | } 27 | 28 | // 是的,计算卷积我应该用FFT的,但我懒了 29 | double[][] result_of_filters = new double[n_filters][array.length]; 30 | for (int i = 0; i < n_filters; i++) { 31 | double[] tmp = new double[array.length]; 32 | for (int j = 0; j < array.length; j++) { 33 | tmp[j] = array[j]*filter[i]; 34 | } 35 | result_of_filters[i] = tmp; 36 | } 37 | for (int i = 0; i < filter.length; i++) { 38 | int filter_index = i; 39 | if (i>=n_filters) { 40 | if (filter.length/2*2 == filter.length) { 41 | filter_index = 2*n_filters-1-i; 42 | } else { 43 | filter_index = 2*n_filters-2-i; 44 | } 45 | } 46 | double[] result_of_filter = result_of_filters[filter_index]; 47 | int start = i; 48 | int end = i+array.length-filter.length+1; 49 | 50 | for (int j = start; j < end; j++) { 51 | result[j-start] += result_of_filter[j]; 52 | } 53 | } 54 | return result; 55 | } 56 | 57 | public static double[] convolve(double[] array, double[] filter) { 58 | return convolve(array, filter, false); 59 | } 60 | 61 | public static double[][] convolve(double[][] array, double[][] filter, boolean[] isFilterSymmetrical) { 62 | if (filter.length>array.length || filter[0].length>array[0].length) { 63 | throw new IllegalArgumentException("Filter size: "+ 64 | filter.length+", "+filter[0].length+ 65 | " is larger than the size of the array: "+ 66 | array.length+", "+array[0].length+"."); 67 | } 68 | if (isFilterSymmetrical.length != (filter.length+1)) { 69 | throw new IllegalArgumentException("The length of isFilterSymmetrical should be equal to (filter.length+1)."); 70 | } 71 | 72 | double[][] result = new double[array.length-filter.length+1][array[0].length-filter[0].length+1]; 73 | 74 | int n_filters = filter.length; 75 | // 如果滤波器是对称的 76 | if (isFilterSymmetrical[0]) { 77 | // 判断滤波器尺寸是否是双数 78 | if (filter.length/2*2 == filter.length) { 79 | n_filters = n_filters/2; 80 | } else { 81 | n_filters = n_filters/2+1; 82 | } 83 | } 84 | 85 | double[][][] result_of_filters = new double[n_filters][array.length][]; 86 | for (int i = 0; i < n_filters; i++) { 87 | double[][] tmp = new double[array.length][]; 88 | for (int j = 0; j < array.length; j++) { 89 | tmp[j] = convolve(array[j], filter[i], isFilterSymmetrical[i+1]); 90 | } 91 | result_of_filters[i] = tmp; 92 | } 93 | for (int i = 0; i < filter.length; i++) { 94 | int filter_index = i; 95 | if (i>=n_filters) { 96 | if (filter.length/2*2 == filter.length) { 97 | filter_index = 2*n_filters-1-i; 98 | } else { 99 | filter_index = 2*n_filters-2-i; 100 | } 101 | } 102 | double[][] result_of_filter = result_of_filters[filter_index]; 103 | int start = i; 104 | int end = i+array.length-filter.length+1; 105 | 106 | for (int j = start; j < end; j++) { 107 | for (int k = 0; k < result[j - start].length; k++) { 108 | result[j-start][k] += result_of_filter[j][k]; 109 | } 110 | } 111 | } 112 | return result; 113 | } 114 | 115 | public static double[][] convolve(double[][] array, double[][] filter, boolean isFilterSymmetrical) { 116 | boolean[] isFilterSymmetricals = new boolean[filter.length+1]; // 初始化默认是false 117 | if (isFilterSymmetrical) { 118 | for (int i = 0; i < isFilterSymmetricals.length; i++) { 119 | isFilterSymmetricals[i] = isFilterSymmetrical; 120 | } 121 | } 122 | return convolve(array, filter, isFilterSymmetricals); 123 | } 124 | 125 | public static double[][] convolve(double[][] array, double[][] filter) { 126 | boolean[] isFilterSymmetricals = new boolean[filter.length+1]; // 初始化默认是false 127 | return convolve(array, filter, isFilterSymmetricals); 128 | } 129 | 130 | public static double min(ArrayList array) { 131 | if (array.size()==0) { 132 | throw new IllegalArgumentException("Empty Array."); 133 | } 134 | double result = array.get(0); 135 | for (double d : array) { 136 | if (d _array = NdUtils.flatten(array); 146 | return min(_array); 147 | } 148 | 149 | public static double max(ArrayList array) { 150 | if (array.size()==0) { 151 | throw new IllegalArgumentException("Empty Array."); 152 | } 153 | double result = array.get(0); 154 | for (double d : array) { 155 | if (d>result) result = d; 156 | } 157 | return result; 158 | } 159 | 160 | public static double max(Object array) { 161 | if (!array.getClass().isArray()) { 162 | throw new IllegalArgumentException("Invalid input. Not an array"); 163 | } 164 | ArrayList _array = NdUtils.flatten(array); 165 | return max(_array); 166 | } 167 | 168 | public static double sum(ArrayList array) { 169 | if (array.size()==0) { 170 | throw new IllegalArgumentException("Empty Array."); 171 | } 172 | double result = 0; 173 | for (double d : array) { 174 | result+=d; 175 | } 176 | return result; 177 | } 178 | 179 | public static double sum(Object array) { 180 | if (!array.getClass().isArray()) { 181 | throw new IllegalArgumentException("Invalid input. Not an array"); 182 | } 183 | ArrayList _array = NdUtils.flatten(array); 184 | return sum(_array); 185 | } 186 | 187 | public static double mean(ArrayList array) { 188 | double _sum = sum(array); 189 | int count = array.size(); 190 | return _sum/count; 191 | } 192 | 193 | public static double mean(Object array) { 194 | ArrayList _array = NdUtils.flatten(array); 195 | double _sum = sum(_array); 196 | int count = _array.size(); 197 | return _sum/count; 198 | } 199 | 200 | // averaging along the first dimension 201 | public static double reduce(double[] img) { 202 | return mean(img); 203 | } 204 | 205 | // averaging along the first dimension 206 | public static double[] reduce(double[][] img) { 207 | double[]result = new double[img[0].length]; 208 | for (int i = 0; i < img.length; i++) { 209 | NdMath.elementwiseAdd(result, img[i]); 210 | } 211 | NdMath.elementwiseDivide(result, img.length); 212 | return result; 213 | } 214 | 215 | // averaging along the first dimension 216 | public static double[][] reduce(double[][][] img) { 217 | double[][] result = new double[img[0].length][img[0][0].length]; 218 | for (int i = 0; i < img.length; i++) { 219 | NdMath.elementwiseAdd(result, img[i]); 220 | } 221 | NdMath.elementwiseDivide(result, img.length); 222 | return result; 223 | } 224 | 225 | // averaging along the first dimension 226 | public static double[][][] reduce(double[][][][] img) { 227 | double[][][] result = new double[img[0].length][img[0][0].length][img[0][0][0].length]; 228 | for (int i = 0; i < img.length; i++) { 229 | NdMath.elementwiseAdd(result, img[i]); 230 | } 231 | NdMath.elementwiseDivide(result, img.length); 232 | return result; 233 | } 234 | 235 | // averaging along the first dimension 236 | public static double[][][][] reduce(double[][][][][] img) { 237 | double[][][][] result = new double[img[0].length][img[0][0].length][img[0][0][0].length][img[0][0][0][0].length]; 238 | for (int i = 0; i < img.length; i++) { 239 | NdMath.elementwiseAdd(result, img[i]); 240 | } 241 | NdMath.elementwiseDivide(result, img.length); 242 | return result; 243 | } 244 | 245 | public static void ndPow(Object array, double num) { 246 | if (!array.getClass().isArray()) { 247 | throw new IllegalArgumentException("Invalid input. Not an array"); 248 | } 249 | int _length = Array.getLength(array); 250 | if (_length==0) { 251 | return; 252 | } 253 | if (array.getClass().getComponentType().isArray()) { 254 | for (int i = 0; i < _length; i++) { 255 | ndPow(Array.get(array, i), num); 256 | } 257 | } else { 258 | for (int i = 0; i < _length; i++) { 259 | Array.set(array, i, Math.pow(Array.getDouble(array, i), num)); 260 | } 261 | } 262 | } 263 | 264 | public static void ndPow(Object array, Object array_) { 265 | if (!array.getClass().isArray()) { 266 | throw new IllegalArgumentException("Invalid input. Not an array."); 267 | } 268 | int _length = Array.getLength(array); 269 | if (_length==0) { 270 | return; 271 | } 272 | if (_length != Array.getLength(array_)) { 273 | throw new IllegalArgumentException("Inconsistent shape."); 274 | } 275 | if (array.getClass().getComponentType().isArray()) { 276 | for (int i = 0; i < _length; i++) { 277 | ndPow(Array.get(array, i), Array.get(array_, i)); 278 | } 279 | } else { 280 | for (int i = 0; i < _length; i++) { 281 | Array.set(array_, i, Math.pow(Array.getDouble(array, i), Array.getDouble(array_, i))); 282 | } 283 | } 284 | } 285 | 286 | public static void ndSqrt(Object array) { 287 | ndPow(array, 0.5); 288 | } 289 | 290 | public static void ndExp(Object array) { 291 | if (!array.getClass().isArray()) { 292 | throw new IllegalArgumentException("Invalid input. Not an array"); 293 | } 294 | int _length = Array.getLength(array); 295 | if (_length==0) { 296 | return; 297 | } 298 | if (array.getClass().getComponentType().isArray()) { 299 | for (int i = 0; i < _length; i++) { 300 | ndExp(Array.get(array, i)); 301 | } 302 | } else { 303 | for (int i = 0; i < _length; i++) { 304 | Array.set(array, i, Math.exp(Array.getDouble(array, i))); 305 | } 306 | } 307 | } 308 | 309 | public static void ndAbs(Object array) { 310 | if (!array.getClass().isArray()) { 311 | throw new IllegalArgumentException("Invalid input. Not an array"); 312 | } 313 | int _length = Array.getLength(array); 314 | if (_length==0) { 315 | return; 316 | } 317 | if (array.getClass().getComponentType().isArray()) { 318 | for (int i = 0; i < _length; i++) { 319 | ndAbs(Array.get(array, i)); 320 | } 321 | } else { 322 | for (int i = 0; i < _length; i++) { 323 | Array.set(array, i, Math.abs(Array.getDouble(array, i))); 324 | } 325 | } 326 | } 327 | 328 | public static void ndSin(Object array) { 329 | if (!array.getClass().isArray()) { 330 | throw new IllegalArgumentException("Invalid input. Not an array"); 331 | } 332 | int _length = Array.getLength(array); 333 | if (_length==0) { 334 | return; 335 | } 336 | if (array.getClass().getComponentType().isArray()) { 337 | for (int i = 0; i < _length; i++) { 338 | ndSin(Array.get(array, i)); 339 | } 340 | } else { 341 | for (int i = 0; i < _length; i++) { 342 | Array.set(array, i, Math.sin(Array.getDouble(array, i))); 343 | } 344 | } 345 | } 346 | 347 | public static void ndCos(Object array) { 348 | if (!array.getClass().isArray()) { 349 | throw new IllegalArgumentException("Invalid input. Not an array"); 350 | } 351 | int _length = Array.getLength(array); 352 | if (_length==0) { 353 | return; 354 | } 355 | if (array.getClass().getComponentType().isArray()) { 356 | for (int i = 0; i < _length; i++) { 357 | ndCos(Array.get(array, i)); 358 | } 359 | } else { 360 | for (int i = 0; i < _length; i++) { 361 | Array.set(array, i, Math.cos(Array.getDouble(array, i))); 362 | } 363 | } 364 | } 365 | 366 | public static void ndTan(Object array) { 367 | if (!array.getClass().isArray()) { 368 | throw new IllegalArgumentException("Invalid input. Not an array"); 369 | } 370 | int _length = Array.getLength(array); 371 | if (_length==0) { 372 | return; 373 | } 374 | if (array.getClass().getComponentType().isArray()) { 375 | for (int i = 0; i < _length; i++) { 376 | ndTan(Array.get(array, i)); 377 | } 378 | } else { 379 | for (int i = 0; i < _length; i++) { 380 | Array.set(array, i, Math.tan(Array.getDouble(array, i))); 381 | } 382 | } 383 | } 384 | 385 | public static void ndSinh(Object array) { 386 | if (!array.getClass().isArray()) { 387 | throw new IllegalArgumentException("Invalid input. Not an array"); 388 | } 389 | int _length = Array.getLength(array); 390 | if (_length==0) { 391 | return; 392 | } 393 | if (array.getClass().getComponentType().isArray()) { 394 | for (int i = 0; i < _length; i++) { 395 | ndSinh(Array.get(array, i)); 396 | } 397 | } else { 398 | for (int i = 0; i < _length; i++) { 399 | Array.set(array, i, Math.sinh(Array.getDouble(array, i))); 400 | } 401 | } 402 | } 403 | 404 | public static void ndCosh(Object array) { 405 | if (!array.getClass().isArray()) { 406 | throw new IllegalArgumentException("Invalid input. Not an array"); 407 | } 408 | int _length = Array.getLength(array); 409 | if (_length==0) { 410 | return; 411 | } 412 | if (array.getClass().getComponentType().isArray()) { 413 | for (int i = 0; i < _length; i++) { 414 | ndCosh(Array.get(array, i)); 415 | } 416 | } else { 417 | for (int i = 0; i < _length; i++) { 418 | Array.set(array, i, Math.cosh(Array.getDouble(array, i))); 419 | } 420 | } 421 | } 422 | 423 | public static void ndTanh(Object array) { 424 | if (!array.getClass().isArray()) { 425 | throw new IllegalArgumentException("Invalid input. Not an array"); 426 | } 427 | int _length = Array.getLength(array); 428 | if (_length==0) { 429 | return; 430 | } 431 | if (array.getClass().getComponentType().isArray()) { 432 | for (int i = 0; i < _length; i++) { 433 | ndTanh(Array.get(array, i)); 434 | } 435 | } else { 436 | for (int i = 0; i < _length; i++) { 437 | Array.set(array, i, Math.tanh(Array.getDouble(array, i))); 438 | } 439 | } 440 | } 441 | 442 | public static void ndAsin(Object array) { 443 | if (!array.getClass().isArray()) { 444 | throw new IllegalArgumentException("Invalid input. Not an array"); 445 | } 446 | int _length = Array.getLength(array); 447 | if (_length==0) { 448 | return; 449 | } 450 | if (array.getClass().getComponentType().isArray()) { 451 | for (int i = 0; i < _length; i++) { 452 | ndAsin(Array.get(array, i)); 453 | } 454 | } else { 455 | for (int i = 0; i < _length; i++) { 456 | Array.set(array, i, Math.asin(Array.getDouble(array, i))); 457 | } 458 | } 459 | } 460 | 461 | public static void ndAcos(Object array) { 462 | if (!array.getClass().isArray()) { 463 | throw new IllegalArgumentException("Invalid input. Not an array"); 464 | } 465 | int _length = Array.getLength(array); 466 | if (_length==0) { 467 | return; 468 | } 469 | if (array.getClass().getComponentType().isArray()) { 470 | for (int i = 0; i < _length; i++) { 471 | ndAcos(Array.get(array, i)); 472 | } 473 | } else { 474 | for (int i = 0; i < _length; i++) { 475 | Array.set(array, i, Math.acos(Array.getDouble(array, i))); 476 | } 477 | } 478 | } 479 | 480 | public static void ndAtan(Object array) { 481 | if (!array.getClass().isArray()) { 482 | throw new IllegalArgumentException("Invalid input. Not an array"); 483 | } 484 | int _length = Array.getLength(array); 485 | if (_length==0) { 486 | return; 487 | } 488 | if (array.getClass().getComponentType().isArray()) { 489 | for (int i = 0; i < _length; i++) { 490 | ndAtan(Array.get(array, i)); 491 | } 492 | } else { 493 | for (int i = 0; i < _length; i++) { 494 | Array.set(array, i, Math.atan(Array.getDouble(array, i))); 495 | } 496 | } 497 | } 498 | 499 | public static void ndLog(Object array) { 500 | if (!array.getClass().isArray()) { 501 | throw new IllegalArgumentException("Invalid input. Not an array"); 502 | } 503 | int _length = Array.getLength(array); 504 | if (_length==0) { 505 | return; 506 | } 507 | if (array.getClass().getComponentType().isArray()) { 508 | for (int i = 0; i < _length; i++) { 509 | ndLog(Array.get(array, i)); 510 | } 511 | } else { 512 | for (int i = 0; i < _length; i++) { 513 | Array.set(array, i, Math.log(Array.getDouble(array, i))); 514 | } 515 | } 516 | } 517 | 518 | public static void ndLog10(Object array) { 519 | if (!array.getClass().isArray()) { 520 | throw new IllegalArgumentException("Invalid input. Not an array"); 521 | } 522 | int _length = Array.getLength(array); 523 | if (_length==0) { 524 | return; 525 | } 526 | if (array.getClass().getComponentType().isArray()) { 527 | for (int i = 0; i < _length; i++) { 528 | ndLog10(Array.get(array, i)); 529 | } 530 | } else { 531 | for (int i = 0; i < _length; i++) { 532 | Array.set(array, i, Math.log10(Array.getDouble(array, i))); 533 | } 534 | } 535 | } 536 | 537 | public static double dot(double[] array, double[] array_) { 538 | if (array.length!=array_.length) { 539 | throw new IllegalArgumentException("Invalid input. Inconsistent vector length."); 540 | } 541 | double result = 0; 542 | for (int i = 0; i < array.length; i++) { 543 | result+=array[i]*array_[i]; 544 | } 545 | return result; 546 | } 547 | 548 | public static double[][] dot(double[][] array, double[][] array_) { 549 | double[][] result = new double[array.length][array_[0].length]; 550 | for (int i = 0 ; i flatten(Object array) { 75 | if (!array.getClass().isArray()) { 76 | throw new IllegalArgumentException("Invalid input. Not an array"); 77 | } 78 | 79 | ArrayList result = new ArrayList(); 80 | int _length = Array.getLength(array); 81 | if (_length==0) { 82 | return result; 83 | } 84 | if (array.getClass().getComponentType().isArray()) { 85 | for (int i = 0; i < _length; i++) { 86 | ArrayList subresult = flatten(Array.get(array, i)); 87 | for (double d : subresult) result.add(d); 88 | } 89 | } else { 90 | for (int i = 0; i < _length; i++) { 91 | result.add(Array.getDouble(array,i)); 92 | } 93 | } 94 | return result; 95 | } 96 | 97 | public static void copyArray(Object array, Object target) { 98 | if (!array.getClass().isArray()) { 99 | throw new IllegalArgumentException("Invalid input. Not an array."); 100 | } 101 | int _length = Array.getLength(array); 102 | if (_length==0) { 103 | return; 104 | } 105 | if (_length != Array.getLength(target)) { 106 | throw new IllegalArgumentException("Inconsistent shape."); 107 | } 108 | if (array.getClass().getComponentType().isArray()) { 109 | for (int i = 0; i < _length; i++) { 110 | copyArray(Array.get(array, i), Array.get(target, i)); 111 | } 112 | } else { 113 | for (int i = 0; i < _length; i++) { 114 | Array.set(target, i, Array.get(array, i)); 115 | } 116 | } 117 | } 118 | 119 | public static int[] shape(Object array) { 120 | if (array.getClass().getComponentType().isArray()) { 121 | int length0 = Array.getLength(array); 122 | if (length0==0) return new int[0]; 123 | 124 | int[] subshape = shape(Array.get(array, 0)); 125 | int[] result = new int[subshape.length+1]; 126 | result[0] = length0; 127 | for (int i = 0; i < subshape.length; i++) { 128 | result[i+1] = subshape[i]; 129 | } 130 | return result; 131 | } else if (array.getClass().isArray()) { 132 | return new int[]{Array.getLength(array)}; 133 | } else { 134 | throw new IllegalArgumentException("Invalid input array."); 135 | } 136 | } 137 | 138 | public static void reshape(ArrayList array, Object target) { 139 | int[] shape = shape(target); 140 | int _sum = 1; 141 | for (int i : shape) _sum*=i; 142 | if (_sum!=array.size()) { 143 | throw new IllegalArgumentException("Inconsistent number of elements."); 144 | } 145 | 146 | if (!target.getClass().isArray()) { 147 | throw new IllegalArgumentException("Invalid target. Not an array"); 148 | } 149 | int _length = Array.getLength(target); 150 | if (_length==0) { 151 | return; 152 | } 153 | if (target.getClass().getComponentType().isArray()) { 154 | int gap = array.size()/Array.getLength(target); 155 | for (int i = 0; i < _length; i++) { 156 | reshape(new ArrayList(array.subList(i*gap, (i+1)*gap)), Array.get(target, i)); 157 | } 158 | } else { 159 | if (target.getClass().getComponentType().equals(double.class)) { 160 | for (int i = 0; i < _length; i++) { 161 | Array.set(target, i, array.get(i)); 162 | } 163 | } else { 164 | throw new IllegalArgumentException("The target should be an array of doubles."); 165 | } 166 | } 167 | } 168 | 169 | public static void reshape(Object array, Object target) { 170 | ArrayList data = flatten(array); 171 | reshape(data, target); 172 | } 173 | 174 | public static double[] cast(int[] array) { 175 | double[] result = new double[array.length]; 176 | for (int i = 0; i < array.length; i++) { 177 | result[i] = (double) array[i]; 178 | } 179 | return result; 180 | } 181 | 182 | public static double[][] cast(int[][] array) { 183 | double[][] result = new double[array.length][]; 184 | for (int i = 0; i < array.length; i++) { 185 | result[i] = cast(array[i]); 186 | } 187 | return result; 188 | } 189 | 190 | public static double[][][] cast(int[][][] array) { 191 | double[][][] result = new double[array.length][][]; 192 | for (int i = 0; i < array.length; i++) { 193 | result[i] = cast(array[i]); 194 | } 195 | return result; 196 | } 197 | 198 | public static double[][][][] cast(int[][][][] array) { 199 | double[][][][] result = new double[array.length][][][]; 200 | for (int i = 0; i < array.length; i++) { 201 | result[i] = cast(array[i]); 202 | } 203 | return result; 204 | } 205 | 206 | public static double[][][][][] cast(int[][][][][] array) { 207 | double[][][][][] result = new double[array.length][][][][]; 208 | for (int i = 0; i < array.length; i++) { 209 | result[i] = cast(array[i]); 210 | } 211 | return result; 212 | } 213 | 214 | // The values are rounded before casting. 215 | public static int[] cast(double[] array) { 216 | int[] result = new int[array.length]; 217 | for (int i = 0; i < array.length; i++) { 218 | result[i] = (int) Math.round(array[i]); 219 | } 220 | return result; 221 | } 222 | 223 | public static int[][] cast(double[][] array) { 224 | int[][] result = new int[array.length][]; 225 | for (int i = 0; i < array.length; i++) { 226 | result[i] = cast(array[i]); 227 | } 228 | return result; 229 | } 230 | 231 | public static int[][][] cast(double[][][] array) { 232 | int[][][] result = new int[array.length][][]; 233 | for (int i = 0; i < array.length; i++) { 234 | result[i] = cast(array[i]); 235 | } 236 | return result; 237 | } 238 | 239 | public static int[][][][] cast(double[][][][] array) { 240 | int[][][][] result = new int[array.length][][][]; 241 | for (int i = 0; i < array.length; i++) { 242 | result[i] = cast(array[i]); 243 | } 244 | return result; 245 | } 246 | 247 | public static int[][][][][] cast(double[][][][][] array) { 248 | int[][][][][] result = new int[array.length][][][][]; 249 | for (int i = 0; i < array.length; i++) { 250 | result[i] = cast(array[i]); 251 | } 252 | return result; 253 | } 254 | 255 | public static double[][] transpose(double[][] array, int[] dims) { 256 | if (dims.length!=2) { 257 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 258 | } 259 | 260 | int[] sizes = new int[]{array.length, array[0].length}; 261 | double[][] result = new double[sizes[dims[0]]][sizes[dims[1]]]; 262 | for (int i = 0; i < sizes[0]; i++) { 263 | for (int j = 0; j < sizes[1]; j++) { 264 | int[] dim_indices = new int[]{i,j}; 265 | result[dim_indices[dims[0]]][dim_indices[dims[1]]] = array[i][j]; 266 | } 267 | } 268 | return result; 269 | } 270 | 271 | public static double[][] transpose(double[][] array) { 272 | return transpose(array, new int[]{1,0}); 273 | } 274 | 275 | public static double[][][] transpose(double[][][] array, int[] dims) { 276 | if (dims.length!=3) { 277 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 278 | } 279 | 280 | int[] sizes = new int[]{array.length, array[0].length, array[0][0].length}; 281 | double[][][] result = new double[sizes[dims[0]]][sizes[dims[1]]][sizes[dims[2]]]; 282 | for (int i = 0; i < sizes[0]; i++) { 283 | for (int j = 0; j < sizes[1]; j++) { 284 | for (int k = 0; k < sizes[2]; k++) { 285 | int[] dim_indices = new int[]{i,j,k}; 286 | result[dim_indices[dims[0]]][dim_indices[dims[1]]][dim_indices[dims[2]]] = array[i][j][k]; 287 | } 288 | } 289 | } 290 | return result; 291 | } 292 | 293 | public static double[][][][] transpose(double[][][][] array, int[] dims) { 294 | if (dims.length!=4) { 295 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 296 | } 297 | 298 | int[] sizes = new int[]{array.length, array[0].length, array[0][0].length, array[0][0][0].length}; 299 | double[][][][] result = new double[sizes[dims[0]]][sizes[dims[1]]][sizes[dims[2]]][sizes[dims[3]]]; 300 | for (int i = 0; i < sizes[0]; i++) { 301 | for (int j = 0; j < sizes[1]; j++) { 302 | for (int k = 0; k < sizes[2]; k++) { 303 | for (int l = 0; l < sizes[3]; l++) { 304 | int[] dim_indices = new int[]{i,j,k,l}; 305 | result[dim_indices[dims[0]]][dim_indices[dims[1]]][dim_indices[dims[2]]] 306 | [dim_indices[dims[3]]] = array[i][j][k][l]; 307 | } 308 | } 309 | } 310 | } 311 | 312 | return result; 313 | } 314 | 315 | public static double[][][][][] transpose(double[][][][][] array, int[] dims) { 316 | if (dims.length!=5) { 317 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 318 | } 319 | 320 | int[] sizes = new int[]{array.length, array[0].length, array[0][0].length, array[0][0][0].length, array[0][0][0][0].length}; 321 | double[][][][][] result = new double[sizes[dims[0]]][sizes[dims[1]]][sizes[dims[2]]][sizes[dims[3]]][sizes[dims[4]]]; 322 | for (int i = 0; i < sizes[0]; i++) { 323 | for (int j = 0; j < sizes[1]; j++) { 324 | for (int k = 0; k < sizes[2]; k++) { 325 | for (int l = 0; l < sizes[3]; l++) { 326 | for (int m = 0; m < sizes[4]; m++) { 327 | int[] dim_indices = new int[]{i,j,k,l,m}; 328 | result[dim_indices[dims[0]]][dim_indices[dims[1]]][dim_indices[dims[2]]] 329 | [dim_indices[dims[3]]][dim_indices[dims[4]]] = array[i][j][k][l][m]; 330 | } 331 | } 332 | } 333 | } 334 | } 335 | 336 | return result; 337 | } 338 | 339 | public static int[][] transpose(int[][] array, int[] dims) { 340 | if (dims.length!=2) { 341 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 342 | } 343 | 344 | int[] sizes = new int[]{array.length, array[0].length}; 345 | int[][] result = new int[sizes[dims[0]]][sizes[dims[1]]]; 346 | for (int i = 0; i < sizes[0]; i++) { 347 | for (int j = 0; j < sizes[1]; j++) { 348 | int[] dim_indices = new int[]{i,j}; 349 | result[dim_indices[dims[0]]][dim_indices[dims[1]]] = array[i][j]; 350 | } 351 | } 352 | return result; 353 | } 354 | 355 | public static int[][] transpose(int[][] array) { 356 | return transpose(array, new int[]{1,0}); 357 | } 358 | 359 | public static int[][][] transpose(int[][][] array, int[] dims) { 360 | if (dims.length!=3) { 361 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 362 | } 363 | 364 | int[] sizes = new int[]{array.length, array[0].length, array[0][0].length}; 365 | int[][][] result = new int[sizes[dims[0]]][sizes[dims[1]]][sizes[dims[2]]]; 366 | for (int i = 0; i < sizes[0]; i++) { 367 | for (int j = 0; j < sizes[1]; j++) { 368 | for (int k = 0; k < sizes[2]; k++) { 369 | int[] dim_indices = new int[]{i,j,k}; 370 | result[dim_indices[dims[0]]][dim_indices[dims[1]]][dim_indices[dims[2]]] = array[i][j][k]; 371 | } 372 | } 373 | } 374 | return result; 375 | } 376 | 377 | public static int[][][][] transpose(int[][][][] array, int[] dims) { 378 | if (dims.length!=4) { 379 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 380 | } 381 | 382 | int[] sizes = new int[]{array.length, array[0].length, array[0][0].length, array[0][0][0].length}; 383 | int[][][][] result = new int[sizes[dims[0]]][sizes[dims[1]]][sizes[dims[2]]][sizes[dims[3]]]; 384 | for (int i = 0; i < sizes[0]; i++) { 385 | for (int j = 0; j < sizes[1]; j++) { 386 | for (int k = 0; k < sizes[2]; k++) { 387 | for (int l = 0; l < sizes[3]; l++) { 388 | int[] dim_indices = new int[]{i,j,k,l}; 389 | result[dim_indices[dims[0]]][dim_indices[dims[1]]][dim_indices[dims[2]]] 390 | [dim_indices[dims[3]]] = array[i][j][k][l]; 391 | } 392 | } 393 | } 394 | } 395 | 396 | return result; 397 | } 398 | 399 | public static int[][][][][] transpose(int[][][][][] array, int[] dims) { 400 | if (dims.length!=5) { 401 | throw new IllegalArgumentException("The dims given are not consistant with the array's dimensions."); 402 | } 403 | 404 | int[] sizes = new int[]{array.length, array[0].length, array[0][0].length, array[0][0][0].length, array[0][0][0][0].length}; 405 | int[][][][][] result = new int[sizes[dims[0]]][sizes[dims[1]]][sizes[dims[2]]][sizes[dims[3]]][sizes[dims[4]]]; 406 | for (int i = 0; i < sizes[0]; i++) { 407 | for (int j = 0; j < sizes[1]; j++) { 408 | for (int k = 0; k < sizes[2]; k++) { 409 | for (int l = 0; l < sizes[3]; l++) { 410 | for (int m = 0; m < sizes[4]; m++) { 411 | int[] dim_indices = new int[]{i,j,k,l,m}; 412 | result[dim_indices[dims[0]]][dim_indices[dims[1]]][dim_indices[dims[2]]] 413 | [dim_indices[dims[3]]][dim_indices[dims[4]]] = array[i][j][k][l][m]; 414 | } 415 | } 416 | } 417 | } 418 | } 419 | 420 | return result; 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /src/ndCommon/CommonMisc.java: -------------------------------------------------------------------------------- 1 | package ndCommon; 2 | 3 | import java.math.BigDecimal; 4 | import java.math.RoundingMode; 5 | 6 | public class CommonMisc { 7 | 8 | public CommonMisc() {} 9 | 10 | public static double round(double value, int places) { 11 | if (places < 0) throw new IllegalArgumentException(); 12 | 13 | BigDecimal bd = BigDecimal.valueOf(value); 14 | bd = bd.setScale(places, RoundingMode.HALF_UP); 15 | return bd.doubleValue(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ndCommon/DoubleArrayIndexComparator.java: -------------------------------------------------------------------------------- 1 | package ndCommon; 2 | 3 | import java.util.Comparator; 4 | 5 | public class DoubleArrayIndexComparator implements Comparator 6 | { 7 | private final double[] array; 8 | private final boolean reverse; 9 | 10 | public DoubleArrayIndexComparator(double[] array, boolean reverse) 11 | { 12 | this.reverse = reverse; 13 | this.array = array; 14 | } 15 | 16 | public DoubleArrayIndexComparator(double[] array) 17 | { 18 | this.reverse = false; 19 | this.array = array; 20 | } 21 | 22 | public Integer[] createIndexArray() 23 | { 24 | Integer[] indexes = new Integer[array.length]; 25 | for (int i = 0; i < array.length; i++) 26 | { 27 | indexes[i] = i; // Autoboxing 28 | } 29 | return indexes; 30 | } 31 | 32 | @Override 33 | public int compare(Integer index1, Integer index2) 34 | { 35 | if (array[index1]==(array[index2])) { 36 | return 0; 37 | } else if (array[index1]<(array[index2])) { 38 | return this.reverse?1:-1; 39 | } else { 40 | return this.reverse?-1:1; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ndCommon/StringArrayIndexComparator.java: -------------------------------------------------------------------------------- 1 | package ndCommon; 2 | 3 | import java.util.Comparator; 4 | 5 | public class StringArrayIndexComparator implements Comparator 6 | { 7 | private final String[] array; 8 | private final boolean reverse; 9 | 10 | public StringArrayIndexComparator(String[] array, boolean reverse) 11 | { 12 | this.reverse = reverse; 13 | this.array = array; 14 | } 15 | 16 | public StringArrayIndexComparator(String[] array) 17 | { 18 | this.reverse = false; 19 | this.array = array; 20 | } 21 | 22 | public Integer[] createIndexArray() 23 | { 24 | Integer[] indexes = new Integer[array.length]; 25 | for (int i = 0; i < array.length; i++) 26 | { 27 | indexes[i] = i; // Autoboxing 28 | } 29 | return indexes; 30 | } 31 | 32 | @Override 33 | public int compare(Integer index1, Integer index2) 34 | { 35 | // Autounbox from Integer to int to use as array indexes 36 | if (this.reverse) { 37 | return -array[index1].compareTo(array[index2]); 38 | } else { 39 | return array[index1].compareTo(array[index2]); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/tests/testCommonMath.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import ndArray.NdCommonMathFunc; 4 | import ndArray.NdMath; 5 | import ndArray.NdUtils; 6 | 7 | import java.util.Arrays; 8 | 9 | public class testCommonMath { 10 | 11 | public static void main(String[] args) { 12 | double[] a = new double[]{0.25, 0.5, 2}; 13 | NdCommonMathFunc.softmax(a); 14 | NdUtils.printNdArray(a); 15 | 16 | a = new double[]{0.25, 0.5, -2000000}; 17 | NdCommonMathFunc.softmax(a); 18 | NdUtils.printNdArray(a); 19 | 20 | a = new double[]{0.25, 0.5, 2000000}; 21 | NdCommonMathFunc.softmax(a); 22 | NdUtils.printNdArray(a); 23 | 24 | a = new double[]{0.25, 0.5, Double.NaN}; 25 | NdUtils.printNdArray(a); 26 | NdMath.replaceNanWith(a, 1); 27 | NdUtils.printNdArray(a); 28 | 29 | a = new double[]{0.25, 0.5, 0.3}; 30 | ndCommon.DoubleArrayIndexComparator comparator = new ndCommon.DoubleArrayIndexComparator(a); 31 | Integer[] indices = comparator.createIndexArray(); 32 | Arrays.sort(indices, comparator); 33 | for (int i : indices) { 34 | System.out.println(i); 35 | } 36 | 37 | System.out.println("---------"); 38 | 39 | comparator = new ndCommon.DoubleArrayIndexComparator(a, true); 40 | indices = comparator.createIndexArray(); 41 | Arrays.sort(indices, comparator); 42 | for (int i : indices) { 43 | System.out.println(i); 44 | } 45 | 46 | System.out.println("---------"); 47 | 48 | String[] sa = new String[]{"mother", "faker", "fucker", "idiot"}; 49 | ndCommon.StringArrayIndexComparator scomparator = new ndCommon.StringArrayIndexComparator(sa); 50 | indices = scomparator.createIndexArray(); 51 | Arrays.sort(indices, scomparator); 52 | for (int i : indices) { 53 | System.out.println(i); 54 | } 55 | 56 | System.out.println("---------"); 57 | 58 | scomparator = new ndCommon.StringArrayIndexComparator(sa, true); 59 | indices = scomparator.createIndexArray(); 60 | Arrays.sort(indices, scomparator); 61 | for (int i : indices) { 62 | System.out.println(i); 63 | } 64 | 65 | System.out.println("---------"); 66 | 67 | System.out.println(ndCommon.CommonMisc.round(200.3456, 2)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/tests/testFilters.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import ndArray.NdMath; 4 | import ndArray.NdUtils; 5 | 6 | public class testFilters { 7 | 8 | public static void main(String[] args) { 9 | // ArrayList a = ndArray.Filters.sobel2d(2); 10 | // utils.Printer.print2dArray(a.get(0)); 11 | // System.out.println(); 12 | // utils.Printer.print2dArray(a.get(1)); 13 | 14 | //////// 分割线 //////// 分割线 //////// 分割线 //////// 15 | 16 | // double[][] a = ndArray.Filters.laplacian2d3(); 17 | // utils.Printer.print2dArray(a); 18 | 19 | //////// 分割线 //////// 分割线 //////// 分割线 //////// 20 | 21 | // double[][] a = ndArray.Filters.gaussian2d(2,1); 22 | // double[] b = ndArray.Filters.gaussian1d(2,1); 23 | // utils.Printer.print2dArray(a); 24 | // System.out.println(); 25 | // 26 | // double[] a2 = a[2]; 27 | // double _sum = 0; 28 | // for (int i = 0; i < a2.length; i++) { 29 | // _sum += a2[i]; 30 | // } 31 | // for (int i = 0; i < a2.length; i++) { 32 | // a2[i] /= _sum; 33 | // } 34 | // utils.Printer.print1dArray(b); 35 | // utils.Printer.print1dArray(a[2]); 36 | // utils.Printer.print1dArray(a2); 37 | // 38 | // ////// 分割线 //////// 分割线 //////// 分割线 //////// 39 | // 40 | // double[][] array = new double[][]{ 41 | // new double[]{1.0, 2.0, 3.0, 4.0, 5.0}, 42 | // new double[]{1.5, 2.5, 3.5, 4.5, 5.5}, 43 | // new double[]{2.0, 3.0, 4.0, 5.0, 6.0}, 44 | // new double[]{2.5, 3.5, 4.5, 5.5, 6.5}, 45 | // new double[]{3.0, 4.0, 5.0, 6.0, 7.0}, 46 | // }; 47 | // 48 | // double[][] filter = new double[][]{ 49 | // new double[]{0.5, 1.5, 0.5}, 50 | // new double[]{1.0, 2.0, 1.0}, 51 | // new double[]{0.5, 1.5, 0.5}, 52 | // }; 53 | // 54 | // double[][] result = NdMath.convolve(array, filter); 55 | // utils.Printer.print2dArray(result); 56 | // 57 | // System.out.println(); 58 | // 59 | // result = NdMath.convolve(array, filter, true); 60 | // utils.Printer.print2dArray(result); 61 | // 62 | // System.out.println(); 63 | // 64 | // array = new double[][]{ 65 | // new double[]{1.0, 2.0, 3.0, 4.0}, 66 | // new double[]{1.5, 2.5, 3.5, 4.5}, 67 | // new double[]{2.0, 3.0, 4.0, 5.0}, 68 | // new double[]{2.5, 3.5, 4.5, 5.5}, 69 | // }; 70 | // 71 | // filter = new double[][]{ 72 | // new double[]{0.5, 1.0, 1.0, 0.5}, 73 | // new double[]{0.5, 1.0, 1.0, 0.5}, 74 | // }; 75 | // 76 | // result = NdMath.convolve(array, filter); 77 | // utils.Printer.print2dArray(result); 78 | // 79 | // System.out.println(); 80 | // 81 | // result = NdMath.convolve(array, filter, true); 82 | // utils.Printer.print2dArray(result); 83 | 84 | //////// 分割线 //////// 分割线 //////// 分割线 //////// 85 | 86 | double[][][][] aa = new double[3][2][5][4]; 87 | aa[0][1][0][1] = 15; 88 | double[][][][] ba = NdUtils.transpose(aa, new int[]{0,2,1,3}); 89 | System.out.println(aa[0][1][0][1]+","+ba[0][1][0][1]+","+ba[0][0][1][1]); 90 | System.out.println(ba.length+","+ba[0].length+","+ba[0][0].length+","+ba[0][0][0].length); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/tests/testIO.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import ndArray.NdImageIO; 4 | import ndArray.NdImagePro; 5 | import ndArray.NdMath; 6 | import ndArray.NdUtils; 7 | 8 | import java.util.ArrayList; 9 | 10 | public class testIO { 11 | 12 | public static void main(String[] args) { 13 | // int[][] _input = new int[][]{new int[]{1,2,3}, new int[]{1,2}, new int[]{1,2,3}}; 14 | // ArrayList _output = ndArray.NdUtils.flatten(_input); 15 | // for (int i = 0; i < _output.size(); i++) { 16 | // System.out.println(_output.get(i)); 17 | // } 18 | // 19 | // System.out.println(NdMath.mean(_output)); 20 | 21 | //////// 分割线 //////// 分割线 //////// 分割线 //////// 22 | 23 | // double[] a = new double[]{1,2,3}; 24 | // System.out.println(a.getClass().getComponentType()); 25 | // System.out.println(a.getClass().getComponentType().equals(double.class)); 26 | 27 | //////// 分割线 //////// 分割线 //////// 分割线 //////// 28 | 29 | // double[][] _input = new double[][]{new double[]{1,2,3,4}, new double[]{1,2,3,4}, new double[]{1,2,3,4}}; 30 | // double[][][] _output = new double[2][3][2]; 31 | // NdUtils.reshape(_input, _output); 32 | // NdUtils.printNdArray(NdUtils.shape(_output)); 33 | // NdUtils.printNdArray(_output); 34 | // System.out.println(); 35 | // double[][][] _output2 = new double[2][3][2]; 36 | // NdUtils.printNdArray(_output2); 37 | // System.out.println(); 38 | // NdUtils.copyArray(_output, _output2); 39 | // NdUtils.printNdArray(_output2); 40 | 41 | //////// 分割线 //////// 分割线 //////// 分割线 //////// 42 | 43 | // String path = "lily.jpeg"; 44 | // int[][][] img = NdImageIO.readImage(path, "chw"); 45 | // img = NdImagePro.resize(img, 256, 256, "chw"); 46 | // NdImageIO.writeImage("lily_resize.jpg", img, "chw"); 47 | // double[][][] img_d = NdUtils.cast(img); 48 | // NdUtils.printNdArray(ndArray.NdUtils.shape(img_d)); 49 | // System.out.println(NdMath.max(img_d)); 50 | // NdUtils.printNdArray(img_d); 51 | // 52 | // double[][][] lap_result = new double[][][]{ 53 | // ndArray.NdMath.convolve(img_d[0], ndArray.Filters.laplacian2d3_nine()), 54 | // ndArray.NdMath.convolve(img_d[1], ndArray.Filters.laplacian2d3_nine()), 55 | // ndArray.NdMath.convolve(img_d[2], ndArray.Filters.laplacian2d3_nine()), 56 | // }; 57 | // 58 | // double[][][] _abs = new double[lap_result.length][lap_result[0].length][lap_result[0][0].length]; 59 | // NdUtils.copyArray(lap_result, _abs); 60 | // NdMath.ndAbs(_abs); 61 | // double _max = NdMath.max(_abs); 62 | // 63 | // // 归一化 64 | // System.out.println(NdMath.min(lap_result)+","+NdMath.max(lap_result)); 65 | // NdMath.elementwiseDivide(lap_result, _max); 66 | // NdMath.ndAbs(lap_result); 67 | // System.out.println(NdMath.min(lap_result)+","+NdMath.max(lap_result)); 68 | // NdUtils.printNdArray(ndArray.NdUtils.shape(lap_result)); 69 | // 70 | // // 变成一个 channel 71 | // double[][] lap_result_reduce = NdMath.reduce(lap_result); 72 | // System.out.println(NdMath.min(lap_result_reduce)+","+NdMath.max(lap_result_reduce)); 73 | // NdUtils.printNdArray(ndArray.NdUtils.shape(lap_result_reduce)); 74 | // 75 | // // 映射: 0.0-1.0 至 0-255 76 | // NdMath.elementwiseMultiply(lap_result_reduce, 255); 77 | // System.out.println(NdMath.min(lap_result_reduce)+","+NdMath.max(lap_result_reduce)); 78 | // NdImageIO.writeImage("lily_p.jpg", lap_result_reduce, "hw"); 79 | 80 | //////// 分割线 //////// 分割线 //////// 分割线 //////// 81 | 82 | String path = "lily.jpeg"; 83 | int[][][] img = NdImageIO.readImage(path, "chw"); 84 | img = NdImagePro.rotate(img, 30, "chw"); 85 | NdImageIO.writeImage("lily_rotate.jpg", img, "chw"); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/tests/testMatrix.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import ndArray.NdMath; 4 | import ndArray.NdUtils; 5 | 6 | public class testMatrix { 7 | 8 | public static void main(String[] args) { 9 | double[][] a = new double[][]{new double[]{3,2,1},new double[]{3,2,1},}; 10 | double[][] b = new double[][]{new double[]{2,1},new double[]{1,0},new double[]{-1,-2},}; 11 | double[][] c = NdMath.dot(a,b); 12 | NdUtils.printNdArray(a); 13 | System.out.println(); 14 | NdUtils.printNdArray(b); 15 | System.out.println(); 16 | NdUtils.printNdArray(c); 17 | System.out.println(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/tests/testStraighten.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import ndArray.Lab; 4 | import ndArray.NdImageIO; 5 | import ndArray.NdImagePro; 6 | 7 | public class testStraighten { 8 | 9 | public static void main(String[] args) { 10 | String path = "inclined.jpeg"; 11 | int[][][] img = NdImageIO.readImage(path, "chw"); 12 | double angle = Lab.straighten_legacy(img, "chw"); 13 | System.out.println(angle); 14 | img = NdImagePro.rotate(img, angle, "chw"); 15 | NdImageIO.writeImage("inclined_rotate.jpg", img, "chw"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chenmingxiang110/J4darrays/bb47137536a1f40eaaa720df8349f2b478ffd080/test.jpeg --------------------------------------------------------------------------------