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: paint.net 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
Code
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 http://marco.guardigli.it/2010/01/scanimation-builder-processing-code.html
//
// this code is Free Software, released under GNU GPL license. See www.gnu.org for license details
// copyleft Marco Guardigli
//
// email: mgua@tomware.it
// 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";
println(fname[i]);
frame[i] = loadImage(fname[i]); // read frame
frame[i].resize(xsize,ysize);
}
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.save(prjname + "_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);
}
}
maskimage.save(prjname + "_mask.png");
// prepare for on screen display of scanimage
size(maxx,maxy);
}
void draw() {
background(255);
image(scanimage,0,0);
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++) {
line(c+b,0,c+b,scanimage.height);
}
}
}
void mousePressed() { // when click shift mask
cframe = (cframe + 1) % nframes;
println("cframe=" + cframe);
}
//
// a processing sketch for generating barrier grid animations
// see http://marco.guardigli.it/2010/01/scanimation-builder-processing-code.html
//
// this code is Free Software, released under GNU GPL license. See www.gnu.org for license details
// copyleft Marco Guardigli
//
// email: mgua@tomware.it
// 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";
println(fname[i]);
frame[i] = loadImage(fname[i]); // read frame
frame[i].resize(xsize,ysize);
}
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.save(prjname + "_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);
}
}
maskimage.save(prjname + "_mask.png");
// prepare for on screen display of scanimage
size(maxx,maxy);
}
void draw() {
background(255);
image(scanimage,0,0);
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++) {
line(c+b,0,c+b,scanimage.height);
}
}
}
void mousePressed() { // when click shift mask
cframe = (cframe + 1) % nframes;
println("cframe=" + cframe);
}
// ---------------
Example
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:
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
http://animbar.mnim.org/
A scratch similar project from MIT
Related websites:
Rufus Butler Seder website (Eye Think inc)
dudecraft's blog
http://animbar.mnim.org/
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.
http://www.eyethinkinc.com/
Gent.mo 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
ReplyDeletehttp://boccalorenzo.blogspot.com
Certo che mi potrà contattare.
ReplyDeleteIn 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!
marco
OHP MEGA DEMO 9000 would not be possible without this nice sketch. Thanks!
ReplyDeleteI added a link to this post in the NFO file so others can make more. Here is the link to the video.
@Luis
ReplyDeleteThank you!!!!
your demo is GREAT!
I jumped back 20 years in time!
Share and Enjoy!
@mgua
Thank you A lot, your code works excellently, I was looking for something like that!!
ReplyDeleteMuchas gracias, Excelente trabajo.
Omar Monroy
Ciao, scusate l'imbranataggine, ma a me viene fuori la .png 'scanimata' completamente vuota: dove sbaglio??? Grazieeee
ReplyDeleteWDL