Local image Transform
This program has been used to locally warp an image, by applying a sinusoidal warp to one segment of a
standard JPEG (using 8-bit color channels). This is useful for warping textures by curving them to better fit
curved objects when mapping the texture to a 3D object. This is written in Java using the NetBeans IDE.
package localimagetransform;
import java.util.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.image.ColorModel;
import java.awt.image.BufferedImage;
public class LocalTransform
{
private BufferedImage img = null;
private BufferedImage processedImg;
private BufferedImage canvas;
private int imageHeight;
private int imageWidth;
private int[] myPixels;
private int[] myProcessedPixels = null;
private int numberPixelsInOriginalImage;
private int newNumberPixels;
private boolean imageHasAlpha;
private int channels;
private int canvasColor = 0x66a30f;
/** Creates a new instance of LocalTransform */
public LocalTransform()
{
imageHeight = 0;
imageWidth = 0;
numberPixelsInOriginalImage = 0;
}
public LocalTransform(String imageFileName)
{
imageHeight = 0;
imageWidth = 0;
LoadImage(imageFileName);
myPixels = getPixels();
}
public void LoadImage(String filename)
{
try
{
img = ImageIO.read(new File(filename));
imageHeight = img.getHeight();
imageWidth = img.getWidth();
}
catch(IOException e)
{
System.err.println("Could not load graphic file!" + e.getMessage());
}
numberPixelsInOriginalImage = imageHeight*imageWidth;
ColorModel myColorModel = img.getColorModel();
imageHasAlpha = myColorModel.hasAlpha();
System.out.println("Image " + filename + " loaded");
System.out.println("Image has Alpha? " + imageHasAlpha);
//setCanvas();
}
public void setCanvas()
{
if(imageHasAlpha)
{
channels = 4;
}
else
{
channels = 3;
}
//use 8-bit color
myProcessedPixels = new int[numberPixelsInOriginalImage];
if(channels == 3)
{
for(int i = 0; i < numberPixelsInOriginalImage; i++)
{
myProcessedPixels[i] = canvasColor;
}
}
else if(channels == 4) //N.B. This has not been tested on an image with translucency yet
{
for(int i = 0; i < numberPixelsInOriginalImage; i++)
{
//set alpha
myProcessedPixels[i*4] = 255;
//set R
myProcessedPixels[(i*4)+1] = 255;
//set G
myProcessedPixels[(i*4)+2] = 0;
//set B
myProcessedPixels[(i*4)+3] = 0;
}
}
processedImg = new BufferedImage(imageWidth,imageHeight,BufferedImage.TYPE_INT_RGB);
processedImg.setRGB(0,0,imageWidth, imageHeight, myProcessedPixels, 0,imageWidth);
//Save Canvas
try
{
File outputFile = new File("canvas.jpg");
ImageIO.write(processedImg,"jpg",outputFile);
}
catch(IOException e)
{
System.err.println("Could not save image!" + e.getMessage());
}
}
public int[] setCanvas(int w, int h)
{
//use 8-bit color
newNumberPixels = w*h;
int[] myNewCanvasPixels = new int[newNumberPixels];
for(int i = 0; i < newNumberPixels; i++)
{
myNewCanvasPixels[i] = canvasColor;
}
canvas = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
canvas.setRGB(0,0,w, h, myNewCanvasPixels, 0,w);
System.out.println("Target canvas created");
//Save Canvas
try
{
File outputFile = new File("canvas.jpg");
ImageIO.write(canvas,"jpg",outputFile);
System.out.println("Target canvas saved");
}
catch(IOException e)
{
System.err.println("Could not save image!" + e.getMessage());
}
return myNewCanvasPixels;
}
public void processImage()
{
try
{
//Apply local transform
//Displace left half of image vertically down by a sine function through pi/2
//Transform parameters
int curvature = +1; //+1 or 0, -1 not fully implemented
int imageDownShift = 0;
double maxAngle = Math.PI/2; //90 degrees
//Calculate final image size required with height increase
//Set amplitude of sine displacement
int amplitude = (int)(0.4*imageHeight);
//Calculate size of final image needed for transform
int newImageWidth = imageWidth;
int newImageHeight = imageHeight + amplitude;
//Place pixels in 1D array
int[] pixel1DArray = setCanvas(newImageWidth, newImageHeight);
for(int i = 0; i < myPixels.length; i++)
{
pixel1DArray[i] = myPixels[i];
}
//Place pixels in a 2D array
int[][] tempArray = new int[imageWidth][imageHeight];
for(int y = 0; y < imageHeight; y++) //rows
{
for(int x = 0; x < imageWidth; x++) //columns = data in 1 row
{
tempArray[x][y] = myPixels[(y*imageWidth) + x];
}
}
//Flip image if needed
tempArray = horizontalFlip(imageWidth, imageHeight, tempArray);
//Expand image as needed
int[][] pixel2DArray = new int[newImageWidth][newImageHeight];
for(int y = 0; y < imageHeight; y++) //rows
{
for(int x = 0; x < imageWidth; x++) //columns = data in 1 row
{
pixel2DArray[x][y] = tempArray[x][y]; //myPixels[(y*imageWidth) + x];
}
}
for(int y = imageHeight; y < newImageHeight; y++) //rows
{
for(int x = 0; x < imageWidth; x++) //columns = data in 1 row
{
pixel2DArray[x][y] = canvasColor;
}
}
//Create 2D pixel array target buffer to hold processed pixels
int[][] temp2DArray = new int[newImageWidth][newImageHeight];
//Transform
myProcessedPixels = new int[pixel1DArray.length];
//******************* Main transform function *********************************************************************
//Apply transformation to temp2DArray row-by-row
//System.out.println(amplitude);
for(int y = 0; y < newImageHeight; y++)
{
for(int x = 0; x < newImageWidth; x++)
{
//transform left half of image only
if(y >= amplitude && x < newImageWidth/2)
{
double D;
switch(curvature)
{
//Curve up
case +1:
D = y - ( (amplitude) * Math.sin(Math.PI/2 * x/(newImageWidth-x)) );
break;
case -1:
D = y - ( (amplitude) * ( 1- Math.sin(Math.PI/2 * x/(newImageWidth-x) ) ) );
break;
case 0:
D = y;
break;
default:
D = y;
}
int Y = (int)D;
temp2DArray[x][y] = pixel2DArray[x][Y];
}
if(y >= amplitude-imageDownShift && x >= newImageWidth/2)
{
//Shift remainder of image
int Y;
switch(curvature)
{
case +1: //Move image down
Y = y-amplitude;
break;
case -1: //Move image up
Y = y + amplitude;
case 0:
Y = y;
break;
default:
Y = y;
}
temp2DArray[x][y] = pixel2DArray[x][Y];
}
if (y < amplitude)
{
if(curvature == + 1)
{
//Pack with canvas color
temp2DArray[x][y] = canvasColor;
}
}
}
}
//**********************************************************************************************************
//Load myProcessedPixels 1D array
for(int y = 0; y < newImageHeight; y++) //rows
{
for(int x = 0; x < newImageWidth; x++) //columns = data in 1 row
{
myProcessedPixels[(y*newImageWidth) + x] = temp2DArray[x][y];
}
}
//Save processed image from myProcessedPixels 1D array
saveImage(newImageWidth, newImageHeight, myProcessedPixels);
}
catch(NullPointerException e)
{
System.err.println("Could not process image - no image file loaded! " + e.getMessage());
}
}
private int[][] shiftImageUp(int w, int h, int shiftAmplitude, int[][] pixelArray)
{
int myTempArray[][] = new int[w][h];
for(int y = 0; y < h-shiftAmplitude; y++)
{
for(int x = 0; x < w; x++)
{
myTempArray[x][y] = pixelArray[x][y+shiftAmplitude];
}
}
return myTempArray;
}
private int[][] shiftImageDown(int w, int h, int shiftAmplitude, int[][] pixelArray)
{
int myTempArray[][] = new int[w][h];
for(int y = shiftAmplitude; y < h; y++)
{
for(int x = 0; x < w; x++)
{
myTempArray[x][y] = pixelArray[x][y-shiftAmplitude];
}
}
return myTempArray;
}
public int[][] horizontalFlip(int w, int h, int[][] pixelArray)
{
int[][] tempArray = new int[w][h];
for(int y = 0; y < h; y++)
{
for(int x = 0; x < w; x++)
{
tempArray[x][y] = pixelArray[x][h-y-1];
}
}
return tempArray;
}
public int[] getPixels()
{
//Initialise empty pixel array
//int numPixels = imageWidth*imageHeight;
int[] tempPixels = new int[numberPixelsInOriginalImage];
//Load pixels into array
try
{
tempPixels = img.getRGB(0,0, imageWidth, imageHeight, myPixels, 0, imageWidth);
System.out.println("Pixels loaded");
}
catch(NullPointerException e)
{
System.err.println("Could not save image!" + e.getMessage());
}
return tempPixels;
}
public void saveImage()
{
try
{
BufferedImage myImage = canvas; // set equal to canvas
myImage.setRGB(0,0,imageWidth,imageHeight,myPixels,0,imageWidth); // set equal to original image
File outputFile = new File("savedImg.jpg");
try
{
ImageIO.write(myImage,"jpg",outputFile);
}
catch(IOException e)
{
System.err.println("Could not save image!" + e.getMessage());
}
}
catch(NullPointerException e)
{
System.err.println("Could not save image - no image file loaded! " + e.getMessage());
}
}
public void saveImage(int w, int h, int[] pixelArray)
{
try
{
BufferedImage myImage = canvas; // set equal to canvas
myImage.setRGB(0,0,w,h,pixelArray,0,w);
File outputFile = new File("savedImg.jpg");
try
{
ImageIO.write(myImage,"jpg",outputFile);
}
catch(IOException e)
{
System.err.println("Could not save image!" + e.getMessage());
}
}
catch(NullPointerException e)
{
System.err.println("Could not save image - no image file loaded! " + e.getMessage());
}
}
}
package localimagetransform;
public class Main
{
/** Creates a new instance of Main */
public Main()
{
}
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
//In this case modify an image called "myImage.jpg"
LocalTransform myTransform = new LocalTransform("myImage.jpg");
myTransform.processImage();
//myTransform.saveImage();
}
}