Assignment 2: By the power of greyscale!

Part I is due on Thursday, February 2, before midnight Part II is due on Thursday, February 9, before midnight

The goals for this assignment are:

  • Implement an class for loading and saving image files

  • Implement various operations and filters for images

Getting started

Clone your copy of the repository to your own computer. To build,

Don’t forget to do an "out of source" build and run cmake .. from the /build directory!
$ git clone<username>/pixmap-ops.git
$ cd pixmap-ops
$ mkdir build
$ cd build
$ cmake ..
$ make (or start pixmap-ops.sln)
$ ../bin/pixmap_test (or ../bin/Debug/pixmap_test from the developer console in Visual Studio)
$ ../bin/pixmap_art (or ../bin/Debug/pixmap_art from the developer console in Visual Studio)

1. Part I: Image class

Due Thursday, February 2, by midnight

Complete the implementation of a class Image in the files image.h and image.cpp. Your Image class should use the STB library to load and save image files.

The base code uses a header file to keep the class definition separate from its implementation. The header file is included in your main application file. If you add new methods to Image, you will need to edit both the header (.h) and source (.cpp) files.

1.1. Requirements

  • Your class should implement an assignment operator, copy constructor, and destructor

  • It’s up to you how you store the internal pixel data, but your implementation should not leak memory.

  • Your class should implement the following methods:

    • bool load(const std::string& filename);

      • Loads the file with the given name. Returns true if successful; False otherwise

    • bool save(const std::string& filename);

      • Saves the file with the given name. Returns true if successful; False otherwise

    • int width() const;

      • Returns the number of columns in this image

    • int height() const;

      • Returns the number of rows in this image

    • Pixel get(int row, int col) const;

      • Gets a pixel (value range in [0,255]) at position (row, col).

    • void set(int row, int col, const Pixel& c);

      • Sets a pixel (value range in [0,255]) at position (row, col)

    • Image flip_horizontal();

      • Returns a copy of the image flipped along the horizontal middle axis

    • Image resize(int width, int height);

      • Returns a copy of the imaged resized to the given width and height

    • Image gammaCorrect(float gamma);

      • Returns a copy of this image with the given gamma correction factor applied to it.

    • Image grayscale();

      • Returns a copy of this image as a grayscale image.

    • Image blend(const Image& other, float alpha);

      • Returns a copy of this image with the other image blended with it by factor alpha. E.g. result.pixel = this.pixel * (1 - alpha) + other.pixel * alpha. Assumes other and this have the same dimensions.

    • Image subimage(int row, int col, int width, int height) const;

      • Returns a sub-image with top,left corner at (x,y) and width and height

    • void replace(const Image& image, int row, int col);

      • Replaces the block of pixels starting at (row, col) with the image. Should not assume image fits on this image.

I recommend working with RGB color for this assignment. When you load images with STB, request 3 channels, rather than 4.

1.1.1. Testing

You are given a program to test your image class, implemented in pixmap_test.cpp.

$ ../bin/pixmap_test (or ../bin/Debug/pixmap_test from the developer console in Visual Studio)
(0,0,0) (100,0,0) (0,0,0) (255,0,255)
(0,0,0) (0,255,175) (0,0,0) (0,0,0)
(0,0,0) (0,0,0) (0,15,175) (0,0,0)
(255,0,255) (0,0,0) (0,0,0) (255,255,255)
loaded feep: 4 4
0 255 175
loaded earth: 400 400

1.2. Load/Copy/Save

To start, make sure that the file, earth.png, loads and saves correctly. Then test that your width, height, copy constructor, and assignment operator work correctly. Lastly, check that your destructor is cleaning up any memory created by your class!!

1.3. Resize

Test resizing the image, earth.png. The following code and image show an example.

Image resize = image.resize(200,300);"earth-200-300.png");
earth 200 300

1.4. Flip horizontally

The following code and image show an example.

Image flip = image.flip_horizontal();"earth-flip.png");
earth flip

