Generating moderately interesting images
- by Williham Totland
Abstract: Can you propose a mathematical-ish algorithm over a plane of pixels that will generate a moderately interesting image, preferably one that on the whole resembles something?
The story thus far:
Once upon a time I decided in an effort to reduce cycle waste on my (admittedly too) numerous computers, and set out to generate images in a moderately interesting fashion; using a PRNG and some clever math to create images that would, on the whole, resemble something.
Or at least, that was the plan. As it turns out, clever math requires being a clever mathematician; this I am not.
At some length I arrived at a method that preferred straight lines (as these are generally the components of which our world is made), perhaps too strongly. The result is mildly interesting; resembling, perhaps, city grids as such:
Now for the question proper: Given the source code of this little program; can you improve upon it and propose a method that gives somewhat more interesting results? (e.g. not city grids, but perhaps faces, animals, geography, what have you)
This is also meant as a sort of challenge; I suppose and as such I've set down some completely arbitrary and equally optional rules:
The comments in the code says it all really. Suggestions and "solutions" should
edit the algorithm itself, not the surrounding framework, except as for to fix
errors that prevents the sample from compiling.
The code should compile cleanly with a standard issue C compiler. (If the
example provided doesn't, oops! Tell me, and I'll fix. :)
The method should, though again, this is optional, not need to elicit help from
your friendly neighborhood math library.
Solutions should probably be deliverable by simply yanking out whatever is between
the snip lines (the ones that say you should not edit above and below, respectively),
with a statement to the effect of what you need to add to the preamble in particular.
The code requires a C compiler and libpng to build; I'm not entirely confident that the MinGW compiler provides the necessities, but I would be surprised if it didn't. For Debian you'll want the libpng-dev package, and for Mac OS X you'll want the XCode tools..
The source code can be downloaded here.
Warning: Massive code splurge incoming!
// compile with gcc -o imggen -lpng imggen.c
// optionally with -DITERATIONS=x, where x is an appropriate integer
// If you're on a Mac or using MinGW, you may have to fiddle with the linker flags to find the library and includes.
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#ifdef ITERATIONS
#define REPEAT
#endif // ITERATIONS
// YOU MAY CHANGE THE FOLLOWING DEFINES
#define WIDTH 320
#define HEIGHT 240
// YOU MAY REPLACE THE FOLLOWING DEFINES AS APPROPRIATE
#define INK 16384
void writePNG (png_bytepp imageBuffer, png_uint_32 width, png_uint_32 height, int iteration) {
char *fname;
asprintf(&fname, "out.%d.png", iteration);
FILE *fp = fopen(fname, "wb");
if (!fp) return;
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, fp);
png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, PNG_FILTER_NONE);
png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_rows(png_ptr, info_ptr, imageBuffer);
png_set_invert_mono(png_ptr); /// YOU MAY COMMENT OUT THIS LINE
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
free(fname);
}
int main (int argc, const char * argv[]) {
png_uint_32 height = HEIGHT, width = WIDTH;
int iteration = 1;
#ifdef REPEAT
for (iteration = 1; iteration <= ITERATIONS; iteration++) {
#endif // REPEAT
png_bytepp imageBuffer = malloc(sizeof(png_bytep) * height);
for (png_uint_32 i = 0; i < height; i++) {
imageBuffer[i] = malloc(sizeof(png_byte) * width);
for (png_uint_32 j = 0; j < width; j++) {
imageBuffer[i][j] = 0;
}
}
/// CUT ACROSS THE DASHED LINES
/// -------------------------------------------
/// NO EDITING ABOVE THIS LINE; EXCEPT AS NOTED
int ink = INK;
int x = rand() % width, y = rand() % height;
int xdir = (rand() % 2)?1:-1;
int ydir = (rand() % 2)?1:-1;
while (ink) {
imageBuffer[y][x] = 255;
--ink;
xdir += (rand() % 2)?(1):(-1);
ydir += (rand() % 2)?(1):(-1);
if (ydir > 0) {
++y;
} else if (ydir < 0) {
--y;
}
if (xdir > 0) {
++x;
} else if (xdir < 0) {
--x;
}
if (x == -1 || y == -1 || x == width || y == height || x == y && x == 0) {
x = rand() % width; y = rand() % height;
xdir = (rand() % 2)?1:-1;
ydir = (rand() % 2)?1:-1;
}
}
/// NO EDITING BELOW THIS LINE
/// -------------------------------------------
writePNG(imageBuffer, width, height, iteration);
for (png_uint_32 i = 0; i < height; i++) {
free(imageBuffer[i]);
}
free(imageBuffer);
#ifdef REPEAT
}
#endif // REPEAT
return 0;
}
Note: While this question doesn't strictly speaking seem "answerable" as such; I still believe that it can give rise to some manner of "right" answer. Maybe.
Happy hunting.