Friday, January 15, 2010

Processing code for building multi-frame animated images

Barrier Grid Animations (or Scanimations® as elsewhere referenced -see endnote-) are fun.

See this nice video by brusspup on youtube to quickly understand the concept.

I wrote a software tool to produce the picture and the related mask to see it.
the code is written in Processing. It produces the picture and the related mask.

My software basically takes a number of images as input that are to be considered the frames of the animation to be built. You can change the parameter to define how many images do you want to use. Typically you can go with 4, and 6 is probably the maximum, otherwise the animation is too dark, because the final effect reduces the image brightness sensibly.

If you use 4 frames, only 1/4 columns of pixels are visible at a given time, reducing overall brightness to 25% of the original.
If you use 6 frames, final brightness goes to 17% of the original.

As source pictures, it is best to use some high contrast pictures, for example some high contrast dark shapes on white background. I tried with photos taken from my webcam but results were quite poor.

Simple parametrization is needed in the source, to adapt to your input image sequence and output resolution.

Printing the mask transparency and the multi-frame picture
Another tricky problem can be the printing of the mask bitmap. I used a standard laser printer, and printed on A4 sized transparencies.Usually printers perform dithering and anti-aliasing and introduce their "improvements" on printed data, but for this print job we do not need any halftoning.

I performed some tests, and was not satisfacted by any of the normal printing results from standard applications. I resorted to using Adobe Photoshop, and performed image scaling multiplying the original size of the image by a integer (i multiplied by 3 my original size and kept proportions).
It is critical and important that, when scaling, you multiply the image size by an integer, so that even spacing between resulting pixel columns is used. (doing this the scaling algorithm needs not to introduce new columns via interpolation).
In the resample image option of the Image/Image-size menu, I then selected "Nearest Neighbor". This option produces no dithering or halftoning upon image resizing.
If someone know how to obtain the same result without using Photoshop, please let me know.
(july 2010 note: has a similar option which is working fine)

Of course, you need to perform scaling of the picture following exactly the same rules. Exact size proportion between pixel column width must be preserved and must be the same in the mask and in the image.

Detail view
For better understanding, here is a detail zoom of a multi-frame image portion, prepared for 6 animation frames:

And here is a corresponding detail zoom of individual pixel of the mask for 6 animation frames. You can see 1 transparent column and 5 opaque columns

To use this code you need a Processing development environment. You can download and install it from the Processing web site. It is open source and multiplatform, for Windows/Linux/Mac.
Then you create a new sketch, and paste the following code, saving the new project.
You then have to put in the sketch folder the pictures you want to create the animation from, naming each file with a name ending in a progressive digit starting from 0,1,2,3... See the source code for understanding better.

Here is the Processing code.

// scanimator
// a processing sketch for generating barrier grid animations

// see
// this code is Free Software, released under GNU GPL license. See for license details
// copyleft Marco Guardigli
//    email:
//    twitter: @mgua
//  2009 dec 20  first draft
//  2010 jan 15  1.0

int nframes = 6;
int maxx, maxy;
int cframe = 1;
int xsize=320;  //resized image
int ysize=240;

String[] fname = new String[nframes];
String prjname = "giulio";       // project name: common initial part of the input frame filenames

PImage[] frame = new PImage[nframes];            // sequence of the initial frame to process
PImage scanimage;                                // resulting multi-frame scanimage
PImage maskimage;                                // mask

void setup() {
  for (int i=0; i < nframes; i++) {              // cycle on input frames
    fname[i] = prjname + "-" + i + ".jpg";
    frame[i] = loadImage(fname[i]);              // read frame
  maxx = frame[0].width;
  maxy = frame[0].height;
  scanimage = createImage(maxx,maxy,ARGB);        // output scanimage
  for (int f = 0; f < nframes; f++) {             // cycle on input frames
    for (int c = 0; c < maxx; c += nframes ) {    // columns to keep of this frame
        for (int y = 0; y < maxy-1; y++) {        // cycle on each pixel of the column
          scanimage.pixels[maxx * y + f + c] = frame[f].pixels[maxx * y + f + c];
  } + "_scanimage.png");   // save resulting scanimage
  // mask preparation and file generation
  maskimage = createImage(maxx,maxy,RGB);
  for (int x = 0; x < maskimage.width; x += nframes ) {
    for (int y = 0; y < maskimage.height; y++ ) {
      maskimage.pixels[xsize * y + x] = color(255,255,255);
  } + "_mask.png");
  // prepare for on screen display of scanimage

void draw() {
  stroke(0);                    // draws a mask on top of the image
  for (int c = cframe; c < scanimage.width; c += nframes ) {
    for (int b=0; b < (nframes -1); b++) {

void mousePressed() {          // when click shift mask
 cframe = (cframe + 1) % nframes;
 println("cframe=" + cframe);
// ---------------

As an example, here are some webcam photos I made with my kids and the resulting mask and multi-frame image. It is a set of six frames:



And here is the processed multi-frame picture:

with the related mask

These on-screen pictures will be probably resized on your computer screen, so do not use them for printing expecting nice results, because they will probably not work.

Related websites:
  Rufus Butler Seder website (Eye Think inc)
  dudecraft's blog  
  A scratch similar project from MIT

Have fun and happy scanimaging.

Marco ( @mgua on twitter )

NOTE on copyright - added on 2010 july 27 after receiving a request from the trademark owner, resulting in removal of every occurrence of the words "scanimation" and "scanimations" in relation to my work:

Scanimation® is a federally registered trademark owned by Eye Think, Inc. and bearing U.S. Registration No. 2,614,549. The mark was federally registered in the United States on September 3, 2002.


Anonymous said... Marco, La ringrazio per queste preziose informazioni per la creazione di immagini in movimento che cercherò di applicare nelle lezioni con i miei studenti della Scuola Media. Se avrò bisogno di ulteriori spiegazioni La potrò disturbare? Lorenzo Bocca

Marco Guardigli said...

Certo che mi potrà contattare.
In qualsiasi momento.

Sono molto interessato alle sue esperienze didattiche. Anche in virtù del fatto che sono papà di due bimbi di 14 e 11 anni.

Le segnalo anche il linguaggio processing, e il fantastico prodotto arduino. (guardi le pagine relative ad alcuni miei progetti in merito).

A presto!


Luis Gonzalez said...

OHP MEGA DEMO 9000 would not be possible without this nice sketch. Thanks!

I added a link to this post in the NFO file so others can make more. Here is the link to the video.

Marco Guardigli said...


Thank you!!!!
your demo is GREAT!
I jumped back 20 years in time!

Share and Enjoy!


Kindle en Español said...

Thank you A lot, your code works excellently, I was looking for something like that!!

Muchas gracias, Excelente trabajo.

Omar Monroy

Anonymous said...

Ciao, scusate l'imbranataggine, ma a me viene fuori la .png 'scanimata' completamente vuota: dove sbaglio??? Grazieeee