| the complete webmaster | ||||
| tutorials | reviews | reference | ||
|
Animation through Image ProcessingIntroductionAnimation is one of the most attractive features that have made web technologies play a major marketing role. Through the use of animated banners and fancy designs, it can immediately draw people's attention. Most of the existing animation applets achieve this effect either by playing a specified sequence of images (including animated GIFs) or by transforming graphic objects. The former poses some problems when you need disk storage for a long sequence of images, while the latter lacks in the ability to deal with real-life photos. What if we just take one single input picture and animate it using image processing techniques performed at real-time? This way we can build on-the-fly intermediate image frames without taking up too much disk space. With the widely used double buffering animation technique, we can actually demonstrate this can produce satisfactory results, as seen in our examples. We are going to start by explaining some fundamental animation techniques and then we will see how we can use image processing concepts to generate creative visual effects. A template animation program will be developed and it will serve as a re-usable applet in the future. A couple of examples will be illustrated according to our proposed approach. More interesting possibilities of turning image processing algorithms into animation applets can be found in my another package, Raster Image Exploring Lab (RIEL), with 80+ image programs available at http://www.cis.udel.edu/~cliu/sw.html. Animation FundamentalsFigure 1 shows that even a simple tint-angle adjustment program can produce a pleasant color changing visual effect through animation. We start with some basics on animation behind the scene, in a general sense. In order to emulate motion, some common concepts are introduced as to achieve this goal. Double buffering is used to prepare a duplicate off-screen graphics object, which mainly shows the change from the previous frame and is drawn only when it is completely ready. This is done in order to reduce screen flickering. Delay between two adjacent image frames is used to control how long you will want a frame to stay unchanged on the screen. Usually, you will use two schemes to generate parameter values for your image processing programs to stay in action. One involves generating numbers randomly, through a system call, while the other consider s a stepsize to control the animation cycle. Of course, the smaller the stepsize is, the smoother the motion will appear on the screen. Java has a special multithread mechanism. A thread is a sequence of code executing within the context of an active program. We also need this to keep track of painting activities as to have total control of when to refresh the screen.Figure 1: Animation by adjusting the tint angle (click on image) A Template Animation Applet and Its UsageNow, we are going to put into practice the fundamentals from the previous section. Since this article is Java-specific, I will start with a template animation applet as in Figure 2. In init(), we basically read an input image and set its dimensions, width and height. In addition, we store image pixels into an array variable, data. Reading parameters from the specified HTML file is done here. We will provide a sample HTML file later. oimg and og are used in double buffering for off-screen image and graphics. Variable t is for thread control and I think you'll probably never need to change anything in this variable. waitForImage() uses a media tracker to load an image file. red(), green(), blue(), and setRGB() are access methods for individual color components. mouseDown() is used to pause and restart the animation. This is a re-usable applet. To customize it, you only need to modify program variables in the declaration program(), parameters in init() and loop control in run(). Otherwise, they are already pre-set for a well-behaved animation applet. A typical HTML file will contain a code segment as in Figure 3, setting all parameters. public class anitint extends java.applet.Applet implements Runnable
{
// general setup
Thread t = null;
boolean suspended = false;
String infile;
Image photo, oimg;
Graphics og;
int width, height;
MediaTracker tracker;
// program variables
int tintAngle = 0;
int step = 20;
int delay = 100;
static int [] data;
static int [] dataNew;
public void init()
{
super.init();
// read params
infile = getParameter("file");
delay = new Integer(getParameter("delay")).intValue();
step = new Integer(getParameter("step")).intValue();
// read infile and save into an array
tracker = new MediaTracker(this);
photo = getImage(getDocumentBase(), infile);
tracker.addImage(photo, 0);
waitForImage();
width = photo.getWidth(this);
height = photo.getHeight(this);
resize(width, height);
data = new int[height * width];
dataNew = new int[height * width];
grabPixels();
buildImage();
// double buffering
oimg = createImage(width, height);
og = oimg.getGraphics();
}
public void start()
{
if (t == null)
{
t = new Thread(this);
t.start();
}
}
public void stop()
{
if (t != null && t.isAlive())
t.stop();
t = null;
}
public void run()
{
Thread.currentThread().setPriority(Thread.NORM_PRIORITY - 1);
while (true)
{
repaint();
try
{
Thread.sleep(delay);
}
catch (InterruptedException e) {}
// program execution and var setup for next frame
program();
tintAngle += step;
if (tintAngle 180)
tintAngle = -180;
}
}
public void update(Graphics g)
{
paint(g);
}
public void paint(Graphics g)
{
if (photo != null)
{
og.drawImage(photo, 0, 0, this);
g.drawImage(oimg, 0, 0, this);
}
}
// real program starts here
private void program()
{
}
// use mouse to toggle animation
public boolean mouseDown(java.awt.Event evt, int x, int y)
{
if (suspended)
t.resume();
else
t.suspend();
suspended = !suspended;
return true;
}
// build an image for displaying
private void buildImage()
{
photo = createImage(new MemoryImageSource(width, height, dataNew,
0, width));
}
// grab pixels into a 1D array
private void grabPixels()
{
PixelGrabber imagegrabber;
imagegrabber = new PixelGrabber(photo, 0, 0, width, height,
data, 0, width);
try
{
imagegrabber.grabPixels();
}
catch(InterruptedException e) {}
}
// R G B access methods
public int red(int y, int x)
{
return ((data[y * width + x] & 0x00FF0000) 16);
}
public int green(int y, int x)
{
return ((data[y * width + x] & 0x0000FF00) 8);
}
public int blue(int y, int x)
{
return (data[y * width + x] & 0x000000FF);
}
public void setRGB(int y, int x, int R, int G, int B)
{
dataNew[y * width+x] = (new Color(R, G, B)).getRGB();
}
// dimensions
public Dimension minimizeSize()
{
return new Dimension(width, height);
}
public Dimension preferredSize()
{
return new Dimension(width, height);
}
// wait while loading an image
private void waitForImage()
{
while (!tracker.checkID(0, true))
{
try
{
Thread.sleep(20);
}
catch(Exception e) {}
}
}
}
Figure 2: A template animation applet <html>
<body>
<applet code=anitint.class width=100 height=100>
<param name=file value=test.gif>
<param name=delay value=20>
<param name=step value=20>
</applet>
</body>
</html>
Figure 3: A typical code segment in a HTML file
Adding An Image Processing AlgorithmIn Figure 2, the placeholder program() is reserved for your own implementation of an image processing algorithm. We give one simple example here, which adjusts the tint angle of a color, in Figure 4. The definition of the formula can be seen in most image processing references. The purpose of this example is to demonstrate what we can choose as the animation variables. Since there is only one control parameter, i.e., the tint angle tintAngle, we can control its animation by using a smooth cycle with a fixed stepsize or by using a random cycle with a system-generated stepsize, applied to tintAngle. After finishing the calculation, we need to create and refresh the screen as in buildImage(). private void program()
{
double angle = (3.14159d * (double)tintAngle) / 180.0d;
int S = (int)(256.0d * Math.sin(angle));
int C = (int)(256.0d * Math.cos(angle));
int RY, GY, BY, RYY, GYY, BYY, R, G, B, Y;
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
{
RY = (70 * red(y,x) - 59 * green(y,x)
-11 * blue(y,x)) / 100;
GY = (-30 * red(y,x) + 41 * green(y,x)
-11 * blue(y,x)) / 100;
BY = (-30 * red(y,x) - 59 * green(y,x)
+ 89 * blue(y,x)) / 100;
Y = (30 * red(y,x) + 59 * green(y,x)
+ 11 * blue(y,x)) / 100;
RYY = (S * BY + C * RY) / 256;
BYY = (C * BY - S * RY) / 256;
GYY = (-51 * RYY - 19 * BYY) / 100;
R = Y + RYY; if (R < 0) R = 0; if (R 255) R = 255;
G = Y + GYY; if (G < 0) G = 0; if (G 255) G = 255;
B = Y + BYY; if (B < 0) B = 0; if (B 255) B = 255;
setRGB(y, x, R, G, B);
}
buildImage();
}
Figure 4: The tint program
ExamplesFigure 5: anilayer (click on image) We provide two more examples, anilayer and aniconv, just to give you a feel of how these simple algorithms can be put into action. In Figure 5, anilayer keeps changing its rotation angle and size, which makes the image seem to be vanishing/approaching. In Figure 6, we randomly pick a location of the picture and then 'blow it up'. Figure 6: aniconv (click on image)
ConclusionThe main purpose of this article is just to show you a few of the many possibilities in animation, in contrast to most others using image sequence input and graphic object manipulation. Those methods have their limitations and special storage requirements. More and more animation flavors can be created using real-time image processing. As long as you get a chance to have a better understanding of how this works, there are lots of imaging algorithms out there you can use. We have provided a template for this purpose. Web technologies, especially Java, have already had a major impact not only in academic areas, but also in industries. You can expect more activities on the web using Java. Next time, I will talk about a less technical but more general topic on web graphics and images. NEXT: A General Introduction of Using Graphics and Images on the Web
Author: Chunyen Liu
More articles about Java |
| write for us | about us | advertise |
Copyright 1997, 1998 A Big Lime. All rights reserved.