CMSC 202 Homework Project 3

revised March 16
Section Date Out Due In
Mr. Baumgarten's Sections Monday, March 15, 1999 Friday April 9, 1999
Mr. Edelman's Sections Monday, March 15, 1999 Sunday April 11,1999
NOTE: There are several differences between Mr. Baumgarten's and my version of the project. Please make sure that you do the right one! Consult your own class page to make sure that you're doing the fight one!

There are 3 main objectives in this assignment:

You are to write a C++ program to implement an algorithm for flood-filling a region of a surface. The purpose of flood-fill is to fill an arbitrary bounded space on the screen with a given color (which, for us, will be black).

To run a flood-fill algorithm, you need a grid of pixels (simply dots on a screen) each of which is either on or off, and a location within the grid, from which to flood-fill. The pixel at the start position should be off. The flood-fill algorithm sets the start position on, and all of its horizontal and vertical neighbors that are off, and all of their horizontal and vertical neighbors that are off, etc. This 'flooding' stops when a pixel that is already on is reached. You can think of the pixels that are initially on as walls, and of the start location as a hose pumping out water. The water fills as much area as it can, but it is stopped by the walls.

As an example, suppose that we were to flood-fill Figure 1 below on the left, starting from the pixel marked with a diamond. The result is shown in Figure 2. Notice that the flooding does not proceed diagonally; only the horizontal and vertical neighbors of a flooded cell that are not already on will be flooded:


Assignment

You are to implement a flood-fill algorithm. You will write a program that reads in a 'screen' (i.e. a two dimensional array of pixels) from a file, asks for a point on that screen from which to commence flood-filling, runs the flood-fill algorithm with that point as the starting point, and writes out the resulting screen to another file. After completing the flood-fill and writing the new file, the program allows the user to view a version of the picture on the screen, using user-selected ASCII characters for pixels.

As stated above, this assignment is intended to give you experience using recursion. Therefore, your program may not use any of C++'s iteration constructs (do, while, for and goto); all repetition must be accomplished using recursion. This applies to every repetitive operation in the program, even those which involve I/O.

Example

Here is an example of how your program should work (text entered by the user is shown in italics):

umbc8[22]% hw3
What is the name of the input PBM file? example.pbm
This screen is 5 pixels wide by 4 pixels high.
Do you want to see the input [n]: y
Please enter characters for '1' and '0': * -

       ****-
       *--*
       **--*
       *****
Please enter the x and y coordinates of the start pixel: a 5
You must enter two integers; 'a 5' is not valid.
Please enter the x and y coordinates of the start pixel: 5 a
You must enter two integers; '5 a' is not valid.
Please enter the x and y coordinates of the start pixel: 8 3
The first integer must lie between 0 and 4, inclusive.
Please enter the x and y coordinates of the start pixel: 0 5
The second integer must lie between 0 and 3, inclusive.
Please enter the x and y coordinates of the start pixel: 0 0
That pixel is already set.
Please enter the x and y coordinates of the start pixel: 2 1
What is the name of the output file? outexample.pbm
Output written to file outexample.pbm
Do you want to see the output [n]: y
Please enter characters for '1' and '0': @ +
          @@@@+
          @@@@@
          @@@@@
          @@@@@

umbc8[23]% more outexample.pbm

          P1
          5 4
          1 1 1 1 0 
          1 1 1 1 1 
          1 1 1 1 1 
          1 1 1 1 1

umbc8[23]%

Note that the pixels are numbered from the upper left-hand corner of the screen, which is 0,0. Your program should verify that the selected start pixel is indeed off, and print a warning message if it is not.


More on processing - Error Checking of Input

Your program should be bulletproofed by checking for certain errors, and if they occur, to respond appropriately. The following errors should result in an appropriate error message printed to cerr and program termination:
The following errors should cause a warning message to be printed to cerr, but should not cause program termination:

Background Information

The PBM Format

