javaimagegraphicspixelwarp

Java, fast image warping according to own function


I am going to warp an image according to the user-defined function in Java. In general, the image is relatively large (JPEG, 30-50 MB).

Initially, the image is loaded:

BufferedImage img = ImageIO.read("image.jpg");

Suppose [X,Y] to be the resampled pixel coordinates of the image,where [x,y] represent its pixel coordinates.

The coordinate function is (a simple example) written as follows:

X = y * cos(x);
Y = x;

My idea is to use pixel-by-pixel transformation:

//Get size of the raster
int width = img.getWidth(), height = img.getHeight();
int proj_width =  (int)(width * Math.cos(height*Math.pi/180)),proj_height = height;

 //Create output image
 BufferedImage img2 = new BufferedImage(proj_width+1, proj_height+1, img.getType());

 //Reproject raster
 for (int i = 0; i < img.getWidth(); i++) {
      for (int j = 0; j < img.getHeight(); j++) {

            //Color of the pixel
            int col = img.getRGB(i, j);

            //Its new coordinates
            int X = (int)(i * Math.cos(j*Math.pi/180));
            int Y = j;

            //Set X,Y,col to the new raster
            img2.setRGB(X,Y,col);                 
       } 
  }

Is there any faster way to realize this operation without any additional library?

For example using the warpRect() method in the Warp class...

Thanks for your help.


Solution

  • Using get/setRGB() is basically the easiest, but also possibly slowest way of copying a pixel in the Java2D API. This is because the value for each pixel has to be converted from its native representation into a packed 32 bit ARGB format in the sRGB color space (and back again for the setRGB() method)..

    As you don't really care what the native pixel data looks like in your case, using (Writable)Raster and its get/setDataElements() method is likely to be faster (how much faster depends on the BufferedImage type):

    // Reproject raster
    Object pixel = null;
    
    Raster from = img.getRaster();
    WritableRaster to = img2.getRaster(); // Assuming img2.getType() == img.getType() always
    
    for (int y = 0; y < img.getHeight(); y++) {
        for (int x = 0; x < img.getWidth(); x++) {
            // Color of the pixel
            pixel = from.getDataElements(x, y, pixel);
    
            // Its new coordinates
            int X = (int) (x * Math.cos(y * Math.pi/180));
            int Y = y;
    
            // Set X,Y,pixel to the new raster
            to.setDataElements(X, Y, pixel);                 
       } 
    

    }

    Note that I also changed the nested loops to iterate over width in the inner loop. This is likely to give better performance due to data locality and caching in normal CPUs.