Introduction: Green Screen

Almost certainly, you're familiar with green screening, where a plain green background is replaced with some other image. The most common example is weather maps on the news - you'll never see a weather person wearing green clothes, or they would disappear.

In this project, we're going to do some green screening, combining a background from one picture with a foreground from another.

For example, consider a picture of Bill the Goat (on the left below). He deserves to be someplace nice. So, for every pixel that is green, we'll replace it with the corresponding pixel from the image in the middle below, giving us the image on the right below.

Honor

The course policy and the instructions it references, most pertinently COMPSCIDEPTINST 1531.1C, spell out what kinds of assistance are permissible for programming projects. The instructor can give explicit permission for things that would otherwise not be allowed.

For this project, you have explicit permission

  1. to get help from other current IC210 instructors (any assistance must be documented though)
  2. and to discuss the "big picture" of how to approach the project with current IC210 MGSP leaders. You may not, however, discuss or view any code that is specific to the project (see the instructors for such discussions), so this will probably be most useful when you are just getting started. If you are stuck on concepts, you may find it helpful to discuss homeworks, lab, or lecture examples with MGSP leaders.
  3. and to use general purpose C++ resources online (though such use must be documented). Resources that might specifically address this project are not allowed.
With the instructions referenced in the course policy and the explicit permissions above, what you get is summarized as:
Warning: Do not even vaguely talk about the contents of the project with your colleagues.

If you have questions about any of these rules, email your instructor and ask about it. We know you want to do what's right and we are here to help you.

Grading

80% of your grade will be based on functionality (i.e., whether your program works as specified), mostly based on the test cases that you see when you submit, but perhaps also extra test cases according to the specifications of the project. The code you submit must work if you expect to earn a passing grade.

20% of your grade will be based on coding style, which includes:

All of this is factored into your maximum score based on which part you have completed. So for example, if you complete up to part 3 perfectly (i.e., 85/100) working and also get 15/20 on style, then your final grade would be 85 * (0.80 + 0.15) = 80.75.

Tips for success

Part 1: Understanding ppm image format (20/100)

An example run (with user input colored in red):
~$ ./readppm
Input file: bg.ppm
P3
width = 6, height = 5
max value = 255
row 0, col 0: r0 g255 b0
row 0, col 1: r255 g0 b0
row 0, col 2: r0 g255 b0
row 0, col 3: r255 g0 b0
row 0, col 4: r0 g255 b0
row 0, col 5: r255 g0 b0
row 1, col 0: r255 g0 b0
row 1, col 1: r255 g0 b0
row 1, col 2: r255 g0 b0
row 1, col 3: r255 g0 b0
row 1, col 4: r255 g0 b0
row 1, col 5: r255 g0 b0
row 2, col 0: r0 g255 b0
row 2, col 1: r0 g255 b0
row 2, col 2: r0 g255 b0
row 2, col 3: r0 g255 b0
row 2, col 4: r0 g255 b0
row 2, col 5: r0 g255 b0
row 3, col 0: r0 g0 b255
row 3, col 1: r0 g0 b255
row 3, col 2: r0 g0 b255
row 3, col 3: r0 g0 b255
row 3, col 4: r0 g0 b255
row 3, col 5: r0 g0 b255
row 4, col 0: r255 g255 b0
row 4, col 1: r255 g255 b0
row 4, col 2: r255 g255 b0
row 4, col 3: r255 g255 b0
row 4, col 4: r255 g255 b0
row 4, col 5: r255 g255 b0

Project files

Download proj01files.tgz. Extract the project files by running following the command in the terminal:
tar -xvf proj01files.tgz

Understanding PPM format

In this project, to manipulate the pixels of images easily, we're going to use a horribly space-inefficient image file format called "plain PPM."

The project files contain a bunch of PPM files that you can use. For example, open bg.ppm in a text editor (i.e., vi, emacs, or atom), you'll see something that looks like this: [NOTE: if you use emacs, at first you will see the actual "rendered" picture. Press Ctrl-C twice to switch to seeing the actual ASCII text].

