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.
|
|
|
| foreground picture | background picture | combined picture |
For this project, you have explicit permission
If you have questions about any of these rules, email your instructor and ask about it.
~/bin/submit -c=IC210 -p=proj01 *.cpp
30% of your grade will be based on coding style, which includes:
tar -xvf proj01files.tgz
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:
P3 6 5 255 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 255 255 0 255 255 0 255 255 0 255 255 0 255 255 0 255 255 0 |
file_header = P3 width=6 height=5 largest_possible_value=255 6 pixels: (r 0, g 255, b 0) ... 6 pixels: (r 255, g 0, b 0) ... 6 pixels: (r 0, g 255, b 0) ... 6 pixels: (r 0, g 0, b 255) ... 6 pixels: (r 255, g 255, b 0) ... |
|
P3 is the "magic number" or file header,
which tells the computer what the format is (remember this from SY110?).
Every PPM file must be in this format.
eog mule.ppm
Of course, you can specify any other ppm file instead of mule.ppm
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 on the
right. In particular, for each pixel, your program should provide its row and
column position in the image.
An example run (with user input colored in red):
~$ ./readppm Input file: bg.ppm P3 width = 6, height = 5 max value = 255 *** row 0 *** 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 *** 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 *** 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 *** 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 *** 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
To get used to the PPM format more, let's make an image grayscale (black and white).
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. 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
The correct output ppm files for bg.ppm and folowers.ppm are provided in
proj01files.tgz. In particular:
graybg.ppm from your code should be the
same as test_graybg.ppm in proj01files.tgz.
grayflowers.ppm against
the provided file test_grayflowers.ppm.
proj01files.tgz):
~/$ chmod 700 diff.sh
diff.sh uses your readppm).
~/$ g++ readppm.cpp -o readppm
~/$ ./diff.sh graybg.ppm test_graybg.ppm ~/$ ./diff.sh grayflowers.ppm test_grayflowers.ppm
In this part, we'll do the part described in the introduction. In particular:
|
|
|
Your program should be in a file called
green.cpp.
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.
Note: A one-pixel wide green border around your foreground subject is fine.
./diff.sh fgbg.ppm test_fgbg.ppm
./diff.sh billflowers.ppm test_billflowers.ppm
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.
|
Write a program in a file called
rowshift.cpp that prompts the user for:
Example pictures illustrating how the row shift works:
|
Example runs of the program (with user input red):
~$ ./rowshift Foreground file: fgc.ppm Background file: bg.ppm Row shift: 1 Output file: fb_1.ppm Image saved to fb_1.ppm ~$ ./rowshift Foreground file: billc.ppm Background file: flowers.ppm Row shift: 100 Output file: bf_100.ppm Image saved to bf_100.ppm ~$ ./rowshift Foreground file: billc.ppm Background file: nonexisting.ppm Row shift: 100 Output file: bf_100.ppm Error: Input file not found ~$ ./rowshift Foreground file: billc.ppm Background file: flowers.ppm Row shift: 1200 Output file: bf_1200.ppm Error: The foreground goes past the background |
rs be a row shift.
|
|
If the given row 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.
fb_1.ppm (recall: rowshift = 1) that
should be analyzed by readppm
as follows.
fb_1.ppm should look as follows.
~/$ ./readppm Input file: fgc.ppm P3 width = 3, height = 2 max value = 255 *** row 0 *** row 0, col 0: r0 g255 b0 row 0, col 1: r0 g255 b0 row 0, col 2: r127 g127 b127 *** row 1 *** row 1, col 0: r127 g127 b127 row 1, col 1: r127 g127 b127 row 1, col 2: r0 g255 b0 |
~/$ ./readppm Input file: bg.ppm P3 width = 6, height = 5 max value = 255 *** row 0 *** 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 *** 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 *** 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 *** 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 *** 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 |
~/$ ./readppm Input file: fb_1.ppm P3 width = 6, height = 5 max value = 255 *** row 0 *** 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 *** row 1, col 0: r255 g0 b0 row 1, col 1: r255 g0 b0 row 1, col 2: r127 g127 b127 row 1, col 3: r255 g0 b0 row 1, col 4: r255 g0 b0 row 1, col 5: r255 g0 b0 *** row 2 *** row 2, col 0: r127 g127 b127 row 2, col 1: r127 g127 b127 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 *** 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 *** 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 |
./diff.sh fb_1.ppm test_fb_1.ppm
./diff.sh bf_100.ppm test_bf_100.ppm
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.
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 |
TipsAs with the previous part, you need to be careful about when not to perform green screening. |
|
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.
./diff.sh fb_1_2.ppm test_fb_1_2.ppm
./diff.sh bf_100_400.ppm test_bf_100_400.ppm