Real time manipulating an image to a trapezium

I want to see if I can do perspective rendering.

After much searching around on google I found http://forums.sun.com/thread.jspa?threadID=5262491
which had a basic solution. But it seemed to be slow at 500x400 images and therefore unable to be used for realtime.

I want to know if anyone knows of a quicker way using only Java2D? What about copying 1-2 pixels strips and resizing them and painting on another image?
Just wanting to know if anyone else has worked in this area before I waste many hours playing around.

The slow line of code is this:

dest.setRGB(destX, y, src.getRGB(x, y));

It is much faster if you read all pixels from a BufferedImage into an int[], do all your operations on it, and then write your int[] back into your BufferedImage in 1 operation.

If it’s a scaling operation, you could probably just use the AffineTransform class.

You can’t scale a rectangle into a trapezium

You can skew and clip two half images… not ideal though - manipulating the bits would be better (oo-er missus!)

I don’t know if manipulating pixel data is cheap enough for real-time?

If you want to do stuff like this, it might make sense to go and get a simple grasp of OpenGL. Images are drawn using 4 vertices, so it’s easy to reshape an image however you want.

Then you lose a lot of center pixels, instead of ‘scaling’ them

[quote]If you want to do stuff like this, it might make sense to go and get a simple grasp of OpenGL. Images are drawn using 4 vertices, so it’s easy to reshape an image however you want.
[/quote]
Its just a simple effect I wanted to try in my game, which the game is only Java2D.
If its too slow then I wont do it. So this is just purely for fun…

[quote]It is much faster if you read all pixels from a BufferedImage into an int[], do all your operations on it, and then write your int[] back into your BufferedImage in 1 operation.
[/quote]
Thanks. Can someone show some code to get me started? I’m not great on the pixel stuff…

Anyone know if this option will be an AffineTransform in Java 7 or so?

    private static BufferedImage createTrapezium(BufferedImage src) {

        int w = src.getWidth();
        int h = src.getHeight();
        float A = w * .1f;
        float B = w * .9f;
        //float C = 0;
        //float D = w;

        int[] pix = new int[h*w];
        int[] pix2 = new int[h*w];
        
        pix = (int[]) src.getRaster().getDataElements(0, 0,w,h,  null);
        for (int y = 0; y < h; y++) {
            int yw = y*w;
        	
        	final float y_to_h = (float) y / (float) h;
        	//float C_A = A;
        	final float C_A_offset = A* (1 - y_to_h);
        	//float offset = C_A_offset;
        	final float trapeziumLine = -C_A_offset + B + (w - B) * y_to_h;
        	final float k = trapeziumLine / w;
        	        	
            for (int x = 0; x < w; x++) {
                int destX = Math.min(w - 1, Math.round(C_A_offset + x * k));
                pix2[yw+destX] =  pix[yw+x];
 
            }
        }
        src.getRaster().setDataElements(0,0,w,h,pix2);
        return src;
    }

All right I got this. Wondering if this still can be improved?
The shape will always stay the same, and I would only render a square of it. So the top width is the would be the width of the square.

Edit:I just tried code on my game on my system, it can do it fine 30fps, but I believe it wont like slower computer so much, so any improvements will be great.

this is 9.8 times faster ;D
Plus you don’t change the original image anymore.
You need that out image in the same size as src image.
There is still some room for improvement using fixed integer math.

private void mycreateTrapezium(BufferedImage src, BufferedImage out, float f) {
		int w = src.getWidth();
		int h = src.getHeight();
		if (f < 0)
			f = 0;
		if (f >= 1)
			f = 1;
		float A = w * f;
		float B = w * (1f - f);
		int[] pix = ((DataBufferInt) src.getRaster().getDataBuffer()).getData();
		int[] pix2 = ((DataBufferInt) out.getRaster().getDataBuffer()).getData();
		for (int i = 0; i < pix2.length; i++) pix2[i] = 0; // clear the image
		for (int y = 0; y < h; y++) {
			int yw = y * w;
			float y_to_h = (float) y / (float) h;
			float C_A_offset = A * (1 - y_to_h);
			float trapeziumLine = -C_A_offset + B + (w - B) * y_to_h;
			float k = trapeziumLine / w;
			for (int x = 0; x < w; x++) {
				int destX = (int) (C_A_offset + x * k);
				pix2[yw + destX] = pix[yw + x];
			}
		}
	}

Thanks!, that does seem to do the trick nicely.
It seems only to be using 5ish% more then my original cpu usage, I believe.

Time to play around and get it ready for its release :slight_smile:

Anymore improvements are also welcome.

Seems this effect is going well, but its not totally what I wanted.
The effect I want is perspective rendering. So further away should be smaller, which atm is only getting skinnier.
I don’t want to miss strips of pixels, that’s the only way I know how to do this effect.
Any help in this area would be great.

For high quality rendering you probably have to roll your own 1D sampler, or even 2D sampler for best results. Don’t forget mipmaps for ultimate results :slight_smile:

You can also use JAI (Java Advanced Imaging) and the PerspectiveWarp class it offers. It allows you to draw any image into any 4-edges polygon. JAI also runs in Pure-Java mode, which is performing well enough on my system - up to 100fps on a 400x300 dynamically rendered image.

Thanks for that info.
I have currently just left it for now, I might convert the game over to JavaFX when its supported on Linux and use the perspective effect on that.