简体   繁体   中英

Java code - compile time optimisation

I am new to programming and have programmed a java program that calculates the voronoi diagram for random points and draws it on a picture - 1080 x 1920 pixels. Here you can see the result

The problem is that it takes nearly four minutes to compile the code. Please help me with code optimization. Below you can find the code:

class Voronoi {
private static Random r;
private static KDTree<Integer> kd;
private static double[][] keys;
private static int counter;
private static int x;

public static void main(String[] args) throws IOException,
        KeySizeException, KeyDuplicateException {
    BufferedImage img = null;
    Scanner sc = new Scanner(System.in);
    x = sc.nextInt();
    // input an image

    img = ImageIO.read(new File("input.jpg"));
    // get image Height and Width
    int w = img.getWidth();
    int h = img.getHeight();
    // make array with equal size like the image and populate it with the 0
    // make an empty array and populate it
    int[][] empty = new int[h][w];
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            empty[row][col] = 0;

        }
    }
    // make a D-dimensional KD-tree
    keys = new double[x][2];
    kd = new KDTree<Integer>(2);
    ArrayList<Color> b = new ArrayList<Color>();
    int[] totalBlue = new int[x];
    int[] totalGreen = new int[x];
    int[] totalRed = new int[x];
    int[] counter_sec = new int[x];
    // Generate random centers and populate them with 1

    for (int i = 0; i < x; i++) {
        generateCentre(empty, h, w);
        // b.add(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)));

    }
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            double[] array = new double[2];
            array[0] = i;
            array[1] = j;
            Color c = new Color(img.getRGB(j, i));
            totalBlue[kd.nearest(array)] = totalBlue[kd.nearest(array)]
                    + c.getBlue();
            totalRed[kd.nearest(array)] = totalRed[kd.nearest(array)]
                    + c.getRed();
            totalGreen[kd.nearest(array)] = totalGreen[kd.nearest(array)]
                    + c.getGreen();
            // img.setRGB(j, i, b.get(kd.nearest(array)).getRGB());
            counter_sec[kd.nearest(array)] = counter_sec[kd.nearest(array)] + 1;
        }
    }
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            double[] array = new double[2];
            array[0] = i;
            array[1] = j;
            Color c = new Color(img.getRGB(j, i));
            // img.setRGB(j, i, b.get(kd.nearest(array)).getRGB());
            Color color = new Color(totalRed[kd.nearest(array)]/counter_sec[kd.nearest(array)], totalGreen[kd.nearest(array)]/counter_sec[kd.nearest(array)],totalBlue[kd.nearest(array)]/counter_sec[kd.nearest(array)]);
            img.setRGB(j, i, color.getRGB());
        }
    }
    File outputfile = new File("image.jpg");
    ImageIO.write(img, "jpg", outputfile);
    System.out.println(totalRed[0]/counter_sec[0]+" "+totalGreen[0]/counter_sec[0]+" "+totalBlue[0]/counter_sec[0]);
}

public static void generateCentre(int[][] empty, int h, int w)
        throws KeySizeException, KeyDuplicateException {
    r = new Random();
    int height = r.nextInt(h);
    int width = r.nextInt(w);
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            if (row == height && col == width && empty[height][width] == 0) {
                empty[height][width] = 1;
                keys[counter][0] = row;
                keys[counter][2] = col;
                kd.insert(keys[counter], counter);
            }/*else if (row == height && col == width
                    && empty[height][width] != 0) {
                generateCentre(empty, h, w);
            }*/
        }
    }


    System.out.println(kd.search(keys[counter]));
    if (counter < x) {
        counter++;
    }
}
}

Although I don't claim a full understanding of your code, I see one potentially large cause of slowdown:

        totalBlue[kd.nearest(array)] = totalBlue[kd.nearest(array)]
                + c.getBlue();
        totalRed[kd.nearest(array)] = totalRed[kd.nearest(array)]
                + c.getRed();
        totalGreen[kd.nearest(array)] = totalGreen[kd.nearest(array)]
                + c.getGreen();
        // img.setRGB(j, i, b.get(kd.nearest(array)).getRGB());
        counter_sec[kd.nearest(array)] = counter_sec[kd.nearest(array)] + 1;

You seem to be repeatedly calling kd.nearest(array) , which is probably not a very cheap operation. You should call that once and store it in a local variable. I would rewrite your key loop as follows:

double[] coords = new double[2];
for (int i = 0; i < h; i++) {
  for (int j = 0; j < w; j++) {
    coords[0] = i;
    coords[1] = j;
    final int nearest = kd.nearest(coords);
    final Color c = new Color(img.getRGB(j, i));
    totalBlue[nearest] += c.getBlue();
    totalRed[nearest] += c.getRed();
    totalGreen[nearest] += c.getGreen();
    counter_sec[nearest]++;
  }
}

Here I have utilized the += and ++ operators to make things shorter and more readable. I have also hoisted your coordinates array outside the loop because it can be safely reused at each iteration. This reduces GC time, but more importantly it helps CPU caches.

Apply the same changes to your second loop, where you generate the output image.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM