Image Filter

What We're Up To

Ever play with Photoshop? Or GIMP? They allow you to load an image and then maniplulate it. Want to recolor? Want to resize or rotate? They can do that and much else too.

In this project you'll use Python to create some basic image filters. These include remove red, green or blue, render in greyscale or black and white, rotate and resize. You'll also build a simple CLI (command line interface) that will allow you use the console to load an image and then apply filters of your choice.

Ansel

You'll use the ansel module to create your filters. Go there. Get acquainted. Like the euclid module, it's built on the back of pygame.

Once you're ready to begin the project, go here. Fork. This will become your completed project.

Instructions

Your primary task is to create a set of filters (one of which I've written for you). You'll also construct a simple command line interface (CLI) that will allow to the user to load and save images, apply filters, undo and redo, etc.

When you fire up the finished program, it should ask the user for the name of an image to load. The program will then load that image and display it. (What image? Your choice, but make it school appropriate.) Next ask the user for a filter to apply. Apply that filter and then ask for another.  Inform the user if a command is not recognized or cannot be applied. Continue until the user types "quit".

The filters I wish you to write are listed below. (In the next section, I'll give you a bit of help about how to write them.)

The CLI should also recognize a few simple commands named below. Check the official Ansel documentation for the first three.

How will your organize your code? Obviously, each of the options above (remove red, remove green, remove blue, photo-negative, etc.) should be wrapped up in its own function. You should also write a function, named perhaps CLI (short for Command Line Interface) that runs the show. Call CLI to begin; CLI will then ask for input and respond to it. It should continue until the user types "quit". 

As always, your code should be robust. I'll try to crash it. If I do, you're at fault, not me.

Hints

How will you write the code for these various filters? You'll have to do a bit of research. But I'll give you a little help.

grayscale and sepia

Luminence.

Google "sepia rgb" and use the formulates you find.

black and white

By "black and white", I mean an image each of whose pixels is either black - (0, 0, 0) - or white - (255, 255, 245). My black and white filter first converted the image to greyscale.

resize


rotate

To rotate, you don't simply exchange the row and column values for a pixel. That doesn't rotate; instead it flips over a diagonal line that runs from bottom left to upper right. (I'll convince you of this in class. I'll flip a bit of text.) How then do you rotate?

First point: the rotated image will exchange width and height: width becomes height and height becomes width. 

Second, let us consider a pair of transformations of a rectangle. The two I mean are a horizontal flip and a diagonal flip.

glass


8-Bit

In 8-bit RGB, we have 3 bits for red, 3 for green and 2 for blue. 2³ = 8 and 2²=4; so in 8-bit RGB, we have 8 reds, 8 greens and 4 blues. These combine to give us 2³·2³·2² = 256 possible colors. How do we make 24-bit RGB (which is the current standard) look as if it's 8-bit? We take the average of the red, green and blue for each 8-by-8 block of pixels in the input image, find the closest 8-bit red,  green and blue for those, and then write a pixel with those 8-bit colors 64 times over in that 8-by-8 block. How do we get the 8-bit colors? For red and green, we limit the range 0 - 255 to eight possible values: 0, 36, 72, 109, 145, 181, 218, 255.  For blue, we limit the range 0 - 255 to four possible values: 0, 85, 170, 255.  Thus we must take the actual red and green and round to the nearest value in the first list; and we must take the actual blue and round to the nearest value in the second list. We then take these rounded values and make a new pixel. For instance, color (66, 100, 212) would become (72, 109, 170). (You'll no doubt want a formula. Hint: divide 256 by 7, divide 256 by 3.)

load, save and saveas


undo and redo (extra credit)

The user should be able to undo back to the original image. Redo should be possible only if the command entered immediately before was "undo"; and the number of "undo"s done immediately before should be the number of "redo"s that are possible. How will you handle this? I suggest two lists: an undo list and a redo list. Begin the undo list with the image that's been loaded; and every time an image is altered, place the new version in the undo list. When the user chooses "undo", display the next to last image in the undo list, and move the last image into the redo list. When the user chooses "redo", display the last image in the redo list, and move it to undo. Moreover, any time the user chooses a filter, empty the redo list; a redo is possible only if the previous command was undo. Of course I'll expect that the CLI won't crash if the user chooses "undo" or "redo" when it isn't possible. For instance, if the user loads an image, then applies "sepia", and then tries two "undo"s, the CLI should inform the user after the second that it isn't possible.

Sample Run

Here's a copy-paste from my CLI. I thought it might help.

Enter image name with extension: fry.jpg

Command or filter: double

Command or filter: quit

Image not saved. Really quit (y or n)? n

Command or filter: undo

Command or filter: 8-bit

Command or filter: rr

Command or filter: saveas

Enter image name with extension or x to exit: new_fry.jpg

Command or filter: quit

Remove Red

Remove Green

Remove Blue

Grayscale

Black and White

Sepia

Negative

Tile

Clockwise

Counterclockwise

8-bit

Sobel