The goal of this lab is to introduce you to basic concepts in the C++ program language. Concepts you will be familiar with after this lab include:
A skeleton version the program will appear in your cs35/labs/01 directory when you run update35. The program handin35 will only submit files in this directory. In later labs you may have the opportunity to work with a partner, but for this lab you should work on your own. Useful links:
This lab will have write a program to load and output image files. In addition, you will provide a user the option to perform some basic image manipulation, including color alteration and horizontal flipping. To begin, we will first learn about the PPM Image format. Click here for information about the PPM format (and how to parse it) as well as tips for viewing and creating PPM image files.
Reading about the PPM format may seem overwhelming, but it's actually fairly simple to get started. At a high level, your program will ask the user to provide both the name of the input PPM image and the name of the file they would like to save the modified PPM to. You will then ask the user which of several image alteration techniques they would like to apply, perform the operations, and save the resulting image. Here is a sample run of the program where the only options are to convert an image to greyscale and flip it horizontally:
$ g++ ppmEditor.cpp -o ppmEditor $ ./ppmEditor Welcome to the Portable Pixmap (PPM) Image Editor Enter name of image file: input/oberon.ppm Enter name of output file: oberon-grey.ppm Do you want to: convert to greyscale? (y/n): y flip horizontally? (y/n): n Session completeThe original and resulting image:
oberon.ppm | oberon-grey.ppm |
I recommend implementing your program in 3 phases:
Your program will need to handle opening, reading, closing, and writing to file.
string inputfilename = "image.ppm"; //Get this from the user ifstream input(inputfilename.c_str());
hungry 356 blueYou can use the code:
string verb, color; int number; input >> verb; //"hungry" input >> number //356 input >> color //"blue"Notice that the strings do not contain whitespace, and that it automatically skipped the whitespace between 356 and blue. The provided code shows how to read the first two lines of the PPM file, you will need to complete the rest.
string outName = "output.txt"; ofstream outputFile(outName.c_str()); output << verb << endl; output << number << " " << color << endl;
To help read a line of pixels write a function readLine with the following signature:
bool readLine(ifstream& input, int pixels[], int columns)that takes in the input file, your buffer array, and the number of columns for one line of the image. Your function should read one line of the image (NOT necessarily one line of the file) and load the values into the pixels buffer. Note that arrays in C++ are passed-by-reference, so any modifications to pixels will modify the array designed in the call to readLine (just like in Python!). Your method should return whether the input stream is still valid (HINT: input.good() returns true if everything is in the clear). Your main program should stop if a read fails, output an error message, and quit.
Create a corresponding function for writing one line of data:
void writeLine(ofstream& output, int pixels[], int columns)
Your output file can actually be formatted as you like. Whitespace includes newline characters, so you can put them in where you wish. The format allows for it. Test this with small files and large files. You can check to see if they are identical by loading them both into a text editor like gvim and comparing number by number. Load them into image viewers, as discussed in the PPM Image Format help page listed above. Example ppm files are available in the input folder in your labs directory for this week.
Once you can exactly replicate a PPM image, you can begin writing functions to manipulate the image. At a minimum, you must implement a function to convert an image to greyscale, another to flip the image horizontally, a method to negate all red values, and at least 2 more of your choosing. Let us begin with negating red values.
void negateRed(int pixels [], int columns, int maxColorValue)It will change just the red color numbers into their "negative". That is, if the red number is low, it should become high and vice versa. This depends on the maximum color value. For example, if maximum value is 255 and a pixel had a red value of 0, it would become 255; if it were 255 it would become 0. If the red were 100, it would become 155. It should make changes to the buffer array as described above.
Note that you are responsible for determining what parameters are needed for each of these functions (aside negateRed which has been provided for you.
Pick whatever sounds interesting for your other methods. Some ideas include:
Greet user Ask user for input file (check if valid) Ask user for output file Read header (check if valid) Output header Ask user what filters (image alterations) to apply For each line of the image: Load image into buffer (check if still in valid state) Apply chosen filters Write image to output file Close files, output messageThe menu simply asks the user if they would like to apply each filter you developed. Using a series of yes or no questions. If the user enters an invalid value (you must define this) you should restate the question until a valid response is provided. At all points in your program, you should be defensive against potential user error
See the example at the top of the writeup for an example menu. Your program should apply each filter specified, in succession, one at a time. The filters must be cumulative (even if doesn't make sense in some cases); that is, if the user chooses to flatten all reds and flatten all blues, you should have a resulting picture of only green values.
To have your output image automatically pop up before your program completes, you can invoke the system command. Note that this is not a requirement but can help save the annoyance of loading the image manually after every run. Simply add the following command after your output file is closed:
system(("viewnior "+outfilename).c_str());viewnior is a image-viewing program and outfilename is a string containing the name of the output image. You will need to include an extra library at the top of your program to use this:
#include <stdlib.h>
Once you are satisfied with your code, hand it in by typing handin35. This will copy the code from your cs35/labs/01 to my grading directory. You may run handin35 as many times as you like, and only the most recent submission will be recorded.
This lab write up is based off of Joshua Guerin and Debby Keen's NIFTY 2012 submission titled PPM Image Editor. The pictures of the dog are by me. His name is Oberon. And yes, he does know how ridiculously cute he is, but he loves hearing it anyways.