Now that we've got color, we can move on to a higher level and more interesting application of abstract data types, and that's image processing. In this, immediately, you're going to be able to write programs to process things like pictures that you take with your cell phone. So, we're going to work with an abstract data type that's called a picture. A picture is a two-dimensional array of pixels. Again, it's defined in terms of its set of values. A set of values is 2D arrays of pixels. So, that's what we think of a picture's being. We're going to have an abstract data type that allows us to write programs that manipulate pictures. So, values are 2D arrays of colors. Just to get oriented, we think of this as rows and columns with zero, zero up at the top left. So, we're going to use two indices to refer to the pixel at a particular place. We have its column and we have it's row. That's how we're going to refer to individual pixels, it's got a certain width and a certain height. So, just with that orientation, then we can define the operations that we're going to perform on pictures. First one is a constructor. How do we make a new picture? Well, what we're going to do is take a filename as argument. In that filename, it's going to be an image that comes from your camera, could be jpeg file or other standard file format. Then, once the constructor has made the image, we can think of it as a two-dimensional array of pixels. We could also create a blank one and then, we can ask for the properties of the picture like its width and its height. We can ask for the color of a particular pixel, given a column and row, as long as the column index is within the width and the row index is within the height. We can also set the color of our pixel to be some other color. Then, the other thing we could do is just display the image in a window like Standard Draw. There's also a method in Standard Draw to display pictures, but this just displays the thing in the window. So, those simple operations, again, we don't really care how the picture is represented and how the system gets these jobs done, we can work with pictures just using these very simple operations. Also, we can save any picture that we've created back out to a file. So, here's an example. We're going to do is write a Java program that'll convert an image to grayscale. So, if we take our mandrill, and this image, by the way, is a standard image that has been used for many decades in computer graphics, so that's the one we're using. If you type Java grayscale and give that filename, then it'll give this black and white version. Interesting computation, so you can make black and white versions of photos you take on your phone yourself if you want. So, how do we do that? It's a very simple program. We get access to the job as color module with an import. Then, we just write a main. First of all, it's going to create a new picture and where it's going to get that picture, the first argument is going to be a filename. So, the constructor takes that filename, it's the jpeg file, then it'll use that to create a new picture which now we can manipulate as a 2D array of colors. Now, what we're going to go do is go through, and for every pixel, we're going to get its color. So, we'll go for all columns and for all rows. It's a double index for loop to look at every possible pixel. Our picture is named P-I-C or pic. So, that's stored in a picture object with pic.get that means take that object, and then the dot means means apply the operation to that object, and the get operation gets the color at the given column in a row. So, that returns a color. Then, that's a variable of type Color with a capital C. So, now we're going to compute with that. What do we want to do with that? We want to just go to our luminance library and get the toGray method that we just did that computes the grayscale value. Put that in another color gray. Then, in our picture, we'll call the set method to change the color of that pixel at that column and row index to that gray value, and that's it. When we're done with those for loops, just show the picture and that's it. An extremely simple program to go ahead and compute any color image into a black and white image. Now, let's look at some more examples. Just to warm up to do some more interesting computations, we'll do a little series of pop quizzes. So, let's think about, what's the effect of this code? This is a very easy question. For all the pixels, what we're going to do is take our picture and set the pixel at column and row to the color that you got from getting the pixel from column and row. Well, that one obviously does nothing, it just shows the picture. But that's a warm up. Let's try to do something more interesting. This one's not so easy. So now, what we're trying to do is set the one at column and rather than row, we do height minus row minus one, so the one at the top becomes the one at the bottom, and so forth. So, looks like we're trying to turn the picture upside down, but it doesn't really work. It takes the top half and puts it on the bottom half, but then it's already done because it's overriding the same picture. So, that's a bug that's worth thinking about. What we need to do if we want to do this upside down thing is create a totally new picture. So, that's the answer to this question. We're going to take our source picture which is the one that we get from the filename on the command line. We're going to get the width and the height of that picture. Then, we're going to create another picture, the target picture, and we'll create a blank picture of the same width and height. Then, we go through for every pixel and we set the pixel in the target picture. There, we can do the rows upside down up to the color that we get from the source picture. Then, show it, so that one actually does make an upside down copy of the image. But lots of our pixel processing programs have the same concept of we go through for every pixel and set it to some value. Maybe it's a value that is a function of a value in some source. So, this is a classic example of scaling filter and this one is useful in lots of contexts. So, what we want to do is write a Java program that will scale an image, arbitrarily and independently. So, if that's my mandrill, then it's a 300 pixel by 300 pixel image. Maybe I want to make it bigger like 500 by 500, or maybe I want to squash it, make it 600 by 200, or maybe I want to make a tiny one, or a long up and down one. So, I want to arbitrarily scale the image and there's lots of applications where we need to do this, maybe to get an image to fit in a certain space, and maybe scaling it just by a little bit extra in one dimension or the other just to make it fit and wouldn't be noticeable. So, that's anywhere a computational challenge, let's scale an image. Now, for example, let's say you had to cut it in half. So, one way to do it is to just downscale by just deleting alternate rows and columns. So, that example, you're going to lose some detail when the picture isn't big enough, but anyway, that's an option, or you can upscale by doubling. So, that's to make a picture twice as big, just replace each pixel with four copies of itself. Then, if you were to do that back and forth, you don't really get quite the same image back, but that's going to be an issue when we do scaling. Fortunately, our pictures, they're high enough resolution that these effects are maybe less noticeable than you might think. But we want to do this in a systematic, organized way. So, here's a strategy that will get this scaling done. So, if we got our source width by height and our target width by height, what we're going to do is just take the ratios of those differences to get ourselves a column and row index. But the key thing to do is to set up the computation that really, what we want is we want each target pixel to have a specific value. So, we're going to do that by scaling from the source, making sure that we get a defined pixel value for every row and column in the target. To do that, we just take whatever row index we get by scaling the target row index and whatever column index we get by scaling that in doing the transformation. So, it turns out to be a pretty simple program. So, we take as input in the first command argument the filename, which is the picture that we want to scale. Then, we take the width and height that we want out of that picture. So, we create a new picture from the file and that's our source. We create a blank picture of size w by h, that's our target. So now, what we want to do is, for every pixel in the target, we want to figure out where we're going to have to go in the source to get a pixel that's close to where it should be according to the scaling. So, that's what we'll do, we'll get some column and some row in the source. We'll get that color of that pixel and then set our target pixel to that color. That way, we've got a good color for every target pixel. Then, we show it and it takes a little thought, but that's a pretty compact program to get this scaling job done. It works fine for our mandrill. This one is worth studying, but it's indicative of the ability that we have with image processing to really do quite a bit with our images. All we need to do is make sure that we set every pixel in the target to some color. People have studied lots and lots of different transformations that we can perform on pictures and you'll have, I think, some fun doing this with pictures that you've taken from your cell phone. So, you can separate out the RGB colors. That's a thing called a swirl filter, that's a wave filter, a glass filter. All these types of transformations are actually not so difficult computationally. So, all the kinds of effects like this and you can see how to do them on your own pictures in the book site or in the book.