For this assignment, we had to use JES to edit the pixel colors for a picture of ourselves. My partner, Ashley Blum, and I used her picture, and copied it using fourteen different modifications, using a wide variety of colors, parameters, and coding instructions. After defining all fourteen individually, we then defined an overarching function that encompassed all fourteen by loading the original picture (any of the user's choice), showing it, and then showing each modification in sequence.
The "loadPicture()" function was quite easy, and was made during lab. It offered the user a choice of picture files to load, loaded the file, and showed the user the file in the graphic user interface. There was nothing paritcularly exciting about it, other than the fact it was our first foray into the world of JES-only functions, including the "pickAFile()" function, the "makePicture(file)" function, and the "show(file)" function, all extremely important to picture editing in JES.
"greyVersion(pic)" was similarly very simple, relying on the simple fact that a color string (x,x,x) is grey, no matter what the x-value is. The higher it is, the lighter shade of grey is produced, and the lower it is, the darker the shade produced is. Because the rest of these functions were going into a "main()" function that would used "loadPicture()" to load a picture into memory, there was no need for any of them to load a picture individually, so we skip that step and go immediately to copying the picture using the "duplicatePicture(file)" command. (However, if we going to "mass-produce" these definitions, we would have to add in the step <<pic = makePicture(pickAFile())>>.) We then ran a "for" loop on all the pixels in the copy of picture file selected, and modified all of them given the values, which in this case changed all the pixels to have the same triplets for their RGB color strings. Notice that the picture itself is not one shade of grey because of the values of the triplets themselves - they all aligned themselves with the original green value for the pixel. So if the green value for pixel (x,y) was 56, then the color string returned for pixel (x,y) in the copy was (56,56,56), which is a darker shade of grey. However, if the green value was 200 initially, then the string would be (200,200,200), a much lighter grey. Finally, the copy was returned, but NOT shown using the "show(file)" function.
"redtoblue(pic)" was very similar to "greyVersion(pic)," except that instead of the "for" loop setting the triplet (x,y,z) to (y,y,y), it would set (x,y,z) to (z,y,x), effectively switching the reds to a blue-ish color, and the blue to a more reddish color. "bluetogreen(pic)" was essentially the same, but instead of (x,y,z) to (z,y,x), it switched (x,y,z) to (x,z,y), switching the blue and green values. Notice that this does not switch all the greens to perfect blue; rather it makes the greens more blue-ish, which usually turns them into some sort of blue-ish color overall. We also made the same function that switched red and green, call (originally), "redtogreen(pic)." "redbluegreen(pic)" switched (x,y,z) to (z,x,y), and worked the same way as the previous three functions. "blueredgreen(pic)" worked the same, switching (x,y,z) to (y,z,x). All stylistically uninteresting, for the most part.
"bluelight(pic)" changed (x,y,z) to (0,0,z) using a "for" loop. This made the whole picture into a dark blue color, with different shades of dark blue throughout. Apparently, her picture had a lot of pixels with very low blue levels.
"glowred(pic)" set specific green (50) and blue (220) values, and kept the red the same. This way, all the pixels would end up having the same green and blue values, and their color would only depend on the red value.
"darkengreen(pic)" eliminated all light green color values altogether. Everything with a green value of more than 100 ended up with no green value at all, i.e. all lightly tinted green pixels lost all their green tint, and everything else immediate gained a green color string value of 255, a very light green. "darkenred(file)" was very similar, but instead of changing the green values, it changed the red values. Both of these functions were a bit more interesting that the previously called ones because of a small conditional statement, which was how we split up the pixels by their green value, and then acted based on that seperation. An interesting little twist on the same basic (albeit cool) formula that we had been using until now.
"decreaseRed(pic,amount)" added another little twist we threw in there. This time, instead of just depending on the input picture (defined, in this case, in the "main()" function using the "loadPicture()" function), it also changed the amount of red in each pixel by multiplying the initial value but some variable. I guess the definition's name of "decreaseRed" isn't particularly accurate. Maybe it should have been "changeRed." And while we used a quick symbol change in the code (value = getRed(p)), we did not need to use that. We could have instead typed, under the "for" loop, <<setRed(p,(getRed(p))*amount)>>, where amount is one of the parameters. But this way was a bit easier to read, we felt.
"negative(pic)" and "offNegative(pic)" were functionally quite similar, and used the basic fact that the color string values went up to 255, and then looped back down to zero. In this way, we could create opposite colors by subtracting the initial value from 255, i.e. if the initial value of red was r, then the opposite color would be 255-r. Negative used this fact to the button, and created a new color called negColor that had the string (255-r,255-g,255-b), which was just (you guessed it) the exact opposite color as the original pixel had shown. In this way, we could create a negative of the photo, which was an interesting effect. Furthering this logic, we made the second function, "offNegative(file)" use 150 instead of 255. That way, it wasn't a true negative, but still could almost pass as one, giving it some interesting looks. However, for her picture, the colors were generally darker than the given 150 value, so the picture ended up just being a lighter version of the negative photo. If we had used, say, 50, it would have been a little crazy I bet. Notice that to use the "setColor(color)" function, we had to first define the negative color, because the parameter for "setColor" is a specific color, not a color string.
Finally, the last and (in my opinion) most interesting function was the "thermalImage(pic)" function. I originally wrote two copies of this function, one for a generic photo (where it ranged over all pixels) and one for my specific picture (which ranged approximately only over the pixels that depicted skin). The specific one, however, ended up not looking much better than the generic one, so I scrapped it altogether. The function basically takes each pixel and determines it's red value, which is similar, I think, to determining heat output from a warm body, using a whole series of "if" and "elif" commands. The higher the red value was, the more the red value increased by and the blue value decreased by (to contrast the increasing red), and the lower the red value was, the more the blue value increased and the more the red value decreased (to contrast the increasing blue this time). This theoretically generated a picture that showed the warmer parts of the skin with reds, and the colder parts with blues, which should have been very cool. And on my picture it was. But with Ashley's, her red shirt got in the way, and it ended up just brightening her shirt and the blue background, and doing little else. It also didn't help that the picture was so small. It turned out that the details of the transformation were pretty minute generally, so they looked better in larger pictures. With my dark shirt, with a low red value, the blue color didn't change all that significantly, although thinking back on it, it could have gone over the 255 mark very easily and gone from a bright blue to a dark blue. That would have very much detracted from what I was trying to do, which was created a psuedo-thermal imaging picture. Notice on mine, the lighter green means more heat, and the darker green indicates the colder areas. Obviously, the red indicates heat as well. <<thermalImage(bhurwitz.jpg)
Finally, we defined a "Main()" function that took all of the previous functions, executed them, and showed all the results in one stunning display of color variety. This was a very straighforward function, using varibale definitions to shorten the code (albeit only a little), and "show(picture)" functions to show the results of the modifications.
<<A screenshot of all 15 pictures, including the original one on the top left.>>
As for extensions, we made numerous other modification functions, used conditional statements in three different functions to achieve different results, we used a second parameter in one of our functions, and we almost used the "range" function to modify on pixels in a certain set of x and y ranges.
What did I learn? I learned how to use "for p in pixels" loops to modifiy the color strings of pixels in a picture. I learned about how computers store picture data, and how easily modified that data is. I learned about how computers show color to use, and how they see color themselves. I learned clever ways of modifying the color of any picture. I learned not to execute the command <<print getPixels(picture)>> because it takes waaaaaay too long. I learned how to use a wide variety of picture and color commands in JES. And of course, I learned a bit about myself in the process.