Moving statue of David Foster Wallace

I’m experimenting with adding different types of animated noise to static images to create an illusion of movement. Nothing very successful so far, but I’m enjoying the periodic modulation of the pixelation effect on this picture of David Foster Wallace. I’m just making a snapshot of this experiment now so that I can return to it later.

Click on the gif below to view it at full size. The original image is included below the code.

//
// pixelator.c - a funny kinda pixelator
// Written by Ted Burke - 11-11-2019
//
// This program loads an image from a PNM file ("dfw1280.pnm"),
// then outputs a series of images, each of which is a "pixelated"
// version of the original. The pixelation process consists of
// iterating through every pixel in the image in random order,
// replacing each one with a dot of the same colour, but of
// random size at the same x,y location. The maximum dot size
// varies from frame to frame.
//
// To compile:
//
//    gcc -o pixelator pixelator.c -lm
//
// To combine frames into a single gif using ImageMagick:
//
//    convert -loop 0 -delay 12 frame* dfw.gif
//

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define W 1280
#define H 842

// Pixel buffers for input and output images
unsigned char pi[H][W][3];
unsigned char po[H][W][3];

// An array of these stuctures is used to store the image pixels
// in a sortable form. When the order of the pixels is shuffled,
// each pixel in the array remembers its colour and x,y position.
typedef struct pixel
{
    int x;
    int y;
    int z;
    unsigned char r;
    unsigned char g;
    unsigned char b;
} Pixel;

Pixel px[W*H];

// This function is used by qsort to sort the pixels by z order
int zcompare(const void *p1, const void *p2)
{
    if (((const Pixel *)p1)->z > ((const Pixel *)p2)->z) return 1;
    else if (((const Pixel *)p1)->z < ((const Pixel *)p2)->z) return -1;
    return 0;
}

// This function renders a dot of specified size and color at
// the specified location in the output image pixel buffer 
void dot(int cx, int cy, int rad, unsigned char r, unsigned char g, unsigned char b)
{
    int x, y, rad2;
    
    rad2 = rad*rad; // radius squared
    
    for (y=cy-rad ; y<=cy+rad ; ++y) for (x=cx-rad ; x<=cx+rad ; ++x)
    {
        if (y>=0 && y<H && x>=0 && x<W && ((x-cx)*(x-cx)+(y-cy)*(y-cy))<=rad2)
        //if (y>=0 && y<H && x>=0 && x<W) // square dots
        {
            po[y][x][0] = r;
            po[y][x][1] = g;
            po[y][x][2] = b;
        }
    }
}

int main()
{
    int t, n, x, y, T=32;
    char buf[1024];
    char filename[256];
    const char input_filename[] = "dfw1280.pnm";
    FILE *f;
    
    // Read image from file
    fprintf(stderr, "Reading %s...", input_filename);
    f = fopen(input_filename, "r");
    for (n=0 ; n<3 ; ++n) fscanf(f, "%[^\n]\n", buf); // PNM header
    fread(pi, 3, W*H, f); // pixel data
    fclose(f);
    fprintf(stderr, "done\n");
    
    // Randomise pixel order
    for (y=0 ; y<H ; ++y) for (x=0 ; x<W ; ++x)
    {
        n = y*W + x;
        px[n].x = x;
        px[n].y = y;
        px[n].z = rand(); // assign random z order
        px[n].r = pi[y][x][0];
        px[n].g = pi[y][x][1];
        px[n].b = pi[y][x][2];
    }
    
    for (t=0 ; t<T ; ++t)
    {
        // Shuffle z order of pixels
        for (n=0 ; n<W*H ; ++n) px[n].z = rand();
        qsort(px, W*H, sizeof(Pixel), zcompare);
        
        // Modify image
        for (n=0 ; n<W*H ; ++n)
        {
            // Draw a random sized dot at the current pixel location
            dot(px[n].x, px[n].y, rand()%((int)(7.0+2.0*sin(t*2.0*M_PI/T))), px[n].r, px[n].g, px[n].b);
        }
        
        // Write image to file
        sprintf(filename, "frame%03d.pnm", t);
        fprintf(stderr, "Writing %s...", filename);
        f = fopen(filename, "w");
        fprintf(f, "P6\n%d %d\n255\n", W, H);
        fwrite(po, 3, W*H, f);
        fclose(f);
        fprintf(stderr, "done\n");
    }
}

The program requires the input image in PNM format. I converted the above PNG image to PNM format using ImageMagick’s convert command:

convert dfw1280.png dfw1280.pnm
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s