Creating a shadow template of a PGM image

I’ve just been cleaning up a scanned copy of a line drawing on paper. The background of the scanned image is quite dark and the shadowing is a bit uneven over the full image region, which makes it difficult to saturate the background to white just by adjusting the white point (using GIMP’s great contrast adjustment tool).

What I needed to do was create a mock-up template of the shadowy page minus the actual drawing, so that I could “subtract out” the background colour variation (using GIMP’s “Difference Layer” feature) before adjusting the contrast.

The following C program does exactly that: it creates an approximate template image of the PGM image’s background. The way it does this is by raising each pixel’s value to at least the level of the brightest nearby pixel. By “nearby”, what I actually mean is “within a square of predefined size centred on the pixel”.

// shadows.c
// shadow contour reconstruction for extracting line drawing
// from shadowy scan of paper.
// written by Ted Burke
// last updated 7-11-2012
// To compile:
//		gcc -o shadows shadows.c
// To run:
//		./shadows input.pgm output.pgm

#include <stdio.h>

#define MAXW 1000
#define MAXH 1000

// image is 464x640 px
unsigned char orig[MAXH][MAXW];
unsigned char shad[MAXH][MAXW];

int main(int argc, char **argv)
	int w, h, x, y, i, j, r=20;
	// Parse command line args and open files
	FILE *fin = fopen(argv[1], "r");
	FILE *fout = fopen(argv[2], "w");
	// Read PGM from file
	char line[1000];
	fscanf(fin, "%[^\n]\n", line);
	fscanf(fin, "%[^\n]\n", line);
	fscanf(fin, "%d %d\n", &w, &h);
	fscanf(fin, "%[^\n]\n", line);
	for (y=0 ; y<h ; ++y)
		for (x=0 ; x<w ; ++x)
			fscanf(fin, "%d", &orig[y][x]);
	// Copy original
	for (y=0 ; y<h ; ++y)
		for (x=0 ; x<w ; ++x)
			shad[y][x] = orig[y][x];
	// Do processing!
	for (y=0 ; y<h ; ++y)
		for (x=0 ; x<w ; ++x)
			for (i=y-r ; i<y+r ; ++i)
				for (j=x-r ; j<x+r ; ++j)
					if (i>=0 && i<h && j>=0 && j<w)
						if (orig[y][x] > shad[i][j])
							shad[i][j] = orig[y][x];
	// Write PGM to file
	fprintf(fout, "P2\n# Ted's shadow reconstruction\n");
	fprintf(fout, "%d %d\n255\n", w, h);
	for (y=0 ; y<h ; ++y)
		for (x=0 ; x<w ; ++x)
			fprintf(fout, "%d ", shad[y][x]);
	// Close files
	return 0;

One way of picturing what this program is doing is to imagine the input greyscale image plotted out as a contour surface – bright pixels are peaks and dark pixels are troughs. Now imagine running a large flat-tipped square probe over the contours of the image. At each probe position, the probe will rest on the highest pixel within its square area.

This is a pretty crude implementation of what is probably actually a reasonably good approach. It would work better – by which I mean produce a better, smoother contour – if the “probe” was something more subtle than a flat-tipped square. Basically, a rounded tip would produce a smoother output contour.

Here are the input and output PGM images that I was working with. On the left is the original scanned picture, with an unevenly shadowed background. On the right is the output image – the reconstructed shadowy background.

Cleaned image:

Here’s the final output image after subtracting out the background variation and adjusting the contrast (by setting the black-point and white-point):

Shakespeare images above are © Don Conroy 2012

This entry was posted in Uncategorized and tagged , , , , , , , , , , , , . Bookmark the permalink.

1 Response to Creating a shadow template of a PGM image

  1. Pingback: File reading and writing examples in C | DIT Engineering Computing 2.1

Leave a Reply

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

You are commenting using your 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