geosolutions-it / jai-ext

Java Advanced Imaging Open Source Replacement Wannabe
Apache License 2.0
89 stars 38 forks source link

Speed up color indexer by using rect iters in place of random iters #253

Closed aaime closed 5 years ago

aaime commented 5 years ago

With a simple benchmark the production time of quantized images goes down by 12% with this change.

package it.geosolutions.jaiext.colorindexer;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.media.jai.ROIShape;

import it.geosolutions.jaiext.JAIExt;

public class QuantizerBenchmark {

    static final int LOOPS = 2000;
    public static final int THREADS = 16;

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        JAIExt.initJAIEXT();

        // Testing color indexing with ROI
        // build a transparent image
        BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_4BYTE_ABGR);
        Graphics g = image.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, 10, 10);
        g.setColor(Color.RED);
        g.fillRect(10, 0, 10, 10);
        g.setColor(Color.BLUE);
        g.fillRect(20, 0, 10, 10);
        g.setColor(Color.GREEN);
        g.fillRect(30, 0, 10, 10);
        g.dispose();

        ExecutorService executors = Executors.newFixedThreadPool(THREADS);

        List<Future<?>> futures = new ArrayList<>();
        long start = System.currentTimeMillis();
        for (int i = 0; i < THREADS; i++) {
            Future<?> future =
                    executors.submit(
                            new Runnable() {
                                @Override
                                public void run() {
                                    for (int j = 0; j < LOOPS; j++) {
                                        // palette and force data extraction
                                        RenderedImage indexed =
                                                quantize(
                                                        image,
                                                        null);
                                        indexed.getData();
                                        System.out.print(".");
                                    }

                                }
                            });
            futures.add(future);
        }
        for (Future<?> future : futures) {
            future.get();
        }
        long end = System.currentTimeMillis();
        System.out.println("Elapsed: " + (end - start) / 1000.0);
        executors.shutdown();
    }

    private static RenderedImage quantize(BufferedImage image, ROIShape roiShape) {
        Quantizer q = new Quantizer(256);
        ColorIndexer indexer = q.buildColorIndexer(image);
        RenderedImage indexed =
                ColorIndexerDescriptor.create(image, indexer, roiShape, null, null, null);
        return indexed;
    }
}

Wondering if further speedups could be achieved by using a raster accessor, or by setting up a specialized rect iter (most of the time is now spent in the iterator getPixel call:

Selezione_875

aaime commented 5 years ago

@dromagnoli I made another pass by providing optimized RectIter implementations (the based sources of which come from ImageN, so they were already Apache licensed)