Installation

We will be using C++ throughout this course. Grab the basecode for this assignment from Canvas. C++ is an object-oriented programming language like Java and it's syntax is similar to both Java and C. If you are familiar with Java, this page can be a great resource for adapting that knowledge to C++. www.cplusplus.com is also a great general reference. C++ is one of the most widely used programming languages in the world. Therefore, if you come across an error it is very likely that someone else has already encountered this problem. Just Googling your errors can often be the best first step in debugging.

C++ is a compiled language, which means you must compile your code first (using a compiler) before executing it. We'll first go over several possible compilers you can use. Regardless of your choice, you must ensure that your code compiles and runs successfully on the Mac OS X machines in Sudikoff 003 & 005 or the Linux servers which you can ssh into.

Compilers

You are welcome to work on your programming assignments on your own computer, in the computer labs, or on one of the departmental Linux servers. However, the code you write should be portable enough to work in any modern C++ compiler. We will be checking your solutions using the clang compiler on Mac OS X.

Mac OS: You can set up the compiler on Mac OS X by installing command line tools either through Xcode (Preferences → Downloads) or the terminal. The process may be different for different versions of OS X; similar tutorials can be easily found online.

GNU/Linux: In Ubuntu, you can install g++ with the following command: sudo apt-get install build-essential.

Windows: You can use Cygwin on Windows to create a UNIX-like shell and use the same compilation setup. The alternative is using Visual Studio on Windows, however, you must ensure your code compiles and runs on the departmental OS X or Linux machines.

Once you have g++ installed, you can compile your code by going to the code directory and typing:

make

on the command line. This will compile the starter code into an executable called a0. You can run this by typing

make run

If you are successful, you should get a message that says

Congratulations, you have compiled the starter code!

Debugging

You are welcome to use a debugger, such as the one that comes with your IDE. However, we also suggest you use assert statements or print statements to make sure conditions you think are true are actually true. For example, if you are performing a division, you may want to assert that the divisor is not zero.
float safeDivision(float dividend, float divisor)
{
    assert(divisor != 0.0f);
    return dividend/divisor;
}
If the divisor is zero, the program will abort. Otherwise, the returned value would be Inf or NaN, which might be undesired.

Image Input/Output

Our Image class supports reading and writing PNG files only. All the sampled images we give you will be PNGs and you can use one of a handful of tools to convert your own images to this format. You can use your favorite image viewer to view the images produced by your code.

C++

In this section, we will introduce a few C++ language features that are different from previous languages you may have used. C++ is most similar to Java. The big differences are that C++ has explicit memory management, distinguishes between references and pointers and organizes code into header and source files. You can find more information in this C++ tutorial for Java programmers and this reference website.

Headers and Source Files

C++ programs are usually organized into header and source files. Most executable code is in source files, while function and class declarations are in headers. Open the attached a0.h and a0.cpp files in a text editor or IDE of your choice. The function

void helloworld(float a, float b);

is in both the header file (a0.h) and the source file (a0.cpp). We will give you key function definitions in the header file, and you will implement them in the source file.

When you compile and execute your code, the program will run all commands in the main function located in a0_main.cpp. We will not grade the contents of this function and will replace it by our own to run our unit tests, but it will allow you to execute your own functions and verify that your code is correct.

Static Typing

All C++ variables must have a type. In this class, we will use IEEE single-precision floats to represent the value of a pixel.

Text Input/Output

You may find it useful to print values to screen for the purposes of debugging or getting information about what you are working on. You can do this using the syntax

cout << "Hello World!" << endl;

You can also use cout to display variables using the same syntax.

Classes and Functions

We have provided the specification for a FloatImage class to represent image date (floatimage.h). The specification contains a number of methods and variables that belong to each instantiation of the FloatImage class. Most of these methods are implemented in the source file (floatimage.cpp). The FloatImage class derives from the template class Array3D—a generic 3D array that can hold any type of data—with the data type set to float. If you are not familiar with templates, this tutorial may be a good place to start.

In a later part of this programming assigment, you are going to implement some of the definitions in the source file floatimage.cpp and array3D.h. For now, just look over the header files and look for the three constructors on lines 19–21 of floatimage.h. They are

FloatImage();
FloatImage(int width, int height, int channels);
FloatImage(const std::string & filename);

You can create an instance of the FloatImage class using any one of these constructors. The first creates an empty image of size zero, and the second creates a blank image of dimensions width * height * channels. For instance, you can use the second constructor to create a FloatImage variable my_im that is 100 × 100 pixels with three color channels by typing

FloatImage my_im(100,100,3);

The FloatImage & Array3D Classes

The FloatImage class specification is given in floatimage.h and array3D.h. Images are three dimensional arrays (width by height by color channel) that store pixels as a vector of floats called m_data (array3D.h). In memory, the pixels in the image are stored sequentially in row-major order in three adjacent color planes. That is, the distance or stride between adjacent values in the same row in m_data is equal to 1. The stride between adjacent values in the same column is equal to the width of the image and the stride between the different color channels at the same pixel is width * height. The Array3D class defines protected member variables with these values.

m_data is a C++ vector, which is essentially an array which manages its own memory. You can access elements of it using brackets. For instance, m_data[0] returns the front element in the vector. More information about vectors can be found here.

For images that correspond to pictures, the floating points in image data will be between 0 and 1. There is nothing guaranteeing that the values of image data stay in this range and there may be times when you want to use the FloatImage class to store intermediate data that doesn’t correspond to pictures, in which case the range is not meaningful. When the image is written to a file, it will assume the data lies in this range and will clamp values outside of the range to one of the endpoints.

You can use the FloatImage::write method to write images to PNG files. For example,

my_im.write("./my_image.png");

Then, you can view them in your favorite image viewer. This may be useful for debugging. Alternatively, if you don’t feel like providing a filename, you can use FloatImage::debugWrite() to write an image to an automatically named file. This might make debugging easier.

Pixel Accessors and Setters

You are going to implement the accessor and setter operators for pixel values in the image. We adopt the convention that the elements are accessed via the () operator. That is, the pixel at location (x, y) in the third color channel of my_im is accessed via

my_im(x,y,2);

The third color channel is accessed via the number 2, not 3. That is because we want to use 0-indexing, in which the first element in a given index is specified by 0.

Implement two accessors with 0-indexing and bounds checking to make sure the input is valid. If the input is not valid, throw an exception using the command throw OutOfBoundsException();.

Brightness and Contrast

Now for the fun part. Once we have these accessors, we can perform simple operations like increasing the brightness or contrast of an image.

Submission

Turn in your files using Canvas and make sure all your files are in the a0 directory under the root of the zip file. Include all sources (.cpp and .h) files, any required input, and the output of your program. Don't include your actual executable, and remove any superfluous files before submission.

In your readme.txt file, you should also answer the following questions:

Acknowledgments: This assignment is based off of one designed by Frédo Durand, Katherine L. Bouman, Gaurav Chaurasia, Adrian Vasile Dalca, and Neal Wadhwa for MIT's Digital & Computational Photography class.