Blobs

This is a little program I’ve just written to generate PGM image files of random blobs like the following ones:

Binary download:

http://dl.dropbox.com/u/2482633/blobs.exe

Source code file:

http://dl.dropbox.com/u/2482633/blobs.c

//
// blobs.c - This program generates images of blobs
// Written by Ted Burke - last updated 21-11-2011
//
// To compile:
//
//		gcc -o blobs.exe blobs.c
//
// To create 20 blob images:
//
//		blobs.exe 20
//

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

// Image data is stored in 2D pixel array
int p[1000][1000];
int w=640, h=400;

#define R1 20
#define R2 20
#define R3 20
#define R4 20
#define R5 40
#define R6 40
#define R7 20
#define R8 20

#define N_min 5
#define N_max 50

// Function prototypes
void add_blob_to_image();
void clear_image();
void save_image_as(char *);

// Main function
int main(int argc, char *argv[])
{
	// Variables
	int num_files, n, x, y;
	char filename[20];

	// If used specified number of files to create,
	// store that information into num_files variable.
	if (argc > 1) num_files = atoi(argv[1]);
	else num_files = 10;

	// Seed random number generation
	srand(time(NULL));

	// Create blob image files
	n = 1;
	while(n <= num_files)
	{
		clear_image();
		add_blob_to_image();
		sprintf(filename, "image%03d.pgm", n);
		save_image_as(filename);
		n = n + 1;
	}

	// Exit normally
	return 0;
}

// Set the image to plain noisy background
void clear_image()
{
	int x, y;

	// Fill pixel array with values
	y = 0;
	while(y < h)
	{
		x = 0;
		while(x < w)
		{
			// Set pixel to a bright random value
			p[y][x] = 180 + (rand() % 60);

			x = x + 1;
		}
		y = y + 1;
	}
}

// Add a blob (solid or ring) to the image
void add_blob_to_image()
{
	// Variables
	int x, y, N;
	int ring = 0;
	int xc, yc, ir_min, ir_max, or_min, or_max;

	// Choose inner radius max and min values
	ir_min = R1 + (rand()%R2);
	ir_max = ir_min + R3 + (rand()%R4);

	// Choose outer radius max and min values
	or_min = ir_max + R5 + (rand()%R6);
	or_max = or_min + R7 + (rand()%R8);

	// Randomly choose either solid or ring
	ring = rand()%2;

	// Print object type
	if (ring)
	{
		fprintf(stderr, "Ring.... ");
	}
	else
	{
		fprintf(stderr, "Solid... ");

		// Blob is solid, so remove centre hole
		ir_min = 0;
		ir_max = 0;
	}

	// Choose blob centre point
	xc = 10 + or_max + (rand()%(w-20-2*or_max));
	yc = 10 + or_max + (rand()%(h-20-2*or_max));

	double distance, r, angle;

	// Choose number of fixed points on boundary contour
	N = N_min + (rand()%(N_max-N_min));
	double ir_vals[N+1], or_vals[N+1];

	// Print parameters for current blob
	fprintf(stderr, "N=%2d, xc=%3d, yc=%3d, ir_min=%2d, ir_max=%2d, or_min=%3d, or_max=%3d\n",
					N, xc, yc, ir_min, ir_max, or_min, or_max);

	int n;
	int i;
	double di;
	double ir, or; // inner and outer radius at a particular angle

	// Calculate varying inner and outer boundaries
	for (n=0; n<N ; n++)
	{
		// Inner boundary contour
		if (ring) ir_vals[n] = ir_min + (rand()%(ir_max-ir_min));
		else ir_vals[n] = 0;

		// Outer boundary contour
		or_vals[n] = or_min + (rand()%(or_max-or_min));
	}
	// Add redundant value to end of array for convenience
	// in calculating interpolated values. This extra value
	// is equal to the first one.
	ir_vals[N] = ir_vals[0];
	or_vals[N] = or_vals[0];

	// Rasterize the blob
	y = 0;
	while(y < h)
	{
		x = 0;
		while(x < w)
		{
			// distance of current point from centre
			distance = sqrt((x-xc)*(x-xc)+(y-yc)*(y-yc));

			// angle of current point relative to centre
			angle = atan2(y-yc, x-xc);

			// di is a double value between 0 and N
			di = (N/2.0)*(1 + angle/M_PI);
			if (di < 0) di = 0;
			if (di >= N) di = N - 0.001;

			// i is the index into the ir_vals and or_vals arrays
			i = (int)di;

			// Reduce di to only its fractional part, i.e. a value
			// between 0 and 1
			di = di - i;

			// Calculate inner and outer boundary distances at this angle.
			// This formula smoothly interpolates between points in the
			// ir_vals and or_vals arrays.
			ir = (0.5 + 0.5*cos(di*M_PI))*ir_vals[i] + (0.5 - 0.5*cos(di*M_PI))*ir_vals[i+1];
			or = (0.5 + 0.5*cos(di*M_PI))*or_vals[i] + (0.5 - 0.5*cos(di*M_PI))*or_vals[i+1];

			// If this point lies within the blob boundary, make it dark.
			if (distance >= ir && distance < or) p[y][x] = rand()%(p[y][x]/2);

			// Next point
			x = x + 1;
		}
		// Next row
		y = y + 1;
	}
}

// Save the current image to the specified filename
void save_image_as(char *filename)
{
	// Variables
	int x, y;

	// Open output file
	FILE *f;
	f = fopen(filename, "w");

	// Print header info to file
	fprintf(f, "P2\n");
	fprintf(f, "# Blob image\n");
	fprintf(f, "%d %d\n", w, h);
	fprintf(f, "255\n");

	// Print all pixel data to file
	y = 0;
	while(y < h)
	{
		// Print a row of pixel values to file
		x = 0;
		while(x < w)
		{
			// Print one pixel value to file
			fprintf(f, "%d ", p[y][x]);

			x = x + 1;
		}
		fprintf(f, "\n");
		y = y + 1;
	}

	// Close output file
	fclose(f);
}
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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s