1.5. Gamma correction

The following code and images show two examples.

Image gamma = image.gammaCorrect(0.6f);"earth-gamma-0.6.png");

gamma = image.gammaCorrect(2.2f);"earth-gamma-2.2.png");

Gamma = 0.6

earth gamma 0.6

Gamma = 2.2

earth gamma 2.2

1.6. Grayscale

The following code and image show an example.

Image grayscale = image.grayscale();"earth-grayscale.png");
earth grayscale

1.7. Subimage

The following code and image show an example.

Image sub = image.subimage(200, 200, 100, 100);"earth-subimage.png");
earth subimage

1.8. Blend and replace

The following code and image show an example.

Image soup;

int x = (int) (0.5f * (image.width() - soup.width()));
int y = (int) (0.5f * (image.height() - soup.height()));
Image background = image.subimage(x, y, soup.width(), soup.height());"background-test.png");

Image blend = background.alpha_blend(soup, 0.5f);
image.replace(blend, x, y);"earth-blend-0.5.png");
earth blend 0.5

2. Part II: Cool operators

Due Thursday, February 9, by midnight

In Image.h and Image.cpp, implement at least eight additional operations. You can make up your own filter, re-implement a filter from Gimp, or research an interesting filter online. Make sure to document your choice in the of your assignment. Below are some ideas:

  • Rotate 90 degrees: rotate the image clockwise by 90 degrees

  • Swirl colors: rotate the colors of your image such that the red channel becomes the green channel, the green becomes blue, and the blue becomes red.

  • Invert colors: subtract each color channel from the max value, 255.

  • Add a border around the edge of your images.

  • Distort: displace pixels based on sine and cosine.

  • Extract the red, blue, or green channels

  • Bitmap: Create a 'fat bits' version of your image

  • Overlay a fill color, or blend a pattern of colors

  • Lightest: given a Image, implement max(this.pixel, other.pixel)

  • Darkest: given a Image, implement min(this.pixel, other.pixel)

  • Difference: given a Image, implement this.pixel - other.pixel

  • Multiply: given a Image, implement this.pixel * other.pixel

  • Sobel operator

  • Gaussian blur

  • Box blur

  • Randomize colors or 'jitter' the colors

  • Glow: produce a glow effect around all pixels of a given color, such as white

  • Painterly effect

  • Glitch effect

2.1. Create unique images

In the program, pixmap_art.cpp, use multiple effects to create one or more unique images. Feel free to use your own images exported from Gimp (or another image application).

Make sure to use your custom operations from the previous question in your artworks!! You will not get credit for operators which you don’t test and show work correctly!

Below are some ideas:

kitty bitmap
SoupTunnel Darkest

2.2. Update

Update to include documentation on your unique features and art you created with your assignment.

3. What to hand in

  1. Your code. Make sure your code is checked into github. Make sure it adheres to the coding style.

  2. Update so it includes a writeup of the features your application supports. Your readme should include images showing off your custom features. Make sure you replace all todos in your README!

4. Grading rubric

Grades each week are out of 4 points.

  • (4 points) Milestone #1

    • (2 points) load/constructors/assignment/destructor/set (memory management)

    • (0.6 points) set/set/width/height/save

    • (0.2 points) resize

    • (0.2 points) flip_horizontal

    • (0.2 points) gammaCorrect

    • (0.2 points) grayscale

    • (0.2 points) blend

    • (0.2 points) subimage

    • (0.2 points) replace

  • (4 points) Milestone #2

    • (2.0 points) no memory errors

    • (1.0 points) readme and unique images/demos

    • (0.2 points) style and header comment

    • (0.8 points) unique filters

Code rubrics

For full credit, your C++ programs must be feature-complete, robust (e.g. run without memory errors or crashing) and have good style. Some credit lost for missing features or bugs, depending on severity of error

-5% for style errors. See the class coding style here. -50% for memory errors -100% for failure to checkin work to Github -100% for failure to compile on linux using make