Difference between revisions of "CSC111 Lab 10 2018"
(→Image Processing) |
(→Skeleton Program #2) |
||
Line 131: | Line 131: | ||
for x in range( WIDTH ): | for x in range( WIDTH ): | ||
for y in range( HEIGHT ): | for y in range( HEIGHT ): | ||
+ | # get the R, G, B values for the pixel at (x,y) | ||
red, green, blue = img.getPixel( x, y ) | red, green, blue = img.getPixel( x, y ) | ||
+ | |||
+ | # set the R, G, B values of the pixel at (x,y) | ||
+ | # to different values (here we set red to 255) | ||
img.setPixel( x, y, color_rgb(255, green, blue ) ) | img.setPixel( x, y, color_rgb(255, green, blue ) ) | ||
Revision as of 12:00, 8 April 2018
D. Thiebaut (talk) 11:30, 8 April 2018 (EDT)
This lab presents image-processing operations in Python using Zelle's Graphics Library. The purpose of this lab is to get you to explore image processing with Python. Some of you will go faster than others. The goal is for you to answer correctly some of the challenges, but it is understood that not all of you will be able to go through all the challenges before the due date. For this reason, to get full credit, you only need to submit the program corresponding to the last challenge you were able to solve before the due date. You will submit both the program and a screen capture of the image you generated. Make sure you code your name(s) as the title of the window, so that the screen capture can be easily assigned to you.
You are encouraged to keep working in pair-programming mode, as always!
Note: While you are not required to finish the lab before the due date, you should look at the solution programs at the end of the page when they become available, you should run them and understand them, as the final exam will have one problem dealing with graphics and image processing. You don't want to find yourself not understanding the challenges in today's lab during the final exam, as there won't be any more help from TAs or instructors during the final exam...
Contents
Images
- Zelle's graphics library works with gif files only. Today, we are going to play with the image whose link is shown below. Click on the link, and once the image appears, drag it or save it to the folder where you will save your program for this lab:
Image Processing
Reminder
Below are various for-loop structures that will come in handy today. Quickly go over them and make sure they make sense.
Assume you have an array of size 5:
array = [10, 12, 20, 30, 101]
If you want to access all of the items of array, in order, you would write:
for i in range( len( array ) ):
doSomethingWith( array[i] )
If you want to access all the items in array in reverse order, starting with the last one, you would write:
for i in range( len( array )-1, -1, -1 ):
doSomethingWith( array[i] )
For the same reason, if you want to access all the pixels on one row of an image you would write:
for x in range( getWidth( image ) ):
doSomethingWithPixelAt( x, y ) #whatever y is
If you want to access all the pixels starting from the end of a row of pixels, you would write:
for x in range( getWidth( image )-1, -1, -1 ):
doSomethingWithPixelAt( x, y ) #whatever y is
Some Images to Play With
Skeleton Program #1
The program you need to submit at the end of this lab will be called lab10.py.
Below is a program you should copy/paste into your Idle window. Make sure you enter your name for the title of the window in the highlighted line. This will allow you later to get a grade for this lab!
# skeleton program for # manipulating images from graphics import * # We measured the image dimensions of our cat to be 243x207 # We make the window the same size WIDTH = 243 HEIGHT = 207 def main(): global WIDTH, HEIGHT # open the graphic window win = GraphWin( "PUT YOUR NAME HERE!", WIDTH, HEIGHT ) # create an image with its center corresponding to the center # of the window. img = Image( Point(WIDTH//2, HEIGHT//2), "catHat.gif", ) # make the image appear in the window img.draw( win ) # close the window when the user clicks on it win.getMouse( ) win.close() main()
- Run it to verify that it displays your image.
Skeleton Program #2
- The program below processes all the pixels of an image and sets the red intensity of the pixels to their maximal value.
# skeleton program for # manipulating images from graphics import * # We measured the image dimensions to be 243x207 # We make the window the same size WIDTH = 243 HEIGHT = 207 def makeRed( img ): """sets the red component of the pixels of the image to their maximal value""" global WIDTH, HEIGHT for x in range( WIDTH ): for y in range( HEIGHT ): # get the R, G, B values for the pixel at (x,y) red, green, blue = img.getPixel( x, y ) # set the R, G, B values of the pixel at (x,y) # to different values (here we set red to 255) img.setPixel( x, y, color_rgb(255, green, blue ) ) def main(): global WIDTH, HEIGHT # open the graphic window win = GraphWin( "PUT YOUR NAME HERE!", WIDTH, HEIGHT ) # create an image with its center corresponding to the center # of the window. img = Image( Point(WIDTH//2, HEIGHT//2), "catHat.gif", ) # make the image appear in the window img.draw( win ) # transform the pixels of the image makeRed( img ) # close the window when the user clicks on it win.getMouse( ) win.close() main()
- Create this program as lab9.py and save it to your usual folder. Make sure you change the title of the window to be your name.
Problem 1: Andy Warhol's Cat
- Copy the makeRed( img ) function and create a new function that looks just the same, but change its name to andyWarhol( img ).
- Make this new function modify the red, green and blue components of each pixel.
- Below are different modifications you can try. Be imaginative and feel free to try others as well. Don't limit yourself to just modifying one color component: apply the modification to all 3.
blue = blue // 2
|
make blue component darker |
blue = blue + (255-blue)//2
|
make blue component lighter |
if blue <125 :
blue = 0
else:
blue = 255
|
Andy Warhol transform |
blue = ( blue + red ) // 2
red = ( red + green ) // 2
green = ( green + blue ) // 2
|
shift colors and average out pairs of components. |
- Can you reproduce the (artistic) image on the right?
Problem 2: black and white
- Add a new function called blackAndWhite( img ) to your program that will be a copy of the skeleton function above.
- Make your image black and white by storing the same value in the green, red, and blue component of a pixel. In a first step, pick the amount of red of the pixel and store that number in the other two components. (green = red, blue = red). See what the image looks like.
- Next take the average amount of red, green and blue and store that value (store it in a variable called grey for example), in all three color components.
- Better: initialize the grey variable as follows:
grey = int( 0.3 * red +0.6 * green +0.11 * blue )
Problem 3: Controlling the Sweep Through the Pixels
- Copy paste this new function that contains a call to win.update( ) inside the for x in range(...) loop. Note that we need to pass win to the function as a 2nd parameter.
def blackAndWhite( img, win ):
"""transforms the image to a black and white image"""
global WIDTH, HEIGHT
for x in range( WIDTH ):
win.update()
for y in range( HEIGHT ):
red, green, blue = img.getPixel( x, y )
grey = int( 0.3 * red +0.6 * green +0.11 * blue )
color = color_rgb( grey, grey, grey )
img.setPixel( x, y, color )
- Make your main program call blackAndWhite( img, win ) instead of the previous function it was calling.
- Run your program.
- Notice how it "sweeps" through the image as it processes it. The win.update() line forces the graphics window to refresh the image and show the state of all the pixels. Normally the graphic window will show the changes only after the for-loops are done with the pixel modification. Now we can better see how the for x and for y loop operate.
Challenge 1 |
- Modify the function so that the sweep goes from right to left.
Challenge 2 |
- Modify the function so that the sweep goes from top to bottom
Challenge 3 |
- Modify the function so that the sweep goes bottom up.
Problem 4: Sideways
Pick one of the functions you have written for the problems above and make a new copy of it under a different name, say, sideways( img ).
Replace the nested for-loop with this loop:
for x in range( WIDTH ):
for y in range( x ):
# make sure y does not get larger than height of image
if y < HEIGHT:
# modify color of pixel at x, y...
# keep your pixel color-modification code here
- Look at the code. See if you can accurately predict the way the image is going to be transformed by these nested for-loops.
- Run the program! Does it make sense? Look at your loop again, and at the resulting image. Make sure the logic of the code explains the resulting image transformation.
- Modify your new function so that the transformation affects another side of the image.
Problem 5: Borders
- Write a new function called addBorder( img ) that will put a red border (or a border of your favorite color) around the image. The width of the border should be 5 pixels.
- Remember that to set a pixel a location (x,y) red, you can simply change the set the color of that pixel to red without reading it first.
img.setPixel( x, y, color_rgb(255, 0, 0 ) )
- Do it one step at a time. First put a border at the top of the image.
- Then add a border at the bottom of the image.
- Then to the left of the image
- Then, add the last border to the right of the image.
- Note
- The left and bottom borders will look thinner than the top and right ones. It's a side-effect of the graphics library and the graphics system we use. It's not you. Don't try to fix it!
Challenge 4 |
- B&W image with Colored Border
- Make your program output a version of your colored image that will be black and white with a colored border around it.
Problem 6: Cat with a Red Nose
- Add a new function that will draw a red square over the cat's nose. Don't worry if it doesn't match perfectly. Just a big square over the nose will do. This exercise will make you get better at working with nested for-loops!
Problem 7: Diagonal
- Go back to one of the transformations that affects all the pixels in the image. Replace the nested for-loops by this single loop like this:
for x in range( WIDTH ):
y = x
# make sure the y coordinate is not beyond the image.
if y < HEIGHT:
image.setPixel( x, y, color_rgb( 255, 0, 0 )
- What do you get?
- Modify your function so that it puts a red cross over the image. In other words, add another diagonal that goes from the top-right corner of the image down to lower left side of the image.
Problem 8: Pixelation
- The image below was created by a form of pixelation of the cat image. Your assignment is to recreate this image.
- The algorithm works as follows:
- draw the cat image with img.draw( win ) first, then undraw it with img.undraw(). Even though the image will have disappeared, you can still access the pixels of the original image and get their color.
- get the color of the pixel that is located at (0, 0)
- create a circle at Point( 0, 0 ) with radius 5, and fill it with the color of the pixel you just read.
- get the color of the pixel at (10, 0), put a circle at Point( 10, 0 ) with radius 5, and fill it with the color of the last pixel read.
- repeat the process, eventually touching the pixels at (20, 0 ), (30, 0), (40, 0), until you create a row of circles at the top of the window. Then the next row of circles will start with a circle at Center (0,10), followed by one at Center(10,10), (20,10), etc.
- At the end of the double nested-for loops, you will covered the whole image with colored circles. Squinting your eyes, you should be able to recognize our cat in the hat.
Challenge of the Day: Symmetrical Cat in Fog |
- Write a graphic program that takes our original cat image (shown on the left below) and produces this new one (on the right) where the cat now has a symmetrical face and is in the fog...
Note that the colors at the top of the new image are the original colors, but that all the pixels on the bottom line are white...
- Hints
-
- To display the symmetrical face of the cat, you need to take the left half side of the image and replicate it on the right side.
- A white pixel is one for which the red, green, and blue components are all set to 255.
- The fog effect is created by making the pixels more and more white the closer the pixels are to the bottom of the image.
- Assume a pixel is half-way down from the top of the image. Its y coordinate is HEIGHT//2. If its original green component is, say, 100, then to make it 50% more white, you add 50% of (255-100) to 100. You do the same for the blue and the red component, and the pixels will become lighter, while keeping their original tint.
Submission
Submit the last program that works to Moodle, in the LAB10 section, along with a screen capture of the last image you were able to generate with your program (assuming some people will not get the symmetry and fog running). Make sure the image you submit has your name showing in the title of the window, otherwise it will hard to assign you a grade for the image you submitted.
Note that Moodle cannot run and display graphics program. This is why you are submitting a copy of the image you generated. This is also why you won't be able to run or evaluate the program on Moodle.
<showafterdate after="20180414 13:00" before="20180601 00:00">
Solution Program
# lab10sol.py
# D. Thiebaut
# A collection of functions for manipulating an image
# using nested for loops. Each function corresponds to a
# transformation that was introduced in the lab.
from graphics import *
# We measured the image dimensions to be 243x207
# We make the window the same size
WIDTH = 243
HEIGHT = 207
def sideways( img ):
global WIDTH, HEIGHT
for x in range( WIDTH ):
for y in range( x ):
# make sure y does not get larger than height of image
if y < HEIGHT:
# modify color of pixel at x, y...
red, green, blue = img.getPixel( x, y )
grey = int( 0.3 * red +0.6 * green +0.11 * blue )
color = color_rgb( grey, grey, grey )
img.setPixel( x, y, color )
def blackAndWhite( img, win ):
"""sets the red component of the pixels of the image
to their maximal value"""
global WIDTH, HEIGHT
for x in range( WIDTH ):
win.update()
for y in range( HEIGHT ):
red, green, blue = img.getPixel( x, y )
grey = int( 0.3 * red +0.6 * green +0.11 * blue )
color = color_rgb( grey, grey, grey )
img.setPixel( x, y, color )
def saturate( component ):
"""transforms component into min or max value depending
on its intensity."""
if component < 125:
return 0
return 255
def AndyWarhol( img ):
"""saturates the image by saturating the
RGB components. If the R component is less than 125, then
set it to 0, otherwise set it to 255. Same for blue and green."""
global WIDTH, HEIGHT
for x in range( WIDTH ):
for y in range( HEIGHT ):
red, green, blue = img.getPixel( x, y )
# the line below replaces the pixel with its original color. Change
# the amount of red, green and blue to see some change in the colors
newColor = color_rgb( saturate(red), saturate(green), saturate(blue) )
img.setPixel( x, y, newColor )
def makeRed( img ):
"""sets the red component of the pixels of the image
to their maximal value"""
global WIDTH, HEIGHT
for x in range( WIDTH ):
for y in range( HEIGHT ):
red, green, blue = img.getPixel( x, y )
img.setPixel( x, y, color_rgb(255, green, blue ) )
def pixelate( img, win ):
global WIDTH, HEIGHT
img.undraw( )
for x in range( 0, WIDTH, 10 ):
for y in range( 0, HEIGHT, 10 ):
red, green, blue = img.getPixel( x, y )
circ = Circle( Point( x, y ), 5 )
circ.setFill( color_rgb( red, green, blue ) )
circ.draw( win )
def addBorder( img ):
"""add a red border around the image"""
global WIDTH, HEIGHT
for x in range( WIDTH ):
for y in range( 6 ):
img.setPixel( x, y, color_rgb(255, 0, 0 ) )
for y in range( HEIGHT-5, HEIGHT ):
img.setPixel( x, y, color_rgb(255, 0, 0 ) )
for y in range( HEIGHT ):
for x in range( 6 ):
img.setPixel( x, y, color_rgb(255, 0, 0 ) )
for x in range( WIDTH-5, WIDTH ):
img.setPixel( x, y, color_rgb(255, 0, 0 ) )
def addRedDiagonal( img ):
"""draws a red diagonal going from the top-left corner
of the image down."""
global WIDTH, HEIGHT
for x in range( 0, WIDTH ):
y = x
if y < HEIGHT:
red, green, blue = img.getPixel( x, y )
img.setPixel( x, y, color_rgb( 255, 0, 0 ) )
def addRedCross( img ):
"""draws a red cross going from the top-left corner
of the image down, and from top-right corner down to
lower left side of the image."""
global WIDTH, HEIGHT
for x in range( 0, WIDTH ):
y = x
if y < HEIGHT:
red, green, blue = img.getPixel( x, y )
img.setPixel( x, y, color_rgb( 255, 0, 0 ) )
for x in range( WIDTH-1, -1, -1 ):
y = WIDTH-1-x
if y < HEIGHT:
red, green, blue = img.getPixel( x, y )
img.setPixel( x, y, color_rgb( 255, 0, 0 ) )
def symmetry( img ):
"""draws the image horizontally symmetrical around the
vertical middle of the image"""
global WIDTH, HEIGHT
for x in range( 0, WIDTH//2 ):
x2 = WIDTH-1-x
for y in range( 0, HEIGHT ):
red, green, blue = img.getPixel( x, y )
img.setPixel( x2, y, color_rgb(red, green, blue ) )
def fog( img ):
"""creates a fog effect, making the pixels more and more
white as we get closer to the bottom of the window."""
global WIDTH, HEIGHT
for x in range( 0, WIDTH ):
for y in range( 0, HEIGHT ):
red, green, blue = img.getPixel( x, y )
percent = 1.0 * y / HEIGHT
red = int( red + (255-red)*percent )
green = int( green + (255-green)*percent )
blue = int( blue + (255-blue)*percent )
img.setPixel( x, y, color_rgb(red, green, blue ) )
def waitForClick( win, message ):
""" waitForClick: stops the GUI and displays a message.
Returns when the user clicks the window. The message is erased."""
# wait for user to click mouse to start
startMsg = Text( Point( win.getWidth()/2, win.getHeight()-15 ), message )
startMsg.draw( win ) # display message
win.getMouse() # wait
startMsg.undraw() # erase
def main():
# open the graphic window
win = GraphWin( "Your name here", WIDTH, HEIGHT )
# create an image with its center corresponding to the center
# of the window.
img = Image( Point(WIDTH//2, HEIGHT//2), "catHat.gif", )
# make the image appear in the window
img.draw( win )
# transform the pixels of the image
#makeRed( img )
# create Andy Warhl image
#AndyWarhol( img )
# make the image black and white
#blackAndWhite( img, win )
# apply a sideways transformation
#sideways( img )
# add a border
#addBorder( img )
# add a red diagonal to the image
#addRedDiagonal( img )
# add a red cross to the image
#addRedCross( img )
# pixelate the image
pixelate( img, win )
# symmetrical cat in fog
#symmetry( img )
#fog( img )
# close the window when the user clicks on it
waitForClick( win, "click to close" )
win.close()
main()
</showafterdate>