COMPSCI 220 Fall 2017
Assignment 10: Image Masking
Out: 6 December, 2017
Due: 14 December, 2017
General Instructions For All Assignments
Assignments in COMPSCI 220 are to be programmed in C++11, using the virtual machine image provided
for the class. All assignments must follow the instructions on the handouts exactly, including instructions
on input and output formatting, use of language features, libraries, le names, and function declarations.
Failure to do so will automatically result in docked points. All assignments are individual: you must not
discuss assignment contents, solutions, or techniques with fellow students. Please review the course policies
on the course website, https://people.cs.umass.edu/~joydeepb/220R.
1 Instructions For This Assignment
This assignment aims to re-iterate many of the concepts covered in this class, including unit testing, ran-
domized testing, inheritance, memory management, visualization and computational e ciency. In this as-
signment you will implement functions to apply masks to images. These masks will be combinations of
rectangular, circular or a right angle shapes. When no masks are applied, the output image will be the
source image converted to grayscale. Once a mask is applied, the area within the mask will be displayed
in the original color of the source image. There may be multiple masks applied to the image. Regions of
the image that overlap with multiple masks should be colored only if they overlap with an odd number of
masks. Figure 1 demonstrates an example result of applying masks to an image.
You are not allowed to use any library or data structures other than what is already included in the starter
code.
Figure 1: An example result of applying several masks to an image.
2 Overview
Image masks are shapes inherited from an abstract base class, Shape. This base class has two purely virtual
methods, DrawOutline and IsWithin to draw the outline of the shape, and to determine if a point lies within
the shape. The Shape base class will be inherited by three shapes Circle, Rectangle and RightAngle. The
class ImageMask will maintain instances of the masks as a collection of Shape instances, and will apply the
masks to a provided source image.
2.1 Shape
This is the base class which contains virtual methods that must be implemented by the derived classes. It
has the following virtual functions:
virtual void DrawOutline(CImg* image) = 0;
virtual bool IsWithin(int x, int y) = 0;
The function DrawOutline draws the outline of the shape on the image.
IsWithin returns true i the pixel at (x, y) lies within the shape.
2.2 Circle
You must implement the class Circle in the le circle.cpp. This class is derived from Shape and has the
following speci cations:
1. Member variables to store the parameters of the circle:
int x;
int y;
int radius;
They store the X coordinate of the center, the Y coordinate of the center and the radius respectively.
2. A constructor:
Circle(int x, int y, int radius);
The circle is centered around the point (x, y) and has a radius radius.
3. You must also implement the functions inherited from the base class Shape:
void DrawOutline(CImg* image);
bool IsWithin(int x,clang int y);
2
2.3 Rectangle
Similarly, you must also implement the class Rectangle in the le rectangle.cpp with the following speci-
cations:
1. Member variables to store the parameters of the rectangle:
int x;
int y;
int width;
int height;
They store the X coordinate of the top left corner, the Y coordinate of the top left corner, the width
of the rectangle and the height respectively.
2. A constructor:
Rectangle(int x, int y, int w, int h);
These parameters are the X and Y coordinates of the top left corner and the width and height of the
rectangle respectively.
3. You must also implement the functions inherited from the base class Shape:
void DrawOutline(CImg* image);
bool IsWithin(int x, int y);
2.4 RightAngle
You must also implement the shape RightAngle. The relationship between the longest and shortest parallel
edges is given by the formula: ShortestParallelEdge = LongestParallelEdge 5. Figure 2 shows this
relation between the dimensions of the shape.
3
Figure 2: Geometric properties of RightAngle shape.
1. Member variables to store the parameters of the RightAngle:
int x0;
int y0;
int x1;
int y1;
They store the X and Y coordinates of the top left corner bottom right corner respectively.
2. A constructor:
RightAngle(int x0, int y0, int x1, int y1);
These parameters are the X and Y coordinates of the top left and bottom right corners of the RightAngle
respectively.
3. You must also implement the functions inherited from the base class Shape:
void DrawOutline(CImg* image);
bool IsWithin(int x, int y);
2.5 ImageMask
The le assignment10.cpp must implement the functions of the class ImageMask. The class has the following
requirements:
4
1. Member variables to store the required data
std::vector masks;
CImg current_image;
CImg source_image;
The vector masks stores pointers to all Circles, Rectangles, or RightAngles that are used to mask
the image. The CImg current_image maintains the pixel values of the image with the masks in masks
applied. source_image stores the original color image.
2. A constructor that takes a Cimg and a destructor
ImageMask(const CImg source_image);
~ImageMask();
3. Functions to add new Shapes
void AddCircle(int x0, int y0, int x1, int y1);
void AddRectangle(int x0, int y0, int x1, int y1);
void AddRightAngle(int x0, int y0, int x1, int y1);
These functions create Circles, Rectangles and RightAngles and add them to masks. The parame-
ters x0, y0, x1, y1 are interpreted di erently for each shape:
(a) AddCircle : x0, y0 is the center of the circle, and the radius is the Euclidean distance between
the points (x1, y1) and (x0, y0) rounded down to nearest integer.
(b) AddRectangle : x0, y0 and x1, y1 are two diagonally opposite corners of the rectangle.
(c) AddRightAngle : x0, y0 and x1, y1 are two diagonally opposite corners of the rectangle con-
taining the right angle.
For AddRectangle and AddRightAngle, note that the coordinates (x0, y0) and (x1, y1) are only
guaranteed to be diagonal corners: they are not guaranteed to correspond to a speci c orientation or
ordering of corners. You must compute what is the top-left corner or bottom-right of the rectangles as
necessary.
Note: Any dynamically allocated memory must be managed and deallocated at the ap-
propriate place. Your code must not have memory leaks.
4. A function that takes the color pixel intensities for the Red, Blue and Green channels and returns a
grayscale value corresponding to those values.
unsigned char ToGray(int R, int G, int B);
The gray level is calculated as the arithmetic mean of the intensities of the individual color channels
round down to the nearest integer.
5. A function to compute current_image from source_image by applying all the masks:
void ApplyMasks();
This function will compute which pixels in the image should be colored or not, and appropriately set
the pixel values in current_image. When no masks are applied, the output image will the the source
image converted to grayscale. Once a mask is applied, the area within the mask will be displayed in
the original color of the source image. There may be multiple masks applied to the image. Regions
of the image that overlap with multiple masks should be colored only if they overlap with an odd
number of masks. A pixel that is grayscale in current_image should use the ToGray function to set
its red, green, and blue values set to the same value, computed from the red, green, and blue values
of the corresponding pixel from the source_image. After applying the masks, this function should
draw the outlines of all the masks by calling the DrawOutline function of all the existing mask shapes.
Note: This function must re-compute current_image from source_image and masks. It cannot re-use
previously computed values of compute_image.
6. A function to reset the masks
void Clear();
This function must remove all existing masks so that new shapes may be added.
7. Public functions that return current_image and masks
CImg* GetCurrentImage();
std::vector GetMasks();
8. For up to 10% extra credit you may implement the function with the following signature:
int GetAreaColored();
This function returns the total area of pixels that remain in color in current_image. The unit for this
area is pixel2
2.6 Test Suite
You must implement tests in the le assignment10Tests.cpp. There are two type of tests you must
implement:
1. Unit Tests: You must de ne unit tests to verify correctness of the implementations of the shapes,
and the MaskImage class.
TEST(UnitTest, TestName)
All tests in this section must have the test case name UnitTest. The individual test name may be
given as you wish.
Your tests should not expect speci c output in cases that violate the speci cations as
output in these cases is not de ned.
2. Random Testing: In this part, you will implement random testing to generate random inputs with
speci c properties, and check that the resultant output obeys expected properties. Speci cally, you
will be implementing random testing to generate random overlapping shapes with an overlapping pixel.
The output properties for two overlapping random shapes you will be testing are:
6
(a) When neither of the shapes are added to the image mask, the overlapping pixel in the output
image should be in grayscale.
(b) When only one of the shapes is added to the image mask, the overlapping pixel should be in color.
(c) When both the shapes are added to the image mask, the overlapping pixel should be in grayscale.
To generate random inputs for this test, you must write a helper function with the following signature:
void RandomOverlappingInput(std::vector* masks, int* x, int *y);
This function should return with two random shapes added to the masks vector. The two shapes must
both overlap with the pixel returned by the coordinates (x, y).
Using RandomOverlappingInput, you should implement random testing using the listed properties to
check for correctness:
TEST(RandomTest, TestName)
All tests in this section must have the test case name RandomTest. The individual tests may be named
as you wish.
Your tests should not expect speci c output in cases that violate the speci cations as
output in these cases is not de ned.
During development, you may use the code in main.cpp to call AddCircle, AddRectangle or AddRightAngle,
but your test cases in assignment10Tests.cpp must not rely on GUI user input. The tests must directly
call AddCircle, AddRectangle or AddRightAngle with some parameters.
Do not use any GUI based input for your test cases in assignment10Tests.cpp
3 Understanding the Starter Code
You are provided with the following les for this assignment:
assignment10Tests.cpp: This le is to be used to de ne and run your unit tests. It includes a main function
to run unit tests, and some code stubs to help you create your unit tests and random tests (Section 2.6).
You must edit this le. However, you must not alter the main function. You may only
add/modify gtest unit tests.
shape.h: This header le contains all the declarations for the base class Shape that represents all shapes.
You must not edit this le.
circle.h: This header le contains the declarations of the Circle class. This class is derived from Shape.
You must not edit this le.
circle.cpp: This le contains the de nitions of functions that belong to the class Circle. You must edit
this le.
rectangle.h: This header le contains the declarations of the Rectangle class. This class is derived from
Shape. You must not edit this le.
rectangle.cpp: This le contains the de nitions of functions that belong to the class Rectangle. You
must edit this le.
rightangle.h: This header le contains the declarations of the RightAngle class. This class is derived from
Shape. You must not edit this le.
rightangle.cpp: This le contains the de nitions of functions that belong to the class RightAngle. You
must edit this le.
assignment10.h: This le contains the declarations of the class ImageMask. You may edit this le for
your implementation. However, your tests will be compiled with implementations that use
the original version of the le that is provided in the starter code.
assignment10.cpp: This le contains the de nitions of the class ImageMask. You must edit this le.
reference_solution: This is a pre-compiled reference implementation executable that you can use to
compare the performance of your code against.
main.cpp: This le provides a main function with the necessary functionality to create an interactive GUI
to draw mask shapes using a GUI, and see the result.
This le will not be submitted. All unit tests must be in assignment10Tests.cpp
You can compile the unit tests using the command:
1 clang++ -std=c++11 assignment10Tests.cpp assignment10.cpp circle.cpp rectangle.cpp
rightangle.cpp -lpthread -lgtest -lX11 -o assignment10,!
You can compile the interactive GUI main program using the command:
1 clang++ -std=c++11 main.cpp assignment10.cpp circle.cpp rectangle.cpp
rightangle.cpp -lpthread -lgtest -lX11 -o assignment10,!
4 Evaluation Criteria
You will be evaluated based on the following criteria:
1. Your code for image masking and implementing the shapes will be checked for correctness using our
unit tests. This portion will be worth 40 points.
2. Memory Leaks - 10 points. We will be checking for memory leaks using the unit testing executable -
this includes both your code to implement the shapes and masking, as well as your unit tests.
3. Your Unit Tests will be run with 2 correct and 2 incorrect implementations. Please remember that
these implementations will stick to the speci cations provided in the assignment handout. This will
be worth 20 points.
8
4. Your Random Tests will be run with the same implementations as above. Please remember that these
implementations will stick to the speci cations provided in the assignment handout. This will be worth
10 points.
5. The execution time of ApplyMasks will be compared to the reference solution provided. Similar or
better performance will obtain 20 points.
6. You may earn up to 10 points of extra credit for correctly implementing GetAreaColored.
5 What To Turn In
Using the provided submission script. submit.sh, the les assignment10.h, assignment10.cpp,
assignment10Tests.cpp, circle.h, circle.cpp, rectangle.h, rectangle.cpp, rightangle.h,
rightangle.cpp and shape.h will be checked to see if they compile, and if successful, will be added to an
archive, assignment10.tar.gz. You must upload this archive to Moodle.