Saint Louis University |
Computer Science 2100
|
Dept. of Math & Computer Science |
Please see the general programming webpage for details about the programming environment for this course, guidelines for programming style, and details on electronic submission of assignments.
For this assignment, you are allowed to work with one other student if you wish (in fact, we suggest that you do so). If any student wishes to have a partner but has not been able to locate one, please let the instructor know so that we can match up partners.
Please make sure you adhere to the policies on academic integrity in this regard.
For this assignment, we are going to use another of the programming contest problems, and a fun one, but one that will take more time (and which deserves more credit) than our typical 50-minute lab.
So this is being elevated to "Programming Assignment" status. As such, I will also grade the source code more critically than I do for the typical lab. That is, I would ideally like for you to get the program working and passing the judge's tests, but even so, the grade will include an evaluation of the clarity and organization of your source code.
I would also like to stress the standard policy on academic integrity, in that a pair of students collaborating for this assignment must not coordinate with any other students, and must not seek any solutions online.
The problem we are using comes from our midwest region in 2010. It looks like a very complex problem, but it turns out to have a rather simple and elegant solution via recursion. By the end of the 5-hour contest, 26% of the teams had successfully completed it. Of course, the other might not have recognized the recursive solution. In the rest of this section, we provide the official problem statement. But please make sure to read my own advice, which follows the official problem statement, as that gives you a roadmap for success.
Source code: | compress.cpp |
Strategies for compressing two-dimensional images are often based on finding regions with high similarity. In this problem, we explore a particular approach based on a hierarchical decomposition of the image. For simplicity, we consider only bitmapped images such as the following:
The image is encoded as a tree, with the root representing the entire image region. If a region is monochromatic, then the node for that region is a leaf storing the color of the region. Otherwise, the region is divided into four parts about its center, and the approach is applied recursively to each quadrant. For a non-leaf node, its four children represent the four quadrants ordered as upper-right, upper-left, lower-left, lower-right respectively. As an example, here is the tree encoding of the above image.
As a larger example, here is an 8x8 image and the tree encoding of it.
Thus far we have described a lossless compression scheme, but the approach can be used for lossy compression with the following adjustment. Instead of continuing the decomposition until reaching a monochromatic region, a threshold such as 75% is used, and a leaf is created whenever a region has at least that percentage of either color. As an example, here is the encoding of the above 8x8 image if using 75% as the threshold.
Your goal is to determine the image that results from this lossy compression scheme, given an original bitmap image and a specific threshold percentage.
Input:
The input will consist of a series of data sets, followed by a line
containing only 0. Each data set begins with a line containing values
W and T, where W is the width of the bitmap and T is the threshold
percentage. Images will always be square with
Output: For each data set, you should print an initial line of the form "Image 1:" numbering the images starting with 1. Following that should be W lines, with each line representing a row of the resulting bitmap as a string of characters 0 and 1, from top to bottom.
Example Input: | Example Output: |
4 80 0000 1000 0011 0011 8 75 11111000 11110000 11000011 11000011 11000100 00000100 00010011 00010011 4 75 1101 1111 0111 0011 0 |
Image 1: 0000 1000 0011 0011 Image 2: 11110000 11110000 11110011 11110011 00000100 00000100 00000011 00000011 Image 3: 1111 1111 1111 1111 |
The first thing I wish to point out is that a solution to this problem does not require the use of any tree data structures! Although we will soon discuss trees, and they are a valuable structure, they simply are not needed here (and time devoted to writing such a data structure would be wasted). Admittedly, the description of the problem may lead readers astray, given the many pictures of trees that are drawn along the way. But the tree can be thought of as a simple conceptual approach for describing the hierarchical (i.e., recursive) decomposition of an image.
All you need for a data structure is a simple array (or vector) of strings. Read each line as a string, and then you have a sequence of lines. That provides a great data structure, as you can use a syntax such as image[r][c] to describe the 0/1 character that is in row r, column c (zero indexed, of course). Furthermore, strings in C++ are mutable, so you are welcome to edit those characters.
The real work for transforming the image can be accomplished recursively. At face value, assuming your job is to transform the entire image. What you can do is count up the number of 0 and 1 characters that occur. If either of those totals reaches the threshold, then you turn the entire image to the dominant color. Otherwise, you simply make four recursive calls, one for each quadrant, and you are done. (I should note that as a base case, a one-by-one portion of the image will have 100% saturation of one of the two colors).
The key is to define the recursive parameterization. You should avoiding making independent copies of quadrants of an image. Instead, send a reference/pointer to the original image throughout the recursion, but with additional parameterization that defines the scope of one recursive call to a portion of the original image. For inspiration, review the coverage of recursion from Chapter 3, and the way that it defines several recursions on a one-dimensional array by passing the entire array recursively, but with additional parameters to define the scope of a recursive computation.
Note as well that if each level of recursion has a pointer or reference to the original underlying image representation, then the purpose of the recursive call can be to overwrite overwrite its portion of the image with the updated values, so that by the end of the entire process, the original image will have been transformed.
Although this is a programming assignment, not a lab, you are still welcome to test your program on the official program contest judges' tests by using our usual technology on turing:
/Public/goldwasser/2100/labs/judge compress.cpp
We'll also break with usual contest protocol and disclose the secret judges input and output (not that its easy to manually examine such big images).
Source Code
Submit your self-contained compress.cpp file.
"readme" file
Discuss the dynamics of your partnership, an overview of your
final product, and any further comments you
wish to make to the grader.
The assignment is worth 20 points.