P3
6 5
255 
0 255 0 255 0 0 ...

Every PPM file must be in this format.

Viewing a PPM image

To view a PPM image on your Linux machine, use the command:
eog thepicture.ppm

Your task: readppm.cpp

Write a program in a file called readppm.cpp. The program should first prompt the user for the filename of an existing PPM image. Then, it should print out the contents of the image as shown above on the right. In particular, for each pixel, your program should provide its row and column position in the image.

Some big hints!

You are working with two-dimensional images, so you might assume that you need to use multiple loops to manipulate the data. However, that is NOT the case. You have two choices:

You can solve this entire project using this "single loop with a counter" approach. You might want to use multiple loops later, for part 4, but it's not necessary.

Submitting Part 1

AFTER you test your program (be sure to try other files, not just bg.ppm), submit it:

~/bin/submit -c=IC210 -p=proj01 readppm.cpp

WARNING: after you run "submit", it will take 1-2 minutes (maybe more, if many students are using the server) before you see the updated test case results. So it will be SLOW for you to make small changes and then run "submit" many times. Instead, test the code yourself, and submit when you are confident it works. Nonetheless, unlike with homeworks, the number of times you can run "submit" is NOT limited for this project.

Part 2: Grayscale an image (40/100)

To get used to the PPM format more, let's make an image grayscale (black and white).

Write a program in a file called gray.cpp:

Tip: To find the gray value of a pixel, take the r, g, and b values, average them (to an integer with fractions truncated), and set all three values to that number. So, the gray version of (5, 100, 16) would be (40, 40, 40).

As an example, running this program on our picture of flowers gives us a picture on the right.

Note: If the input file to be read in does not exist, the program should print an error message and gracefully exit. You must still "return" a value of "0" from your main() function in this case (otherwise, the "submit" system will consider your program to have failed with an error).

Checking your output with test vectors

You can check if your output files match the corresponding test files contained in proj01files.tgz.

  1. Change the permission of diff.sh (which is also found in proj01files.tgz) to be executable:
    ~/$ chmod 700 diff.sh
    
  2. Make sure that your readppm compiles and works correctly (the script diff.sh uses your readppm, which MUST have that name).
    ~/$ g++ readppm.cpp -o readppm
  3. Use the script to see if your output file is the same as the corresponding test data.
    ~/$ ./diff.sh graybg.ppm test_graybg.ppm
    ~/$ ./diff.sh grayflowers.ppm test_grayflowers.ppm
    
Example runs of the program are shown here (with user input colored in red):
~$ ./gray
Input file: bg.ppm
Output file: graybg.ppm
Image saved to graybg.ppm

~$ ./gray
Input file: flowers.ppm
Output file: grayflowers.ppm
Image saved to grayflowers.ppm

~$ ./gray
Input file: nonexisting.ppm
Output file: output.ppm
Error: Input file not found

Submit

Submit this program with the command
~/bin/submit -c=IC210 -p=proj01 readppm.cpp gray.cpp

Part 3: Combine images (85/100)

In this part, we'll do the part described in the introduction.

Example runs of the program (with user input red):

~$ ./green
Foreground file: fg.ppm
Background file: bg.ppm
Output file: fgbg.ppm
Image saved to fgbg.ppm

~$ ./green
Foreground file: bill.ppm
Background file: flowers.ppm
Output file: billflowers.ppm
Image saved to billflowers.ppm

~$ ./green
Foreground file: fg.ppm
Background file: flowers.ppm
Output file: fgflowers.ppm
Error: Images have different sizes

~$ ./green
Foreground file: bill.ppm
Background file: nonexisting.ppm
Output file: billflowers.ppm
Error: Input file not found

Your program should be in a file called green.cpp.

Your program should prompt the user

