Problem set 0 · Introduction to C++ and the 6.8370/1 Image Class
Where to hand in. Submit at
https://compphoto-portal.fredopdurand.workers.dev/
Make sure your files sit in the asst directory at the root of the zip. The
Submission section at the end of this handout has the details, along with the
questions the form will ask you.
AI policy.
You are only allowed to use the class's AI assistant at
https://comp-photo-book.pages.dev/
embedded in the book, notes, slides, and problem sets.it is built to help you think, not to hand you the answer
it knows our material: chapters, notes, demos, problem sets
Fine: brainstorming, explanations, editing, debugging, learning support.
Not fine: pasting problem statements into other (general) AI tools, asking for solutions to assigned problems, or submitting AI-written text, code, equations or analysis as your own.
Keep the line visible: distinguish your own work from AI-assisted work, and mention how the AI helped you (or not).
Extra credit. Percentages are of the regular points of your own version of the class, 6.8370 or 6.8371. An extension is worth what the handout says, 5% unless marked otherwise; for 6.8371, a part marked “6.8370 only” counts as extra credit at the percentage it gives. All extra credit on one problem set together is capped at 10%, so a problem set gives at most 110%.
Questions. Ask on Piazza, where the whole class sees the answer:
https://piazza.com/mit/fall2026/683701
Summary
Learning C++
Compiling, Debugging and Submitting Code
C++ (Source/Header, Static Typing, Text I/O, Classes)
Installation and Environment Setup
Throughout this course, you will develop a C++ library for computational photography that you can use in future projects.
C++ is a compiled, statically typed, object-oriented language. If you come from Python, the free book C++ for Python Programmers (https://runestone.academy/ns/books/published/cpp4python/index.html) introduces each C++ construct next to the Python you would have written instead. If you come from TypeScript or JavaScript, the syntax will already look familiar and the type annotations work much as TypeScript's do, with two large differences: a compiler checks the types and produces a binary, and there is no garbage collector, so memory is yours to manage. https://learnxinyminutes.com/c++/ is a fast tour of the syntax from that starting point. We also suggest https://www.learncpp.com/ as a thorough tutorial and http://www.cplusplus.com/ as a 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, or asking the class AI assistant about them, can often be the best first step in debugging.
C++ is a compiled language, which means C++ code must be compiled before it can be executed. In this section, we will go over how to compile and submit your code. Regardless of which compiler you choose to use, your code must compile on our online submission system.
Compilers
The code you write should be portable enough to compile with any compiler. The
submission system uses the GNU g++ compiler on Linux, so that is the setup
to match. You need a C++ compiler and make on the command line:
Linux, including the Athena cluster machines: on Ubuntu or Debian,
sudo apt install build-essentialinstalls both.macOS: open Terminal and run
xcode-select --installto get Apple's command line tools. You do not need the full Xcode application. On macOS,g++is Apple Clang answering to that name, which compiles this code fine; the submission system is where it meets real GNUg++.Windows: install the Windows Subsystem for Linux by running
wsl --installin an administrator PowerShell (https://learn.microsoft.com/windows/wsl/install), then follow the Linux instructions inside it. Cygwin (https://www.cygwin.com/) gives you a unix-like shell on Windows too, if you prefer it.
There are four .cpp source files in the assignment folder: a0_ main.cpp, a0.cpp, Image.cpp and lodepng.cpp. Normally, you would compile this collection of files by executing
the following command:
g++ -Wall -std=c++11 -o a0 a0_main.cpp a0.cpp Image.cpp lodepng.cpp -I.
This compiles the four .cpp files and generates the output (-o)
a0. The -I. flag tells g++ to look for the headers (or
include files) in the current directory (.). The assignment folder
contains three headers: a0.h, Image.h, lodepng.h. See
Headers and Source Files for more details on header and source files. The -Wall flag (for `warn all') tells the compiler to display all warning messages
emitted during compilation. The -std=c++11 flag tells the compiler to use
the C++11 standard.
If you have g++ installed, compile the code by going to the code
directory and typing the above command. Check that an executable named a0
is created. You can run the executable with the following command:
./a0
If you are successful, you should get a message that says
Congratulations, you have compiled the starter code!
Makefiles
Typing the compile command directly each time you want to re-compile can become
cumbersome, especially if you have many .cpp files that have complicated
dependencies. For example, if you are making changes to only one .cpp
file, recompiling all of them every time (which is what the previous command
does) is time consuming and inefficient. Makefiles are a simple way to
organize code compilation. A Makefile contains a list of commands to
compile a series of files as well as their dependencies. While in a directory
containing this Makefile, you can type make and the commands in the
Makefile will be executed. Open the Makefile in a text editor and
see how compiler commands and source file dependencies are specified. Please
take a moment to read through the "tutorial" comments we provided inside the
Makefile to get a better idea of how the file is specified. Now, compile
your code by going to the code directory and typing
make
on the command line. This will also create an executable called a0. You
can run this by typing
make run
Alternatively you could use an IDE: Visual Studio Community (https://visualstudio.microsoft.com/vs/community/) on Windows, or Visual Studio Code with its C/C++ extension (https://code.visualstudio.com/docs/languages/cpp) on any platform.
We strongly recommend that you stick to the Makefile/g++ approach
for this class. We will try to help you with compilation problems during office
hours.
- 1
Make sure you can compile the starter code without problems. There is nothing to turn in for this problem, but if you can't compile the code, you are unlikely to complete the remainder of the assignment.
Submission System
The online submission system compiles your code on our servers, executes it and
then displays the output. All text written to the standard output and standard
error streams is printed on screen. Any .png images written to the asst/Output directory is displayed by the submission system, so you can verify
that your code is working properly through the system. We provide a Makefile rule to prepare a submission zipfile. Run it using
make prepare
This make rule will execute the necessary sequence of commands to produce
a submission zip file. You can inspect the commands specified inside the Makefile. You can also manually zip your submission code. If you do so, please
make sure to keep all your code in the asst directory at the root of the
.zip archive and make sure to exclude all build outputs, executables as
well as the Output folder and its contents as these
will bloat the size of your zip file and slow down your upload.
Problem set 0 is due Wednesday September 16 at 9pm, and it does not use any of your 3 late days. The submission system keeps accepting it after the deadline, until Saturday September 19 at 9:15pm, without charging a late day.
Debugging
You are welcome to use a debugger, such as gdb
(http://www.gnu.org/software/gdb/) or 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. The assert used here is the course's own
two-argument macro from messageassert.h, which takes a condition and the
message to print; it is not the one-argument assert of the standard
library.
float safeDivision(float dividend, float divisor) {
assert(divisor!=0, "Divisor is zero");
return dividend/divisor;
}
If the divisor is zero, the program will abort and tell you which assertion
failed. Otherwise, the returned value would be Inf or NaN, which
might be undesirable.
Image Input/Output
Our Image class supports reading .png files only. All the sample
images we give you will be in the PNG format. To convert your own images, use
the class's own converter, described in the File conversion tools appendix of
the book:
https://comp-photo-book.pages.dev/u/jpg-png-without-an-alpha-channel
It runs in your browser, uploads nothing, and writes a three-channel RGB PNG
with no alpha channel. Our loader reads any PNG and discards the alpha channel
if there is one. In addition, the Image class can only write to .png files. You can use your favorite
image viewer to view the images.
Warning: Renaming a JPG file's extension to .png does not
convert the file type! You might think this is a silly comment but we include
this because people have tried and failed to do so. Instead, you may open the
image in some image editor and change the format when saving to convert a JPG
file.
C++
In this section, we introduce a few C++ language features that are different from previous languages you may have used. Next to Python or TypeScript, 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 the tutorials linked above (https://runestone.academy/ns/books/published/cpp4python/index.html coming from Python, https://www.learncpp.com/ otherwise) and on this reference website (http://www.cplusplus.com/).
Headers and Source Files
C++ programs are usually organized into header and source files. Actual
executable code is written in source .cpp files, while function and class
declarations live in .h header files. 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).
While the .h file has only a declaration of the function's name and
signature, the .cpp file provides it with an actual body of code: its
definition.
Throughout the assignments, we will give you key function declarations in the header file, and you will implement them in the source file.
When you compile and execute your code, the program runs all commands in the
main function located in a0_main.cpp. This allows you to execute
your own functions and verify that your code is correct.
We will not grade the content of a0_main.cpp as we will replace
it with our own unit tests.
Static Typing
All C++ variables must have a type. In 6.8370/1, we use IEEE single-precision floats to represent the value of a pixel.
- 2.a
Return a floating point variable
cthat is the sum ofaandbin the functionfloat getSum(float a, float b).
Text Input/Output
You may find it useful to print values to the screen to debug your program or get 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.
- 2.b
Write statements in
void helloworld(float a, float b)that print the followingHello World! The value of a is _. The value of b is _. The sum of a and b is _.where the underscores are replaced by the actual numbers that make the sentences true.
Simple Image Class
In a0.h we have provided a simple image class (SimpleImage). The
aim of this class is to create a binary image (just zeros and ones) to
demonstrate the basics of how data can be stored and manipulated. The
specification of the class contains the declaration of various methods, all of
which have dummy implementations in a0.cpp. Throughout this exercise, you
will be asked to provide proper definitions.
Images are inherently two-dimensional (three if multiple channels are
available), however, it is often desired to store them as a single-dimensional
array and index into them appropriately (we'll see more details about this in
future problem sets). For our SimpleImage class, we will store a ${\tt
width} \times {\tt height}$ image as an array of ${\tt width} * {\tt height}$
elements in row-major order. That is, consecutive columns are tightly packed
(no separation between them) while consecutive rows have a separation of ${\tt
width}$ elements.
In general, we do not know the size of images ahead of time. As a result, our
arrays must vary their sizes. Rather than handle memory directly, we will
generally rely on the Standard Library's vector container (see line 53 of
a0.h). The vector container provides various convenience methods for
array-like operations where the size of the array can vary arbitrarily. See
http://www.cplusplus.com/reference/vector/vector/ for the container's
documentation.
Now that the mechanisms for storing data have been outlined, we can move on to constructing the class, line 33: declares the class constructor:
SimpleImage(int width, int height);
The constructor takes care of creating an instance of the object when needed. As we would expect, the constructor above takes two input integers, the width and height of the desired image. For example, typing
SimpleImage my_im(10,10);
would form an empty image of size $10 \times 10$.
- 3.a
Implement the
SimpleImageconstructor:
SimpleImage(int width, int height)ina0.cpp.
Make sure to keep all relevant information and initialize the image to zero (avoid adding elements one-by-one if possible).
An empty image is not of much use so let's go ahead and add some detail by using the class method
void make_rectangle();
to create a white rectangle (that is pixel value of 1.0) in the center of our image. Let's make the rectangle be 20% of the width (and height respectively). It is sometimes helpful to think of the image plane as a continuous space (observed at discrete locations) and we will adopt this convention in this example; as a result, the center of the image is allowed to be fractional and similarly, any pixel that partially overlaps with the rectangle should be denoted as white. That is, calling
SimpleImage img2(11,11);
img2.make_rectangle();
should produce a white rectangle spanning $[4, 4]$ to $[6, 6]$. (Note: the indices are zero-indexed and ranges are inclusive.)
To provide additional examples:
Image of size $5 \times 3$ would have a rectangle of one pixel at $[2, 1]$
Image of size $4 \times 4$ would have a rectangle spanning $[1, 1]$ to $[2, 2]$
Image of size $3 \times 7$ would have a rectangle spanning $[1, 2]$ to $[1, 4]$
Image of size $10 \times 9$ would have a rectangle spanning $[4, 3]$ to $[5, 5]$
- 3.b
Implement the class method
void make_rectangle()ina0.cpp.
This method should set pixels to white (1.0) that are within 10% (inclusive) of the image center in each direction (hint: check your boundary conditions to ensure the rectangle is symmetric around the image center).\medskip Don't spend too much time on the rectangle's exact boundary pixels. This is a warmup in C++ and image indexing. Aim for a reasonably centered rectangle; if the boundary wording seems ambiguous, choose a consistent convention and move on. Minor differences at the rectangle's edges are not a concern for this exercise.
Sometimes it is helpful to compute statistics across the entire image. A potentially useful statistic could be the average pixel intensity. Let's add that functionality to our binary image.
- 3.c
Implement the class method
float compute_average() constina0.cpp.
Loop over all image pixels and return the computed average.
We have an image, but no way of visualizing it. We could print the pixel values
directly to the terminal, but this could be tedious to parse. Instead, let's
use characters, similar to ASCII art
(https://en.wikipedia.org/wiki/ASCII_art). We only have two values in our
images so let's use the characters - and + to encode zeros and ones
respectively:
- 3.d
Implement the class method
void print_to_terminal() constina0.cpp.
Loop over the image and print pixel values as characters instead of numbers. Map the values so that zeros appear as-and ones appear as+in a ${\tt width} \times {\tt height}$ format (hint: you can use case statements or the values to index into an array of characters).
A Better Image Class
We have provided the specification for a class that better represents images
(Image.h). The specification contains a number of methods and variables
that belong to each instantiation of the Image class. Most of these methods are
implemented in the source file (Image.cpp).
In the next pset, you will implement some of the definitions in the source file
Image.cpp. In the meantime, look over the header file and look for the two
constructors on lines 34 and 39 of Image.h. They are
Image(int width_, int height_ = 1, int channels_ = 1,
const std::string &name="");
Image(const std::string & filename);
You can create an instance of the Image class using either constructor. The
first creates a blank image of dimensions ${\tt width\_}\times {\tt
height\_}\times {\tt channels\_}$. You can use the first constructor to create
an Image variable my_im that is $100\times 100$ pixels with three color
channels by typing
Image my_im(100,100,3);
- 4
Implement the function
Image readAnImage(const std::string &filename)ina0.cpp,
which returns an Image created using the second constructor takingfilenameas an input.
Submission
Turn in your files to the online submission system and make
sure all your files are in the asst directory under the root of the zip
file. If your code compiles on the submission system, it is organized correctly.
The submission system will run code in your main function, but we will not use
this code for grading. The submission system should also show you the image your
code writes to the ./Output directory
Leave the input images we provide out of the zip: make prepare copies only
the images you made yourself (Input/debug/, or a file a question asks
for by name), the submission system
supplies the provided ones, and grading uses its own copy. Uploads are limited
to 100 MB.
In the submission system, there will be a form in which you should answer every written question this handout marks with “(Answer in the form)”, and these:
How long did the assignment take? (in minutes)
Potential issues with your solution and explanation of partial completion (for partial credit)
Any extra credit you may have implemented and their function signatures if applicable
Collaboration acknowledgment (you must write your own code)
What was most unclear/difficult?
What was most exciting?