Funhouse Mirror

16 Jan

This sketch shows how to do a basic funhouse mirror effect on a still image. Move the mouse over the image to warp it.

The basic idea is that we loop through all the pixels we want to draw, using the variables dx,dy to represent the coordinates of each pixel. A transformation is applied to figure out sx,sy, which are the coordinates of the image which we want to pull. Here is the basic framework.

  for (int dy = 0; dy < height; ++dy) {
    for (int dx = 0; dx < width; ++dx) {
      int sx = /* transform dy here */;
      int sy = /* transform dx here */;

      pixels[dy*width+dx] = sourceImage.pixels[sy*width+sx];

If we use a straight assignment, like so:

sx = dx;
sy = dy;

Then we will draw the source image exactly as is. The following transform flips it horizontally.

sx = (width-1)-dx;
sy = dy;

For the Funhouse mirror effect, I'm measuring the distance to the mouse, and then using it to warp sx,sy, within a circle of radius width/2. Within the circle, the closer the pixel is to the mouse, the more it is warped. I use the lerp() function to interpolate the coordinates to be closer to the mouse, creating a magnifying glass effect.

      float dMouse = dist(mouseX, mouseY, dx, dy );

      float r = map(dMouse,0,width/2,1,0);
      r = constrain(r,0,1);
      int sx = int(lerp(dx,mouseX,r));
      int sy = int(lerp(dy,mouseY,r));

It is important that both dx,dy and sx,sy be legal coordinates -- otherwise you will get a memory access violation. Notice my use of constrain. This insures that the r has a value of 0 to 1, which insures that the warped coordinates fall on a line between their original value, and the mouse position. Since the mouse position is always reported to be within the frame, this keeps the coordinates legal.

This code is a little sluggish in Processing.js, but is quite zippy in Processing. It's possible to do the same thing with the live images coming from your webcam, using the video library, without too much hassle.

No comments yet

Leave a Reply

Your email address will not be published. Required fields are marked *