Your program should replace every pixel in the foreground that is pure "green" (for us, this means RGB values of 0 255 0 ) with the corresponding pixel in the background image. Note: In the output, you will probably see a one-pixel wide green border around your foreground subject; this is fine.

Your program should work for any two images that are the same size as each other. If the foreground and background images are not the same size, your program should output an error message.

If one of the two files to be read in don't exist, the program should print an error message and gracefully exit.

Checking your output with test vectors

Use the script to see if your output file is the same as the test data.
 ./diff.sh fgbg.ppm test_fgbg.ppm 
 ./diff.sh billflowers.ppm test_billflowers.ppm 

Submit

Submit this program with the command
~/bin/submit -c=IC210 -p=proj01 readppm.cpp gray.cpp green.cpp

Part 4: Offset foreground image (100/100)

The problem with our program so far is that it only accepts pictures that are the same size. What if we want Bill somewhere other than in the middle of the picture? Some pictures in the tarball you downloaded are cropped (i.e., fgc.ppm, billc.ppm, bbillc.ppm, and mulec.ppm), so we should be able to put them anywhere in a picture that is at least as big as they are.
Example runs of the program (with user input red):
~$ ./shift
Foreground file: fgc.ppm
Background file: bg.ppm
Row shift: 1
Column shift: 2
Output file: fb_1_2.ppm
Image saved to fb_1_2.ppm

Foreground file: billc.ppm
Background file: flowers.ppm
Row shift: 100
Column shift: 400
Output file: bf_100_400.ppm
Image saved to bf_100_400.ppm

~$ ./shift
Foreground file: billc.ppm
Background file: nonexisting.ppm
Row shift: 100
Column shift: 200
Output file: bf_100_200.ppm
Error: Input file not found

~$ ./shift
Foreground file: billc.ppm
Background file: flowers.ppm
Row shift: 0
Column shift: 1200
Output file: bf_0_1200.ppm
Error: The foreground goes past the background 
Write a program in a file called shift.cpp that prompts the user for:

Example pictures illustrating how the row shift and column shift work:

row shift=0, column shift=0

row shift=0, column shift=450

row shift=100, column shift=0

More specifically, let rs be a row shift and cs be a column shift. Then, when green screening is performed,

the output pixel at row r+rs and column c+cs considers the foreground pixel at row r and column c.

If the given row shift or column shift is so large that the foreground image would extend past the background image, an error message should be given, and no output image created. In addition, if one of the two images input does not exist, the program should print an error message and gracefully exit.

Checking your output with test vectors

Use the script to see if your output file is the same as the test data.
 ./diff.sh fb_1_2.ppm test_fb_1_2.ppm 
 ./diff.sh bf_100_400.ppm test_bf_100_400.ppm 

Submit

Submit with the command
~/bin/submit -c=IC210 -p=proj01 readppm.cpp gray.cpp green.cpp shift.cpp

Making your own pictures (extra 3 points)

To turn a picture in some other format into a plain ppm on your VM, first install the needed software by running:

sudo apt-get install imagemagick
When it asks for your password, this is your VM password. The lab machines already have this software installed.

Once you have this software, if you have a picture somePic.jpg (or any other image format), you can convert it to a PPM with:

convert -compress none somePic.jpg somePic.ppm
If you want it to be a particular size (like 1280x960), you would run:
convert -compress none -resize 1280x960\! somePic.jpg somePic.ppm

Cutting out a foreground picture and putting it in front of a green screen requires Photoshop or its open-source equivalent GIMP, and the process is googleable, but longer than is appropriate for this page.

Your Task

Create your own background (mybg.ppm) and cropped foreground images (myfgc.ppm). Use shift.cpp and create the green screened image (myshift.ppm); choose the row/column shift values appropriately.

Submit

Submit with the command
~/bin/submit -c=IC210 -p=proj01 *.cpp myfgc.ppm mybg.ppm myshift.ppm

Deadline and late-day penalty

Part 1

The full project

Late Penalties