CS 4810: Introduction to Computer Graphics
In this assignment you will create a simple image processing program, a pared-down version of Adobe Photoshop or The Gimp. The operations that you implement will be mostly filters which take in an input image, process the image, and produce an output image.
The code skeleton can be downloaded here.
An overview of the code you will be using can be found here.
Some test images can be found here.
Examples of what some of the results should look like can be found here.
You should use the code skeleton as a starting point for your assignment. We provide you with several files, but you should only have to change
main.cpp: Parses the command line arguments, and calls the appropriate image functions.
Util/cmdLineParser.[cpp/h]: Code for processing the command line arguments.
JPEG/*.[cpp/h]: Functions for the back end of jpeg file reading and writing. You won't need to modify these, but you will have to compile them into a library to support reading and writing files in this format.
Image/bmp.[cpp/h]: Functions to read and write Windows 24-bit BMP files.
Image/jpeg.[cpp/h]: Functions to read and write jpeg images.
Image/image.[cpp/h]: Image processing code.
Image/lineSegments.[cpp/h]: Line segment processing code.
Image/image.todo.cpp: Code stubs for image processing that you will need to implement.
Image/lineSegments.todo.cpp: Code stubs for line segment processing that you will need to implement.
assignment1.dsw: Workspace file suitable for Visual C++ on Windows 2000 platform.
JPEG/Makefile: The makefile for compiling the
JPEGlibrary under Unix.
Makefile: The makefile for compiling the
assignment1executable under Unix (use 'gmake' to build!!).
After you copy the provided files to your directory, the first thing to do is compile the program. To do this, you will first have to compile the
JPEGlibrary and then compile the
assignment1executable.On a Windows Machine
Begin by opening
Assignment1.slnusing Microsoft Visual Studio.
Build -> Build Solutionor
Ctrl + Shift + B. (If it has not been compiled yet, this will also compile the
JPEGlibrary.)On a Unix Machine
maketo compile the
Assignment1executable. (If it has not been compiled yet, this will also compile the
The user interface for this assignment was kept to the simplest possible, so you can concentrate on the image processing issues. The program runs on the command line. It reads an image from a specified file, processes the image using the filter specified by the command line arguments, and writes the resulting image to the specified file.
The command line parser is set up to read the arguments from the command line that are specified in the following format: First the parameter name is specified by pre-pending with two hyphens, and then the parameter values are enumerated. (Note that the number of arguments associated to each parameter are fixed in
main.cppand the order in which the parameters are specified is ignored.)
For example, to increase the brightness of the image
in.bmpby 10%, and save the result in the image
out.bmp, you would type:To see the full list of possible arguments, you can simply type:
% Assignment1 --brighten 1.1 --in in.bmp --out out.bmpThis gives you a list of all the possible parameter names and the number and meaning of the associated parameter values. Bracketed parameters are optional (an input image file and an output image file need to be specified).
Note that since the order in which parameters are specified is ignored, if you want to apply two filters to a single image you can specify parameters for both filters, but you cannot control the order in which the filters are applied. For some filters, the order in which the filters are applied does not affect the output image while for others, the output image may depend on the order. (For the latter case, you can control the ordering by applying one filter, writing the output to a temporary image, and then applying the second filter to the temporary image.)
main.cppdecides if the specified image file is Windows BMP file or a JPEG file based on the file extension.
The assignment is worth 30 points. The following is a list of features that you may implement (listed roughly from easiest to hardest). The number in front of the feature corresponds to how many points the feature is worth.
The assignment will be graded out of 30 points. In addition to implementing these features, there are several other ways to get more points:
- (1) Image32::AddRandomNoise (
Add random noise to an image.
- (1) Image32::Brighten (
Individually scale the RGB channels of an image.
- (1) Image32::Luminance (
Change a color image into a luminance (grayscale) image.
- (1) Image32::Contrast (
Change the contrast of an image. (See Graphica Obscura.)
- (1) Image32::Saturate (
Change the saturation of an image. (See Graphica Obscura.)
- (1) Image32::Crop (
Extract a subimage specified by two corners
- (2) Image32::Quantize (
Change the number of bits per channel of an image, using simple rounding.
- (2) Image32::RandomDither (
Convert an image to a given number of bits per channel, using a random threshold.
- (2) Image32::OrderedDither2x2 (
Convert an image to a given number of bits per channel, using a 2x2 ordered dithering matrix.
- (2) Image32::FloydSteinbergDither (
Convert an image to a given number of bits per channel, using dithering with error diffusion.
- (2) Image32::Blur3x3 (
Blur an image by using a 3x3 mask of weights as a filter.
- (2) Image32::EdgeDetect3x3 (
Detect edges in an image by using a 3x3 mask of weights as a filter.
- (1) Image32::NearestSample (
Return the value of the pixel closest to the position
- (1) Image32::BilinearSample (
Return the value of the pixel obtained by interpolating the values of the four pixels closest to the position
- (1) Image32::GaussianSample (
Return the value of the pixel obtained by computing the weighted average of all pixels whose distance is less than
radiusfrom the sample point
(x,y)using Gaussian weighting where the variance of the Gaussian is specified by
- (1) Image32::ScaleNearest (
Scale an image up or down by a real valued factor using nearest pixel sampling.
- (1) Image32::ScaleBilinear (
Scale an image up or down by a real valued factor using bilinear interpolation.
- (1) Image32::ScaleGaussian (
Scale an image up or down by a real valued factor using Gaussian sampling. (Make sure to choose the variance of the Gaussian and the radius of weighting so that they correspond to the scale factor in a meaningful way.)
- (2) Image32::RotateNearest (
Rotate an image by a given angle about the center pixel using nearest pixel sampling.
Note: You may have to resize the image as the dimensions of the output image need not be the same as the dimensions of the input image.
- (2) Image32::RotateBilinear (
Rotate an image by a given angle about the center pixel using bilinear interpolation.
- (2) Image32::RotateGaussian (
Rotate an image by a given angle about the center pixel using Gaussian sampling.
- (1) Image32::SetAlpha and Image32::Composite (
Compose two images by overlaying the target image over the source.
Note: In practice, Windows BMP files and JPEG files only specify 3-channel, RGB (no alpha), images. Thus, in order to generate an image with an alpha-channel, composition is performed by calling something akin to:%assignment1 --in source.bmp --composite overlay.bmp matte.bmp --out out.bmpThen, in
main.cpp, the method
Image32::SetAlphais called to set the alpha-channel of the image
overlay.bmpusing the image
matte.bmp. This generates a 4-channel, RGBA, image that is passed along to
- (1) Create a composite image of yourself and a famous person.
- (2) Image32::FunFilter (
Warp an image using a non-linear mapping of your choice (examples are fisheye, sine, bulge, swirl).
- (6) Beier-Neely Morphing:
Morph two images using the method in Beier Neely's Feature-based Image Metamorphosis.
See this page for more information about the command line, input options, and some test cases.
To make your life easier, the
Image32::BeierNeelyMorphfunction already has a body which interpolates the line segments, calls the warping function
Image32::Warpand then cross-dissolves the resultant images by calling
OrientedLineSegmentPairs::getSourcePositionwhich determines the position of the source pixel given the position of the target.
In order to get this function to actually return the desired image, you will need to implement the following methods:
- OrientedLineSegment::length (
This method returns the length of the line segment.
- OrientedLineSegment::distance (
This method returns the shortest distance from the point
(x,y)to the line segment.
- OrientedLineSegment::getPerpendicular (
This method writes the coordinates of the unit-vector perpendicular to the direction of the line segment.
Note: When implementing this method, be sure to choose the orientation of the perpendicular vector consistently.
- OrientedLineSegment::GetSourcePosition (
This method uses a single pair of source and target line segments to define the position of the source pixel, given the position of the target pixel. (To change the way in which the blending occurs, you will want to change the default values of the parameters
- Image32::Warp (
This method uses a set of oriented line segment pairs to warp the current image. In order to implement this method you will most likely want to call
OrientedLineSegmentPairs::getSourcePositionwhich returns the position of the source pixel you want to sample at in order to compute the color value at the target. (Assuming that you have implemented
OrientedLineSegmentPairs::getSourcePositionmethod should not need any implementation.)
- Image32::CrossDissolve (
This static method takes in two images and a cross-disolving value in the range [0,1], and generates the specified blend of the two images.
For images or movies that you submit, you also have to submit the sequence of commands used to created them, otherwise they will not be considered valid.
- (1) Submitting one or more images for the art contests.
- (1) Submitting a
.gifmovie animating the results of one or more filters with continuously varying parameters. You can generate such a video by outputting the results of your filter in JPEG format and then using an executable such as FFmpeg or JPGAvi which stitches together a collection of JPEG files into a single movie. Alternatively, if you are a Linux user, you can use the
mpeg_encodecommand or The Gimp to produce an animated gif for your results.
- (2) winning the regular art contest,
It is possible to get more than 30 points. However, after 30 points, each point is divided by 2, and after 32 points, each point is divided by 4. If your raw score is 29, your final score will be 29. If the raw score is 33, you'll get 31.25. For a raw score of 36, you'll get 32.
Submission intstructions are specified here.
Please include the following in your submission:
- the complete source code;
.bmpimages (source and dest) for the image processing features (you can alternatively submit .png or .jpg files);
.bmpimages (source, overlay, and matte) for the compositing feature (you can alternatively submit .png or .jpg files);
- the line files for the morph feature and 10
.jpegimages showing the morph between two images at 10 different time-steps (optional);
.mpegmovie or animated .gif for the movie feature (optional);
- the images for the art contest (optional); and
- a writeup.