Introduction |
This programming assignment covers little new material, but its scale is
much larger.
You will write only one program, but it will comprise about two dozen
interrelated classes and interfaces, some that you will write for the
assignment and some that are already written by me (but, you will have
to read, understand, and correctly use them).
Primarily you will write a Model class that manipulates arrays of pictures,
which are themselves represented by 2-d arrays of pixels; there will
plenty of opportunity for interesting looping code (e.g., nested for
loops and the interaction between 1-d and 2-d structures).
I provide a Picture class, which can read, manipulate, and display .jpeg images. . Picture manipulation is accomplished via the Red, Green, and Blue (RGB) components of every pixel in the picture (typically there are tens of thousands of these, even in small photos). The model is driven by a text-only view, allowing the user to execute a variety of methods, selected from a menu displayed on the console. Later in the semeseter, when we learn about Java controls and graphics, we will write a matching GUI View and Controller for this Model. The assignment is to write a general purpose program that produces photomosaics. A photomosaic is large picture that is constructed from a a collection of smaller pictures. When an aesthetically pleasing photomosaic is viewed closely, the observer can identify the contents of each of the small pictures. When viewed from far away, these small pictures lose their detail, but the observer sees their gross visual characteristics fit together to form one large picture, whose overall image is clearly visible. The actual assignment is to produce a photomosaic of yourself. . We will use a variety of data, from the trivial (blobs of b/w or color images) to b/w pictures of your fellow students (taken from this year's CMU Pic Book -I've got data for past years as well), to collections of color cd/video covers. You might want to search the web for databases of pictures; a requirement is that each picture in the collection should have the same aspect ratio (width/height). Basically, a program that produces a photomosaic works as follows. It must first read and store a big database of small pictures (typically thousands). Then it must read a large picture to render as a photomosaic. Then, it must scan all the disjoint regions that comprise the large picture and find for each region the the small picture in the database that best matches it (there are various metrics), possible subject to other constraints like how often a picture can be used and if multiple uses are allowed, how far away they must be from each other. Finally, it must build a large picture (the photomosaic) by appropriately overlaying these small pictures onto a blank canvas. The details are discussed in the next major section. Each class described below is either in a package in the Java standard or the course library (edu.cmu.cs.pattis.cs151xx), or is in the photomosaic package specific to this project.
You need to modify only the files Model.java, PhotomosaicInfo.java, RBGMetric.java, and MetricFactory.java. You should NOT modify any of the other classes that I have provided unless you make the case to me that the class needs to be more general (in which case I might modify it myself or replace it with your modification so that other students can use it). You can download the Javadoc for the prewritten classes supplied in this assignment, which contains documenation for all these classes. This shows all the package-friendly entries, because you are reading this code as the writer/maintainer of the photomosaic package. Some classes are fully documented (in English) others just contain the information automatically generated by Javadoc. Click on the index.html file that it contains to bring up the Javadoc. As you already know, navigating and reading Javadoc files are activities that all programmers must repeatedly perform, so this is another opportunity to build your skill doing so. You might even want to print some of the more important documentation. As always, you can check the behavior of your programs against mine by downloading and running my Executable, to help you understand the specification of the problem and observe the programmer/user interaction you are to implement |
Details: Running the Program |
To discuss the details of this program, first we examine a transcript of
a short but typicaly user-interaction with it on the console.
Notice that the "view" is just a text-only interface runing on the console,
prompting for which method to call and the parameters necessary to call
it.
The executable download contains cmu.gif which is the picture
used below.
Running your program should produce an equivalent transcript.
photomosaic.Model methods ? - Comparators, Filters, and Metrics r - resetPictureDatabase l - loadMoreInPictureDatabase d - displayPictureDatabase s - shift < - resortPictureDatabase f - setFilter m - setMetric L - loadPictureToRender R - renderPicture q - quit Enter Command[?rlds<fmLRq]: m Enter Metric Name: QuadIntensityMetric model.getResponse() = Metric set and applied to all Database Pictures photomosaic.Model methods ? - Comparators, Filters, and Metrics r - resetPictureDatabase l - loadMoreInPictureDatabase d - displayPictureDatabase s - shift < - resortPictureDatabase f - setFilter m - setMetric L - loadPictureToRender R - renderPicture q - quit Enter Command[?rlds<fmLRq]: f Enter Filter Name: GrayScaleFilter model.getResponse() = Filter set (applied to subsequent pictures only) photomosaic.Model methods ? - Comparators, Filters, and Metrics r - resetPictureDatabase l - loadMoreInPictureDatabase d - displayPictureDatabase s - shift < - resortPictureDatabase f - setFilter m - setMetric L - loadPictureToRender R - renderPicture q - quit Enter Command[?rlds<fmLRq]: l Enter width for Picture DB images (in pixels)[1,1000](13): Enter height for Picture DB images (in pixels)[1,1000](16): See Picture Database Selection pop-up window Attempting to load 824 pictures Loaded 50 pictures Loaded 100 pictures Loaded 150 pictures Loaded 200 pictures Loaded 250 pictures Loaded 300 pictures Loaded 350 pictures Loaded 400 pictures Loaded 450 pictures Loaded 500 pictures Loaded 550 pictures Loaded 600 pictures Loaded 650 pictures Loaded 700 pictures Loaded 750 pictures Loaded 800 pictures Loaded 824 pictures model.getResponse() = 824 pictures displayed 824 pictures loaded: Picture Databse now contains 824 pictures model.getResponse() = 824 pictures loaded: Picture Databse now contains 824 pictures photomosaic.Model methods ? - Comparators, Filters, and Metrics r - resetPictureDatabase l - loadMoreInPictureDatabase d - displayPictureDatabase s - shift < - resortPictureDatabase f - setFilter m - setMetric L - loadPictureToRender R - renderPicture q - quit Enter Command[?rlds<fmLRq]: L See Picture to Render Selection pop-up window model.getResponse() = Picture C:\Documents and Settings\Administrator\Desktop\ executable\cmu.gif loaded for rendering photomosaic.Model methods ? - Comparators, Filters, and Metrics r - resetPictureDatabase l - loadMoreInPictureDatabase d - displayPictureDatabase s - shift < - resortPictureDatabase f - setFilter m - setMetric L - loadPictureToRender R - renderPicture q - quit Enter Command[?rlds<fmLRq]: R Picture to Render is 504 x 449 Enter # pixels for width in sample[1,504](13): Sample height (conforming to image database) 16 Rendered picture will contain 1064 tiles: 38 x 28 Enter maximum # of times to reuse any picture[2,1064](2): 100 Enter minimum distance between picture reuse [1.0,38.0](1.0): Rendering 0 percent done Rendering 10 percent done Rendering 20 percent done Rendering 30 percent done Rendering 40 percent done Rendering 50 percent done Rendering 60 percent done Rendering 70 percent done Rendering 80 percent done Rendering 90 percent done Rendering 100 percent done model.getResponse() = Picture C:\Documents and Settings\Administrator\Desktop\ xecutable\cmu.gif rendered and displayedFirst, the user specifies the metric to use when pictures are compared. Here the QuadIntensityMetric is selected, which is the best one I've written for b/w photos. Second, the user specifies the filter to use on the small and large pictures to be loaded. Here the GrayScaleFilter is selected, which converts color images to b/w (and leaves b/w images unchanged). Third, the user specifies to load "more" pictures into the database, which actually starts empty. The user specifies the number of pixels for each small picture (see the Javadoc for Prompt for interpreting the values in brackets and parentheses). As each actual small picture is read, it is resized to fit the specified size. Here I am using Picbook 2003 photos (see below), which are 127x165 rectangles, so pixel sizes of 13x16, 25x33, etc. are all reasonable values to enter here (keep the aspect ratio width/height at 127/165: these pictures are higher than they are wide). Then a file-selection window pops up (it is mentioned in the console); the user can select a folder (or multiple files) containing the database of pictures to use when constructing photomosaics; then the user presses the Load Picture(s) button. The program traces loading every 50 images This is called a heartbeat (so you know the program is running). It also printis the number of pictures loaded and the total number of pictures in the database (we can perform this load operation any number of times, to keep increasing the size of the small picture database). When finished, it displays an approximately square window, populated by all the small pictures read into the database (labelled by the width x height of the entire window, measured in pixels).
Fourth, the user specifies to load a picture to render. Another file-selection window pops up (it is mentioned in the console); the user can select a single file containing the picture to render as a photomosaic (the one to approximate by all the images loaded earlier); then the user presses the Load Picture button. This picture is displayed in a window, labelled by the file read and its width x height measured in pixels.
Finally, the user specifies to render the picture as a photomosaic. The program first prompts for the # of pixels wide to sample in the large picture for each small picture. Here the picture's width is 504 pixels, if I chose a sample width that was 10 pixels, I'd have 50 (504/10) small pictures in each row of the photomosaic; instead I chose the default (13), so the photomosaic will have 38 (504/13) small pictures in each of its rows. Given the entered sampling width, the sampling height is fixed at 16 (according to the aspect ratio 13/16 of each small picture); thus, the photomosaic will have 28 (449/16) small pictures in each of its columns. Yielding a total of 1064 (38x28) small pictures in the photomosaic. Notice that the default values in these prompts are choosen to create a photomosaic that is about the same size (measured in pixels) as the original. It will be actually 494 (13x38) x 448 (16x28) By sampling with different widths, the photomosaic can be made smaller (using a larger width) or larger (using a smaller width) than the original picture to be rendered. The program determines the number of pixels high to sample (keeping the same aspect ratio as the small pictures in the database) and prints this value. Note, if the sample size does not evenly divide the width or height of the picture, it will ignore some pixels at the far right or far bottom of the picture. The program also allows us to specify two extra constraints when rendering the photomosaic. It asks for the maximum number of times to reuse any small picture. Note that with a database of 824 small pictures, and with 1064 small pictures in this photomosaic, we need to use at least some pictures twice; obviously we don't need to use any picture more than 1064 times. "Good" photomosiacs don't use the same pictures over and over, they use all the pictures in the database equally (even better if the database is bigger than the photomosaic, it uses pictures just once or not at all). But, if we use the upper bound here (allowing small pictures to be reused as often as necessary), the rendered image would look best. The user in this run has allowed for a reasonable amount of small picture reuse in this rendering. Finally, the program asks for the minimum distance between reuses of the same small picture (this part, by the way, is extra credit; see below for details). Here the distance is euclidean, measured from the center of each picture (and assumes each picture is 1x1; so the centers of the closest pictures are 1 unit apart; on the diagonal they are sqrt(2), etc.). "Good" photomosiacs, if they do reuse small pictures, don't use the same ones near each other. Note if the minimum distance is 1, then it means that pictures can be repeated with no constraints. The user in this run has allowed for the small pictures to be arbitrarily close (the same as if this constraint were not implemented, since it is extra credit). The program then selects which small pictures appear where in the photomosaic rendering of the large picture (in accordance with the two constaints just entered), printing a hearbeat every time 10% more of the image in completed. It then displays the large picture rendered as a photomosaic. Look closely at this picture to see the individual faces (they are really a bit too small but I had to fit everything on a web page). Then look at the picture from a few yards away, to let the individual pictures meld into the original image.
|
The Model Class |
I wrote a helper class named PhotomosaicInfo; each object stores
(privately, of course) a Picture (don't touch this class) and its
associated information: its metric, and once a rendering is started, how
many times it has been used (and for extra credit, what locations it has
been used at -to see if the distance constraint is met); these last two
values must be reset for each new rendering.
I wrote under a dozen methods to support the behavior of this class, including
one that returns the Picture it stores, so it can be operated on
further.
The Model class itself must support the following methods and signatures. The menu-driven View class calls these methods; later our GUI View class will call exactly the same methods with exactly the same arguments. Mine stores about a dozen instance variables, of which a centrally important one is an array of PhotomosicaInfo. Some methods set these instance variables so that other, called later, can use them: they are used by different behaviors to communicated with each other. Discounting blank/comment lines, I have about 250 lines of code in this class (including imports, lines with just left/right braces on them, etc.); this includes solving the extra credit parts. In fact, removing lines with only left/right braces knocks the count down to almost 200.
You must also write a RGBMetric which processes stores three averages: the intensity of all the Red, Green, and Blue components of the pixels. The distance between two such metrics is just the sum of the absolute values of their component differences (e.g., the red intensity of one minus the red intensity of the other). Integrate this class into the MetricFactory class, along with the name QuadRGBMetric (using the QuadMetric to decorate it). Feel free to create any other classes that you might find useful for this project. A large part of this program is familiarizing yourself with this software. Do not write Javadoc code for any of your class, but put in appropriate amount of comments to help YOU write and debug the program. Iterative Enhancement: You must become very familiar with the capabilities of the Picture class before thinking about the rest of the assignment. Experiment with the picture class by writing little programs that solve the following problems.
To start on the actual program, first stub all Model methods. Then implement each in the following order (each builds on the others). Each new method can be tested, via the menu, once the previous ones work.
You'll learn alot about using Picture objects during this phase. Write the picturing matching code to ignore any constraints (allow each small picture to match any number of times, anywhere). Then, add in the constraint of how often a small picture can be used. Then, for extra credit, add in the distance constraint. |
Picture Databases |
I am providing two black/white "picture" databases.
The first is trivial: it consists of a series of 10x10 squares spanning all
possible the gray scale intensities, from 0 to 255.
Although trivial, this database is large enough to use when debugging most
aspects of your program.
You can download these images via
Gray Blobs.
The second picture database is much more interesting: it consists of a series of .jpeg files made by scanning this year's CMU Pic Book. It contains pictures of almost 1,000 students (many from this class). You can download these images via Pic Book. I also have three color databases. You can download 1,000 random colored squares (also 10x10) Color Blobs. You can download 2003 CD cover images (64x64) via CD Covers. You can download 951 Videotape cover images (70x130) via Videotape Covers. You can download 2,505 Holiday cards (35x56) via Holiday Cards. All these can be used in various parts of the assignment. Whenever you are doing something new (either b/w or color), I suggest using the blobs.
|
Software Patents |
Robert Silvers developed computer photomosaics while a graduate student at MIT.
He has been commisioned to create photomosaics for corporate logos, magazine
covers, celebrities, jigsaw puzzles, etc. and has published three books of
his collected works:
Photomosiacs,
Photomosaic Portraits, and
Disney's Photomosaics.
For an interesting essay on Mr. Silvers' work, read Images and Icons: The Making and Unmaking of Pictures for Mass Consumption. Mr. Silver's company, Runaway Technology has patented the realization of computer programs to produce photomosaics. You can download a copy of the Patent and examine it (read its claims). Unlike copyrighted works, there is no "fair use" of patented material for educational purposes. But primarily, patents are designed to protect revenue, which our use of photomosaics as a programming assignment should not affect (in fact one can use Google to find various photomosaic-producing programs available for sale on the internet: I'm not sure what action Mr. Silvers is taking in these cases). Therefore, to keep everyone's legal exposure to a minimum, we should not post any photomosaics on the web or even print any. I will be destroying the ones I brought to class after the assignment. Also, we should not share our code with anyone. If you are still concerned about violating patent law, when you run your photomosaic program, use only the databases of Gray Blobs (or Color Blobs), but no pictures. Because the small pictures are now not really pictures, but gray squares, what you are producing is not really a photomosaic. Interestingly enough, the photomosaic program works regardless of whether the "small pictures" are really pictures or just a mish-mash of pixels. I have mixed feelings about this patent in particular and the general idea of patents on software. I will discuss the US Patent system, and the topic of software patents in general, briefly in class. You might wish to google "Software Patents". I found one interesting web page on Software Patents that is run by the Programmers Freedom League. It contains links to many interesting essays on this topic (most anti-patent). Whether software is patentable is an issue that is hot now, and will be for a long time. For example, Europe will be deciding whther to adopt American-style software patents. Lawrence Lessig, a faculty member at the Stanford Law school has written extensively on the interaction between law and technology. A book I found particular interesting and readable is Lessig, Free Culture: How Big Media Uses Technology and the Law to Lock Down Culture and Control Creativity. |
Extra Credit |
As mentioned above, implementing the distance constraint is extra credit,
worth 1 point.
I will also give 1 point of extra point for rendering the tiles from the middle of the picture outward. This is easy to test: render 0.jpg using 0.jpg, 120.jpg, and 240.jpg: the pattern should approximate a bullseye, with the center matching perfectly, and the matches getting worse as its concentric circles move outward. There is a fairly compact and elegant way to do do this using the Point class, which is in the standard Java library.
|