UMBC CMSC 202, Computer Science II, Spring 1999, Sections 0101, 0102, 0103, 0104

Project 3: Recursion

Due: Friday April 9, 1999

See Project Notes


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]% cat 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.


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

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.junk > 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 constructor
        PBM (int rows, int columns);    // alternate constructor 
        ~PBM ();			// destructor 
        PBM (const PBM &);		// copy constructor 
        PBM& operator= (const PBM &);   // overloaded assignment operator

        // Get status of an individual pixel 
        // Parameters:  row and column position of the pixel
        // Returns:     1 for on, 0 for off, -1 for outside of grid

	int GetPixelStatus (int row, int column); 
  
        // Floodfill a region from specified starting position
        // Parameters:  row and column position of the start pixel
 					
        void FloodFill(int row, int column);
	
        // Read PBM from a file
        // Parameter:  reference to file input stream
        // Returns:    true for success, false if the file is not
        //               in valid PBM format

        int Load (ifstream& istr);

        // Write PBM to a file
        // Parameter:  reference to file output stream

        void Save (ofstream& ostr); 
   };
You may add other functions and data members to the class as needed.

Your source files should be named PBM.H, PBM.C, and Proj3.C (contains main()). You may create additional source files as needed. 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, as you will get no credit for it.


Submission

As usual, 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. 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!

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 prompts 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 13:35:50 EST by Alan Baumgarten, abaumg1@cs.umbc.edu

Back up to Spring 1999 CMSC 202 Section Homepage