C++ pic
PA#2/ PA#2.docx
This assignment is a continuation of lab 4. In this homework, you will create a program that will add simple effects to a PPM image.
Prerequisites
Before beginning this assignment, you will need some sort of imaging software that can open PPM- based images. I recommend Ifranview for Windows as it's free and lightweight.
PPM Image Format
The PPM image format is encoded in human-readable ASCII text. It might be helpful to read over the formal PPM specification document. A PPM document has two pieces: the header and the body. The header is always the top three uncommented lines in the file:
The first line specifies the type of image that is contained within the file. We will always use the "P3" specification. The second line specifies the number of columns and rows present in the image. In this example, we have a 4x4 image. The final number indicates the maximum value for each red, green, and blue element in the picture. Having a max value of 255 is quite common and is the value that we will always use. Below the header is the body of the PPM file. Each pixel has a red, green, and blue value. For example, the content of our 4x4 image might be:
P3 44 255
000 10000 000 255 0255 000 0255175 000 000 000 000 015175 000 255 0 255 0 0 0 0 0 0 255 255 255
With these values, the pixel in the first column and row has a RGB value of (0,0,0) and the last column in the first row has an RGB value of (255,0,255). A blown-up image containing these values would look like:
Task
Your task is to write a program that will perform the following basic image manipulations on a user specified image. Below is a reference value and the images that result from the image processing.
Original Image
Remove Red
Will remove all red (i.e. set red to 0) pixels in the image
Remove Green
Will remove all green pixels in the image
Remove Blue
Will remove all blue pixels in the image
Negate Red
Will negate all red pixels in an image. To negate a color, simply subtract the current pixel's red color value from 255.
Negate Green
Will negate all green pixels in an image.
Negate Blue
Will negate all blue pixels in an image.
Add Random Noise
Will add random noise to the image by randomly selecting a value ranging from -10 to 10 and adding that value to the pixel's current value. If the addition causes the pixel value to be less than 0, then set to 0. Likewise, if the addition causes the pixel's value to be greater than 255, just set the pixel's value to 255. For example, we randomly generate the number -7. Next, we add -7 to each of the current pixel's red, green, and blue values.
High Contrast
Examine each color in a pixel. If the color is greater than half of 255, then max the color out (i.e. set to 255). Otherwise, set the value to 0. For example, performing a high contrast operation on a pixel whose RGB values are 170, 50, 100 would result in an RGB value of 255, 0, 0.
Grayscale
Converts the image to grayscale by setting the value of each color in a given pixel to the average of all three values. For example, if a pixel's RGB was 177, 15, 39, the resulting RGB value would be 77, 77, 77.
BONUS - Flip Horizontal
Flips the image along the horizontal axis.
BONUS - Flip Vertical
Flips the image along the vertical axis.
Chaining Effects Together
Note that manipulations can be chained together. Below is the image generated from performing a negate red, negate green, and negate blue operation.
UML Diagram
In order to complete this assignment, you must develop and implement the following classes:
Note that it might help to zoom in on the UML diagram. We start with the Point class that we developed in Lab 4. In the center, we have the SimpleImageEffect interface that defines a single pure virtual function called processImage. Each effect described in the previous section derives itself from SimpleImageEffect, implementing the processImage method in such a way to fulfill its role (e.g. NegateRedEffect will negate all red pixels in the image). Note that while a factory-type class isn't defined, it may be useful for you to write one.
Also note the white diamond going from SimpleImageEffect to Point. This is called "aggregation" and is another form of a "has-a" relationship. The main difference between aggregation and composition (black diamond) has to deal with the lifespan of an object. A black diamond means that the object goes out of scope at the same time as the owner class. A white diamond means that the object stays alive even when the owner class goes out of scope. If you think about the lifespan of a Point, it is easy to see that a given Point will exist for a longer period than the SimpleImageEffect. This makes sense as the Point still needs to be written to the output file!
Getting Your Code to Work with HackerRank
In order to make your code work both inside and outside of HackerRank, the first thing you'll need to do is to determine whether or not the input is coming from cin or from a file. HackerRank expects
everything to come in via cin while a normal program would expect data to come in via a file object. As such, your program should start off by asking the user where data will be read (see screenshot below).
Sample Output
Note that the program allows for unlimited effects to be added to a given image. Also note that some of these effects might take a while for your computer to process!
Possible Strategy for Getting Started
If you're feeling overwhelmed, try implementing one of the more simplistic image effects (e.g. remove red) inside of main. Once you get that working on a PPM file, put the necessary code into its own class and .h file.
Alternatively, do the image effects last. Instead, work on file processing. Spend time making sure that you can open and write PPM files.
Also, use Lab 4 as a template. Most of the ideas we covered in lab can be directly applied to the solving of this assignment. Header Comment, and Formatting
1. Be sure to modify the file header comment at the top of your script to indicate your name, student ID, completion time, and the names of any individuals that you collaborated with on the assignment.
2. Remember to follow the basic coding style guide. A basic list of rules is included with this document.
Reflection Essay
In addition to the programming tasks listed above, your submission must include an essay that reflects on your experiences with this homework. This essay must be at least 350 words long. Note that the focus of this paper should be on your reflection, not on structure (e.g. introductory paragraph, conclusion, etc.). The essay is graded on content (i.e. it shows deep though) rather than syntax (e.g. spelling) and structure. Below are some prompts that can be used to get you thinking. Feel free to use these or to make up your own.
Describe a particular struggle that you overcame when working on this programming assignment.
Conversely, describe an issue with your assignment that you were unable to resolve.
Provide advice to a future student on how he or she might succeed on this assignment.
Describe the most fun aspect of the assignment.
Describe the most challenging aspect of the assignment.
Describe the most difficult aspect of the assignment to understand.
Provide any suggestions for improving the assignment in the future. Deliverables You must upload your program and reflection as a ZIP file through Canvas and your code through HackerRank no later than midnight on Thursday, March 2, 2017. Remember that your submission must either contain a CodeBlocks, Netbeans, or Visual Studio project file! Grading Criteria Your assignment will be judged by the following criteria: Reflection essay (5pts)
Your reflection meets the minimum requirements as specified earlier in this document.
Style (20pts)
Your project contains good structure and implements the required classes. Your program intelligently uses classes when appropriate and generally conforms to good OOP design (i.e. everything isn't slapped into main).
HackerRank Test Cases (75pts)
Your program successfully passes all test cases
EXTRA CREDIT (5pts)
[1/2 credit] You add either the ability to flip the image horizontally or vertically. [full credit] You add the ability to flip the image both horizontally and vertically.
Grade Distribution
Your final grade for the assignment will be determined based on the number of points earned. Note that failing to use good design (e.g. objects, appropriate data structures), regardless of score earned, may result in a lower overall grade.
90 80
70
70 55
40
50 25
25 15
Score Points Required
100
85
80
60
40
20
image4.jpeg
image5.jpeg
image6.jpeg
image7.jpeg
image8.jpeg
image4.png
image9.jpeg
image5.png
image6.png
image10.jpeg
image7.png
image8.png
image9.png
image10.png
image11.png
image12.png
image13.png
image14.png
image15.png
image16.png
image17.png
image18.png
image19.png
image1.png
image2.png
image3.png
image1.jpeg
image2.jpeg
image3.jpeg
__MACOSX/PA#2/._ PA#2.docx
PA#2/.DS_Store
__MACOSX/PA#2/._.DS_Store
PA#2/bunny.ppm
__MACOSX/PA#2/._bunny.ppm
PA#2/LAB4.docx
Lab #4
This lab is intended to get you started on PA #2. To this end, Lab 3 introduces you to the portable pixel map (PPM) image format and basic image manipulation.
Goals
In completing this lab, you will have been exposed to the following:
Test-driven development
PPM image format
File processing
Object-oriented design
Inheritance
Polymorphism Prerequisites Before beginning this lab, you will need some sort of imaging software that can open PPM-based images. I would recommend Ifranview for Windows as it's free and lightweight. PPM Image Format The PPM image format is encoded in human-readable ASCII text. It might be helpful to read over the formal PPM specification document. A PPM document has two pieces: the header and the body. The header is always the top three uncommented lines in the file: The first line specifies the type of image that is contained within the file. We will always use the "P3" specification. The second line specifies the number of columns and rows present in the image. In this example, we have a 4x4 image. The final number indicates the maximum value for each red, green, and blue element in the picture. Having a max value of 255 is quite common and is the value that we will always use. Below the header is the body of the PPM file. Each pixel has a red, green, and blue value. For example, the content of our 4x4 image might be:
P3 44 255
000 10000 000 255 0255 000 0255175 000 000 000 000 015175 000 255 0 255 0 0 0 0 0 0 255 255 255
With these values, the pixel in the first column and row has a RGB value of (0,0,0) and the last column in the first row has an RGB value of (255,0,255). A blown-up image containing these values would look like:
Task
Your task for this lab is to write an image effect that removes all green from a given image. Note that this can be accomplished by simply setting the green value in each RGP triplet to zero.
UML Diagram
Below is a UML diagram for the lab. While it is most certainly overkill for this lab task, it sets you up nicely to complete the homework assignment.
Note that we use the Point class to represent a given RGB triplet in the PPM file. We create the SimpleImageEffect interface to represent a given image effect (the HW has many more) with RemoveGreenEffect being a concrete implementation of a given image effect. Note that the processImage function should process the PPM one line at a time.
Expected Output (for Hacker Rank)
Hacker Rank has its own simplified tests for your program to pass. These test cases can be found by following this link.
Sample Output (for testing)
Below is a screenshot of my lab along with the input and output files:
Note that the "parsing" stage may take a while (several seconds).
Bunny.ppm
This is the original bunny file:
Bunny_out.ppm
And the image with green removed:
image1.jpeg
image2.jpeg
image1.png
image2.png
image3.png
image4.png
image5.png
image6.png
__MACOSX/PA#2/._LAB4.docx
PA#2/main/main.cpp
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: main.cpp * Author: asc564 * * Created on February 13, 2017, 5:12 PM */ #include <cstdlib> #include <string> #include <vector> #include <fstream> #include <sstream> #include <iostream> #include "Point.h" #include "RemoveGreenEffect.h" using namespace std; //converts a string-based line into a vector of INTs vector<Point> parse_line(string line) { istringstream scanner{line}; vector<Point> result{}; int red; int green; int blue; //read all ints present on the line while(scanner.good()) { scanner >> red; scanner >> green; scanner >> blue; Point p{ red, green, blue }; result.push_back(p); } return result; } /* * */ int main(int argc, char** argv) { string line = ""; //throw all lines into a vector of strings vector<string> lines_in_file{}; SimpleImageEffect *effect = nullptr; //TODO: use menu to alter effect. For now, hard code to green effect = new RemoveGreenEffect{}; getline(cin, line); while(line.length() > 0) { lines_in_file.push_back(line); getline(cin, line); } //lines_in_file should contain all lines in our PPM //[0] - PPM spec //[1] - dimension //[2] - max RGB value //[3]+ - pixels //output back to cout cout << lines_in_file[0] << endl; cout << lines_in_file[1] << endl; cout << lines_in_file[2] << endl; //output back the pixels for(int i = 3; i < lines_in_file.size(); i++) { //convert text into a series of numbers vector<Point> points = parse_line(lines_in_file[i]); //apply image effect effect->processImage(points); //output all values to the screen for(auto p : points) { //with java-style call cout << p.toString(); //with c++ style call //cout << p; cout << endl; } } return 0; }
__MACOSX/PA#2/main/._main.cpp
PA#2/main/Point.h
#ifndef POINT_H #define POINT_H #include <string> #include <sstream> #include <ostream> using namespace std; class Point { private: int _red = 0; int _green = 0; int _blue = 0; public: Point(int r = 0, int g = 0, int b = 0) { _red = r; _green = g; _blue = b; } int getRed() const { return _red; } int getGreen() const { return _green; } int getBlue() const { return _blue; } void setRed(int r) { if (r >= 0 <= 255) { _red = r; } } void setGreen(int g) { _green = g; } void setBlue(int b) { _blue = b; } //Java-style string toString() const { ostringstream output{}; output << _red << " " << _green << " " << _blue; return output.str(); } }; //C++ style ostream& operator<<(ostream &out, const Point& p) { out << p.toString(); return out; } #endif // ! POINT_H
__MACOSX/PA#2/main/._Point.h
PA#2/main/RemoveGreenEffect.h
#ifndef REMOVE_GREEN_EFFECT #define REMOVE_GREEN_EFFECT #include "Point.h" #include "SimpleImageEffect.h" #include <vector> using std::vector; class RemoveGreenEffect : public SimpleImageEffect { public: //note: we're using pass by reference because it's faster //AND it allows us to modify the original point values. virtual void processImage(vector<Point> &points) { for (Point& p : points) { p.setGreen(0); } } }; #endif // !SIMPLE_IMAGE_EFFECT_H
__MACOSX/PA#2/main/._RemoveGreenEffect.h
PA#2/main/SimpleImageEffect.h
#ifndef SIMPLE_IMAGE_EFFECT_H #define SIMPLE_IMAGE_EFFECT_H #include "Point.h" #include <vector> using std::vector; class SimpleImageEffect { public: //note: we're using pass by reference because it's faster //AND it allows us to modify the original point values. virtual void processImage(vector<Point> &points) = 0; }; #endif // !SIMPLE_IMAGE_EFFECT_H