A Slightly More Advanced Assembly Exercise
Exercise 1: Converting a Color Image (PPM) to Grayscale (PGM)
For this exercise, you will first write a C program to convert a color image (in PPM format) to grayscale (PGM format). Once you have thoroughly tested your C code to verify it is working correctly, you will convert it into a MIPS assembly program to do the same.
PPM and PGM File Formats
For this exercise, we will use the ASCII file formats of type PPM (color) and PGM (grayscale). For a detailed description of these file formats, please see the Wikipedia entry on Netpbm format. A short description is given below.
The format of a PPM or PGM file is as follows:
- A PPM or PGM file begins with an identifier on the first line (called "magic number"). A magic number of "P3" means this file is an ASCII PPM file; "P2" means it is an ASCII PGM file.
- There may be an optional comment line following this, starting with "#". To make this assignment a little easier, the input files given to you will not have this optional comment line (or any other comment lines anywhere else in the input).
- Next, there are two numbers, the first indicating the number of columns, and the second the number of rows in the image.
- Next, there is a max value, which indicates the maximum value any pixel component (R, G, B, or gray value) may have. This value may be any positive integer, although values of 15 and 255 are quite typical.
- Finally, there are color or gray values for all the column * row pixels. The values are ordered by rows from top to bottom, i.e., row 1 first, then row 2, etc., and within each row, the pixels are listed left to right.
- For a PPM image, each pixel value is listed as the values of its three components, Red, Green and Blue.
- For a PGM image, each pixel value is a single gray value.
- A whitespace (i.e., typically a space or newline character) must separate these integers. Other than that, the file is allowed to have any number of values on each line. For example, it is possible that the file has a single pixel value (R, G and B, separated by spaces) on a single line. Or, the file may have a single pixel color component per line (i.e., R on one line, G on the next, then B, then the next pixel, etc.). Or, one line in the file may have color values for multiple pixels, e.g., the RGB values for an entire row of pixels may be listed on a single line (as in the Wikipedia examples). But, we will put some restrictions on this format to simplify reading/writing these files.
Additional Formatting Specifications for This Exercise: Since the MIPS input/output routines (syscalls) available in MARS are somewhat limited, we will put further restrictions on the format of PPM/PGM files as follows:
- The files will not have any comments in them (so, no need to look for "#").
- Each line will only have one number on it. This means that the number of columns and the number of rows in the image will appear on separate (consecutive) lines. Also, the three color components of a pixel (R, G and B values) will appear on three separate lines.
- Please refer to the samples provided for any other formatting questions.
PPM and PGM Viewers
There are a number of free/open-source viewers available for displaying PPM/PGM image files, including:
- Windows/Mac: GIMP (GNU Image Manipulation Program), available from http://www.gimp.org. You can also look into IrfanView, AyeView (fee trial), and ToyViewer (for Mac). I would recommend GIMP.
- Linux: I would recommend GIMP again, but many X Windows distributions already include a lighter-weight tool called XV.
C Program
Write a C program that reads a PPM image (on its standard input, i.e., keyboard), and outputs its corresponding PGM image (on its standard output, i.e., console). Keep in mind the following:
- The input PPM image may be formatted in various ways, as mentioned above, i.e., one pixel per line, or one pixel row per line, or one pixel color component per line, etc. These variations in format will not affect your code. For instance, if you use scanf("%d%d%d", &r, &g, &b) in C, it will read the next three (decimal) integer values, regardless of any intervening space or newline characters.
- The max value for each color component can be specified to be any number 1 or greater. For this exercise, this number could be from 1 to 255 for the input PPM images.
- The max value for the gray values for the output must be 255. Thus, if the input PPM image has a max color component value of 15, then all of the values must be scaled appropriately. In particular, if the red, green and blue values of the pixel colors in the PPM image is R, G and B, respectively, and the max value is specified to be PPM_MAX, then the corresponding gray value in the output PGM image must be computed exactly as follows:
Gray_Value = ((R + G + B) * 255) / (3 * PPM_MAX)
Your C code (and assembly code below) must compute this expression exactly in the order indicated by the parentheses. The division is a truncated integer division (i.e., no rounding, throw away remainder).
- The magic number of the output image must be "P2" since it is an ASCII PGM file.
- You can run your program and test it by typing (or cutting-and-pasting) sample inputs onto the console, and looking at the console output. For the larger examples, use input/output redirection:
ex1 < ex1in1.ppm > ex1result1.pgm
Copy the PGM output to your laptop and view it in GIMP
Make sure the PGM output looks like a grayscale version of the PPM input
Make sure the PGM output has the same overall brightness as the input; otherwise check PPM_MAX
Name the file containing your C program ex1.c, and test it on sample inputs provided. First view the output file using GIMP. If it looks good, then you may check it against the sample output provided using the diff command.
Assembly Program
Once your C program is working correctly, write an equivalent MIPS assembly program that implements the same conversion from PPM to PGM images. Do not begin work on the assembly program until you are sure that the C program is working correctly. The best strategy would be to convert your C code (pretty much line-by-line) into its assembly equivalent. Run your program in MARS and verify that it is working correctly.
You can run your program in MARS and test it by typing (or cutting-and-pasting) sample inputs onto the console, and looking at the console output. For the larger examples, you will need to run it in command-line mode and use input/output redirection.
If you are developing your code on a Mac/Linux machine, you can use the following command on your computer within a terminal window (replace /path/to with the actual path to Mars, e.g., /Users/yourid/Desktop/Mars/Mars4_4.jar):
java -jar /path/to/Mars4_4.jar nc mc CompactDataAtZero ex1.asm < ex1in1.ppm > ex1result1.pgm
If you are using a Windows machine, you will need to login onto classroom.cs.unc.edu, copy your work there, and then run the following command:
java -jar /home/montek/comp411/bin/Mars4_4.jar nc mc CompactDataAtZero ex1.asm < ex1in1.ppm > ex1result1.pgm
For more information on running MARS in command-line mode, please see http://courses.missouristate.edu/kenvollmar/mars/help/MarsHelpCommand.html.
Name the file containing your assembly program ex1.asm, and test it on sample inputs provided. First view the output file using GIMP. If it looks good, then you may check it against the sample output provided using the diff command.
11 October 2013, Montek Singh, montek@cs.unc.edu