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