We will be using a file format called PBM, which stands for Portable Bit Map. A PBM file has three components. The first item in the file is the pair of characters 'P1'; this serves to identify the file as a PBM file (For those of you interested, the 2 character pair at the start of a file is known in unix as the file's magic number). The second item in the file is a pair of integers that indicate the size of the screen: first the width, then the height (i.e., first the number of pixels in each row, then the number of rows). The remaining lines of the file contain one digit for each pixel in the image. A '1' means that the pixel is on, while a '0' means that the pixel is off. Here is the sample file used above in PBM format:

          P1
          5 4
          1 1 1 1 0
          1 00 0 1
          11 00 11 111 1

Note that neither the rows nor the bits in those rows are required to be separated by whitespace. In particular, a newline is not required after each row (of the image). Complete details about the PBM format may be obtained by reading the man page ('man pbm').

Two other points should be made about the PBM format. First, characters from a # to the end of the line are supposed to be ignored in a PBM file; however, we will not allow such comments in our PBM files. Second, no line is supposed to be over 70 characters long. We will ignore this requirement; however, if you decide you want to use the output of your program as the input to other programs that manipulate PBM files, you might want to observe it.

Resources

You will find some test PBM files here. All of these files have the file extension .pbm

There are a couple of tools that you might find useful when working on this assignment. The 'xv' program can display pictures that are stored in a variety of formats, including PBM. Because the standard X-windows manager imposes a minimum window width, very small PBM pictures will be stretched when they are displayed by xv. You can unstretch such pictures by changing the size of the xv window (for instance, by dragging the lower right-hand corner of the window with the mouse).

Another tool you might find useful is the 'bitmap' program. Bitmap allows you to draw a picture on a bitmap screen and flood-fill it. You can use bitmap to experiment with flood-filling, to verify that your program produces correct results, and to create new bitmaps for use as input to your program. Unfortunately, bitmap does not save its results in PBM format. It uses instead an alternative format called XBM. You can convert a PBM file into an XBMfile using the 'pbmtoxbm' program:

umbc8[24]% pbmtoxbm myfile.pbm > myfile.xbm
Converting a file from XBM to PBM format is slightly more complicated. First, you must use the 'xbmtopbm' program to convert from XBM format to a packed version of the PBM format. Then, you use the 'pnmnoraw' program to convert the packed PBM file into an ordinary PBM file such as those with which we are familiar:

umbc8[25]% xbmtopbm myfile.xbm > myfile.junk
umbc8[26]% pnmnoraw myfile.ju
nk > myfile.pbm
umbc8[27]% rm myfile.junk

What to code

You should implement a class for portable bitmap files. Use this class declaration as a starter:
    class PBM {
    private:
       int _rows; //number of rows in the image
       int _cols; //number of columns in the image  
       int ** bits; //the pixel settings for the image (will become 2 dimensional array)
    public:
        PBM();                          //default class constructor
        PBM(int rows, int columns);     // alternate class constructor 
        ~PBM();				// class destructor 
        PBM (const PBM &);		// copy constructor 
        PBM& operator= (const PBM &);   // overload assignment operator


	//returns status of an individual pixel 
	// 1 for on, 0 for off, -1 for outside of grid
	int GetPixelStatus(int row, int column);   
        
	// floodfill a region from a specified starting position
	// parameters are  x, y coordinates of starting pixel
	void floodfill(int, int);	// floodfill a region
 
        // extract PBM from a file
	// Return Value = 1 (true) for success and 0 (false) for
	// any failure to read successfully
        int Load ();    //reads a PBM from a file

        //Write PBM to a file
	// return value = 1 (true) on successful write
	//     and 0 (false) on any failure 
        int Save ( );  //writes a PBM to a file 

	//display image on screen
	void Display();

   };
You may add other functions to the class, if you wish to. If you do so, you may not change the public interface to the PBM class You might also wish to implement overloaded << and >> file functions to read and write pbm files, but that is not a required part of this project.

You should have 2 header files: the first header file declares the PBM class; the second one declares all of the functions used by function main.

You will also code 3 .C files: the implementation files for the headers you wrote, and also a file that contains function main and very little else.

The reason for this partitioning is to cultivate the habit of writing modular programs.

In addition to this, you must also write and submit a makefile that runs with the single command make.

Hints

The flood--fill task itself is a natural for ordinary recursion. You should use tail recursion to read and write the files. Refer to the recursion handout for more information about tail recursion. You should write and test the code to read the input file before attempting to write the rest of the program. If you are having great difficulty writing the necessary code directly, you may try implementing the code using iteration statements, then translating your code into recursive code. Don't submit the iterative code though--you will get no credit for it.

Submission

Use the submit program to turn in your work. For Sections 0101-0104, use as the submission class cs202-01; Sections 0201-0202 use a submission class of cs202-02. the submission assignment is Proj3 (Note that submit is case-sensitive, and that is an uppercase "P" in Proj3 !)

You must submit all of your .C and .h files, together with your Makefile. The Makefile must correctly compile your homework upon issue of the make command with no arguments. You may name your files as you wish, but the executable created by the make command must be named Proj3. Your Makefile will be used to compile your submitted code, so be sure it works. A simple Makefile that just does the compilation is fine.

You may submit your program more than once, but only the last version you submit will be graded. Submissions made by midnight on the due date are considered on--time. Projects received after that date are late, and will be penalized.

Make sure that you adhere to the I/O specifications given in this handout (i.e., the order of inputs to your program--the precise wording of the program's questions to the user is unimportant). If you do not adhere to these specifications, the automatic portions of the grading process will fail, and you will receive a poor grade.

Checklist

You should check to make sure that you have fulfilled each of these requirements:


Last Modified: 19 Mar 1999 09:55:04 EST by Mitch Edelman edelman@cs.umbc.edu

Back up to Spring 1999 CMSC 202 Section Homepage