This lab we will be writing programs that manipulate images.
We will be using a format called PGM (.pgm), that is very
simple. It represents an image in a text file in which each
pixel is represented by a number from 0 and 255. 0 is black,
and 255 is white.
- The first line of the file is P2.
- The second line is the width-space-height in pixels.
- The third is 255.
- From then on we get pixels values (a single number per pixel).
So, for example:
P2
4 4
255
0 255 0 0
0 0 255 0
0 0 0 255
128 128 128 128
|
<-- header
<-- size: 4 (width) x 4 (height)
<-- max value = 255
|
We will be reading, storing and writing files in these formats. Here are two
images for you to play with:
dog.pgm / dog.jpg
and
cat.pgm / cat.jpg
Part 1: Posterize -- part1.cpp
Write a program that reads in a file in .pgm format, and
produces a "posterized" version of that file.
Note: even though
this particular part doesn't require it, I insist that you
read the file completely and store it in a 2D
array, and only then create the posterized version.
Here's an example:
run of program | cat.pgm | postercat.pgm |
~/$ ./part1
filename: cat.pgm
output filename: postercat.pgm |
|
|
The rule for posterization I used was this:
- If a pixel in the
original has value > 128, in the new image that pixel has
value 255.
- Otherwise, it has value 0.
Viewing pgm files
To view your image, use the eog
program. For
example:
eog postercar.pgm &
Test vector
- Download test_postercat.pgm.
- Download diffsh.
- Change the permission of diffsh in the terminal:
~/$ chmod 700 diffsh
- Check if your output file is correct:
~/$ ./diffsh postercat.pgm test_postercat.pgm
Submit
~/bin/submit -c=IC210 -p=lab08 part*.cpp
Part 2: Mirror -- part2.cpp
Write a program that reads in a file in .pgm format, and
produces a version of that file that is the image with its
reflection along the bottom of the original image.
Here's an example:
run of program | dog.pgm | mirrordog.pgm |
~/$ ./part2
filename: dog.pgm
output filename: mirrordog.pgm |
|
|
Test vector
- Download test_mirrordog.pgm.
- Check if your output file is correct:
~/$ ./diffsh mirrordog.pgm test_mirrordog.pgm
Submit
~/bin/submit -c=IC210 -p=lab08 part*.cpp
Part 3: Merge -- part3.cpp
Write a program that reads in two files in .pgm format, both of the same size,
and produces a new file of that size merges the two files. Here's an
example:
run of program | cat.pgm | dog.pgm | catdog.pgm |
~/$ ./part3
file 1: cat.pgm
file 2: dog.pgm
output filename: catdog.pgm |
|
|
|
The rule for merging is as follows:
- The value of pixel (i,j) in the merged file is the average of the values
of the first file's pixel (i,j) and the second file's pixel (i,j) value.
Test vector
- Download test_catdog.pgm.
- Check if your output file is correct:
~/$ ./diffsh catdog.pgm test_catdog.pgm
Submit
~/bin/submit -c=IC210 -p=lab08 part*.cpp
Part 4: Rotate -- part4.cpp
Write a program that reads in a file in .pgm format, and produces a version of
that file with the image rotated 90 degrees counter-clockwise.
Here's an example:
run of program | cat.pgm | rotatecat.pgm |
~/$ ./part4
filename: cat.pgm
output filename: rotatecat.pgm |
|
|
Test vector
- Download test_rotatecat.pgm.
- Check if your output file is correct:
~/$ ./diffsh rotatecat.pgm test_rotatecat.pgm
Submit
~/bin/submit -c=IC210 -p=lab08 part*.cpp
Part 5: Show your pictures to the instructor
I want you to use your own pictures for this stuff.
Other useful commands
You can convert back to .jpg with the following:
convert bar.pgm bar.jpg
You can also resize with Imagemagick. For example, to stretch/compress the an
image tmp.jpg into a 300 wide by 500 pixel high image, I can do:
convert -resize 300x500! tmp.jpg tmpNEW.jpg
jpg/png/gif → pgm
Hopefully you already know how to download and save image
files. What you need to know, however, is how to convert them
to pgm files. Fortunately, the lab machines have a suite of
tools called "Imagemagick" installed. One of these, convert,
can do this conversion for you.
Suppose foo.jpg is a file of yours (could be .png, .gif, whatever). To convert
it to pgm do the following:
convert -compress none foo.jpg fpp.pgm
-compress none: Whenever the output file in convert
is a .pgm
file, be sure to give the -compress none
option! It's a good idea to check each .pgm file to make sure
the format looks OK using the more
command, like
this:
more foo.pgm
Viewing pgm files
To view an image, use the eog
program. For
example:
eog foo.pgm &
To do: Show your images (posterized, mirrored, merged, and rotated) to
your instructor!
Part 6: Going Further - striping -- part6.cpp
Write a program that reads in two files in .pgm format,
both of the same size,
and
produces a new file of that size
consisting of vertical strips alternatingly from one
then the other of the input files.
The user will input the width of each vertical strip (in pixels).
Here's an example:
run of program | cat.pgm | dog.pgm | catdog.pgm |
~/$ ./part6
file 1: cat.pgm
file 2: dog.pgm
width of a strip in pixels: 8
output filename: stripcatdog.pgm |
|
|
|
Test vector
- Download test_stripcatdog.pgm.
- Check if your output file is correct:
~/$ ./diffsh stripcatdog.pgm test_stripcatdog.pgm
Submit
~/bin/submit -c=IC210 -p=lab08 part*.cpp
Part 7: Going Further - blur -- part7.cpp
Write a program that reads in a file in .pgm format, and
produces a version of that image that's blurred.
Here's an example:
run of program | dog.pgm | blurdog.pgm |
~/$ ./part7
filename: dog.pgm
blur size: 3
output filename: blurdog.pgm
|
|
|
Here's how I did the blur:
- If K is the "blur size", pixel (i,j) in the output image is the average of
the square of pixels centered at pixel (i,j) with side-length 2*K + 1. That
is, the left-top of the square is pixel (i-K, j-K) and the right-bottom is pixel
(i+K, j+K).
-
To keep all the pixels in range, you'll see that the output image is smaller
than the input image. In particular, an image with width w and hight h would be blurred into an image with width w-2k and height h-2k.
Test vector
- Download test_blurdog.pgm.
- Check if your output file is correct:
~/$ ./diffsh blurdog.pgm test_blurdog.pgm
Submit
~/bin/submit -c=IC210 -p=lab08 part*.cpp
Part 8: Still Going Further
From here, the sky's the limit. What do you want to do?
You could draw pictures in pixels, fade to black as you move
horizontally across an image, merge to images so that the top is
image 1, the bottom is image 2, and the transition between is
smooth.
How about "masking", e.g. take one of the posterized images and
a second image, and make it so that the second image only shows
through where the posterized image is white.
You could take an image and produce an ASCII art
equivalent. You could do that thing where you create a big
picture that's made up of little pictures.