Introduction to Computing and Programming in Python A





![Side Note: That thing in [] is a sequence >>> a=[1, 2, 3] >>> Side Note: That thing in [] is a sequence >>> a=[1, 2, 3] >>>](https://slidetodoc.com/presentation_image_h2/a054e8bd293685a56f9e7349e5c149ea/image-6.jpg)





















































- Slides: 59

Introduction to Computing and Programming in Python: A Multimedia Approach Chapter 4: Modifying Pixels in a Range 1

Chapter Learning Goals 2

Reminder: Pixels are in a matrix Matrices have two dimensions: A height and a width We can reference any element in the matrix with (x, y) We refer to those coordinates as index numbers or indices We sometimes want to know where a pixel is, and get. Pixels doesn’t let us know that. 3

Pixels in a Matrix “Barbara. jpg” has height 293 (bottommost index is 292) and width 221 (rightmost index is 220) 4

Introducing the function range Range is a function that returns a sequence between its first two inputs, possibly using a third input as the increment >>> print range(1, 4) [1, 2, 3] >>> print range(-1, 3) [-1, 0, 1, 2] >>> print range(1, 10, 2) [1, 3, 5, 7, 9] >>> print range(3) [0, 1, 2] Notice: • The end value is never included. • range(0, 10) ends at 9. • If you leave out a start value, it’s assumed to be zero. 5
![Side Note That thing in is a sequence a1 2 3 Side Note: That thing in [] is a sequence >>> a=[1, 2, 3] >>>](https://slidetodoc.com/presentation_image_h2/a054e8bd293685a56f9e7349e5c149ea/image-6.jpg)
Side Note: That thing in [] is a sequence >>> a=[1, 2, 3] >>> print a [1, 2, 3] >>> a = a + 4 An attempt was made to call a function with a parameter of an invalid type >>> a = a + [4] >>> print a [1, 2, 3, 4] >>> a[0] 1 We can assign names to sequences, print them, add items to sequences, and access individual pieces of them. We can also use for loops to process each element of a sequence. 6

We can use range to generate index numbers We’ll do this by working the range from 0 to the height-1, and 0 to the width-1. Using the range function will make it easy to start from 0 and stop before the end value. But we’ll need more than one loop. Each for loop can only change one variable, and we need two for indexing a matrix 7

Working the pixels by number We will use range, along with nested loops One to walk the width, the other to walk the height Be sure to watch your blocks (i. e. , indentation) carefully! def increase. Red 2(picture): for x in range(0, get. Width(picture)): for y in range(0, get. Height(picture)): px = get. Pixel(picture, x, y) value = get. Red(px) set. Red(px, value*1. 1) 8

Be careful with the get. Pixel function get. Pixel(picture, x, y) Notice that the get. Pixel function has three parameters The first is the name of the picture from which you want a pixel color The second is the x (horizontal, i. e. , across the width) index (i. e. it says the column of the matrix) The third is the y (vertical, i. e. , down the height) index (i. e. it says the row of the matrix) So, for Barbara. jpg (width 221 and height 293) the upper left pixel is get. Pixel(picture, 0, 0) 9

Image manipulations Now you understand how to manipulate a pixel if you know where the pixels are you can do a lot of things to pictures: Mirror an image Rotate an image Copying images (you can create collages!) Crop an image Increase or decrease the size of an image (scale up or down) Blur an image Useful stuff! You can actually change your pictures similar to the way Photoshop does 16

Mirroring an image horizontally Source image Target image 17

Horizontal mirror recipe mirroring means intuitively "flipping around" an axis (when you mirror horizontally, you flip your picture around a vertical axis) STEP 1. Since the picture is represented by a matrix, you must determine the coordinates (x and y) of all the "points" of this axis in the matrix STEP 2. Then you have to determine the direction of the flipping (when you mirror horizontally, you may flip the left side to right side or vice versa) STEP 3. Now, since pictures are encoded as a matrices, you must figure out where a pixel of the source picture should go in the target picture 18

Step 1 - determine the mirror axis Step 2 - determine the flipping direction 1 2 19

Work it out with matrices �To find out the mirror axis you need just to determine its x coordinate (the mirror. Point). It is is halfway across: get. Width(picture)/2 20

Work it out with matrices �STEP 2. If the flipping direction is left to right, then the source and target matrices will look like this: 21

Step 3 Figure out where a pixel of the source picture should go in the target picture If source pixel is at (x, y), target pixel is at (widthx-1, y) 22

Can we do it with a horizontal mirror? def mirror. Horizontal(source): mirror. Point = get. Height(source) / 2 height = get. Height(source) for x in range(0, get. Width(source)): for y in range(0, mirror. Point): top. Pixel = get. Pixel(source, x, y) bottom. Pixel = get. Pixel(source, x, height - y - 1) color = get. Color(top. Pixel) set. Color(bottom. Pixel, color) 26

Of course! 27

What if we wanted to copy bottom to top? Very simple: Swap the order of pixels in the bottom lines def mirror. Bot. Top(source): mirror. Point = get. Height(source) / 2 height = get. Height(source) for x in range(0, get. Width(source)): for y in range(0, mirror. Point): top. Pixel = get. Pixel(source, x, y) bottom. Pixel = get. Pixel(source, x, height - y - 1) color = get. Color(bottom. Pixel) set. Color(top. Pixel, color) 28

Mirroring bottom to top 29

Doing something useful with mirroring Mirroring can be used to create interesting effects, but it can also be used to create realistic effects. Consider this image from a trip to Athens, Greece. Can we “repair” the temple by mirroring the complete part onto the broken part? 30

Figuring out where to mirror Use Media. Tools to find the mirror point and the range that we want to copy 31

Program to mirror the temple def mirror. Temple(): source = make. Picture(get. Media. Path("temple. jpg")) mirror. Point = 276 for x in range(13, mirror. Point): for y in range(27, 97): pleft = get. Pixel(source, x, y) pright = get. Pixel(source, mirror. Point + mirror. Point - 1 - x, y) set. Color(pright, get. Color(pleft)) show(source) return source 33

Did it really work? It clearly did the mirroring, but that doesn’t create a 100% realistic image. Check out the shadows: Which direction is the sun coming from? 34

Some Utility Functions If you know the name of the file, searching for it with pick. AFile() feels tedious You can set and get a media folder (path) for remembering a place where your media will be coming from (or going to) set. Media. Path() lets you pick a file in your media folder get. Media. Path(basefilename) lets you generate a complete filename out of only the last part 35

Example >>> set. Media. Path() New media folder: C: Documents and SettingsMark GuzdialMy Documentsmediasources >>> get. Media. Path("barbara. jpg") 'C: \Documents and Settings\Mark Guzdial\My Documents\mediasources\barbara. jpg' >>> barb=make. Picture(get. Media. Path("barbara. jpg")) 36

Moving pixels across pictures We’ve seen using index variables to track the pixel position we’re working with in a picture. We can copy between pictures, if we keep track of: The source index variables Where we’re getting the pixels from The target index variables Where we’re putting the pixels at (Not really copying the pixels: Replicating their color. ) 42

What can you do then? What can you do when copying from one picture to another? Collages: Copy several pictures onto one Cropping: You don’t have to take the whole picture Scaling: Make a picture smaller, or larger when copying it 43

Copying pixels In general, what we have to do is to keep track of the source index variables (source. X and source. Y), and of the target index variables (target. X and target. Y). We increment (add to them) in pairs source. X and target. X get incremented together source. Y and target. Y get incremented together The tricky parts are: Setting values inside the body of loops Incrementing at the bottom of loops 45

Copying Barb to a canvas def copy. Barb(): # Set up the source and target pictures barbf=get. Media. Path("barbara. jpg") barb = make. Picture(barbf) canvasf = get. Media. Path("7 in. X 95 in. jpg") canvas = make. Picture(canvasf) # Now, do the actual copying target. X = 0 for source. X in range(0, get. Width(barb)): target. Y = 0 for source. Y in range(0, get. Height(barb)): color = get. Color(get. Pixel(barb, source. X, source. Y)) set. Color(get. Pixel(canvas, target. X, target. Y), color) target. Y = target. Y + 1 target. X = target. X + 1 show(barb) show(canvas) return canvas 46

Comments Python ignores from “#” through the rest of the line If you start a line with “#”, the whole line is ignored Why do we want lines to be ignored? To be able to leave notes to ourselves or someone else about how the program works 47

What’s this naming something as itself? target. X = target. X + 1 This isn’t really naming something as itself target. X + It 1 is evaluated will result in the number after target. X = then sets the value of target. X The result is that target. X gets incremented by 1 52

Transformation = Small changes in copying Making relatively small changes in this basic copying program can make a variety of transformations. Change the target. X and target. Y, and you copy wherever you want Cropping: Change the source. X and source. Y range, and you copy only part of the picture. Rotating: Swap target. X and target. Y, and you end up copying sideways Scaling: Change the increment on source. X and source. Y, and you either grow or shrink the image. 55

Copying into the middle of the canvas def copy. Barb. Midway(): # Set up the source and target pictures barbf=get. Media. Path("barbara. jpg") barb = make. Picture(barbf) canvasf = get. Media. Path("7 in. X 95 in. jpg") canvas = make. Picture(canvasf) # Now, do the actual copying target. X = 100 for source. X in range(0, get. Width(barb)): target. Y = 100 for source. Y in range(0, get. Height(barb)): color = get. Color(get. Pixel(barb, source. X, source. Y)) set. Color(get. Pixel(canvas, target. X, target. Y), color) target. Y = target. Y + 1 target. X = target. X + 1 show(barb) show(canvas) return canvas 56

Copying: How it works Here’s the initial setup: 57

Copying: How it works 2 After incrementing the source. Y and target. Y once (whether in the for or via expression): 58

Copying: How it works 3 After yet another increment of source. Y and target. Y: When we finish that column, we increment source. X and target. X, and start on the next column. 59

Copying: How it looks at the end Eventually, we copy every pixel 60

Making a collage Could we do something to the pictures we copy in? Sure! Could either apply one of those functions before copying, or do something to the pixels during the copy. Could we copy more than one picture! Of course! Make a collage! 61

def create. Collage(): flower 1=make. Picture(get. Media. Path("flower 1. jpg")) print flower 1 flower 2=make. Picture(get. Media. Path("flower 2. jpg")) print flower 2 canvas=make. Picture(get. Media. Path("640 x 480. jpg")) print canvas #First picture, at left edge target. X=0 for source. X in range(0, get. Width(flower 1)): target. Y=get. Height(canvas)-get. Height(flower 1)-5 for source. Y in range(0, get. Height(flower 1)): px=get. Pixel(flower 1, source. X, source. Y) cx=get. Pixel(canvas, target. X, target. Y) set. Color(cx, get. Color(px)) target. Y=target. Y + 1 target. X=target. X + 1 #Second picture, 100 pixels over target. X=100 for source. X in range(0, get. Width(flower 2)): target. Y=get. Height(canvas)-get. Height(flower 2)-5 for source. Y in range(0, get. Height(flower 2)): px=get. Pixel(flower 2, source. X, source. Y) cx=get. Pixel(canvas, target. X, target. Y) set. Color(cx, get. Color(px)) target. Y=target. Y + 1 target. X=target. X + 1 Page 91 -92 (2 ed edition) #Third picture, flower 1 negated negative(flower 1) target. X=200 for source. X in range(0, get. Width(flower 1)): target. Y=get. Height(canvas)-get. Height(flower 1)-5 for source. Y in range(0, get. Height(flower 1)): px=get. Pixel(flower 1, source. X, source. Y) cx=get. Pixel(canvas, target. X, target. Y) set. Color(cx, get. Color(px)) target. Y=target. Y + 1 target. X=target. X + 1 #Fourth picture, flower 2 with no blue clear. Blue(flower 2) target. X=300 for source. X in range(0, get. Width(flower 2)): target. Y=get. Height(canvas)-get. Height(flower 2)-5 for source. Y in range(0, get. Height(flower 2)): px=get. Pixel(flower 2, source. X, source. Y) cx=get. Pixel(canvas, target. X, target. Y) set. Color(cx, get. Color(px)) target. Y=target. Y + 1 target. X=target. X + 1 #Fifth picture, flower 1, negated with decreased red decrease. Red(flower 1) target. X=400 for source. X in range(0, get. Width(flower 1)): target. Y=get. Height(canvas)-get. Height(flower 1)-5 for source. Y in range(0, get. Height(flower 1)): px=get. Pixel(flower 1, source. X, source. Y) cx=get. Pixel(canvas, target. X, target. Y) set. Color(cx, get. Color(px)) target. Y=target. Y + 1 target. X=target. X + 1 show(canvas) return(canvas) 62

Can we make that easier? The collage code is long, yet simple. It’s the same thing overand-over. We can generalize that copying loop, and with parameters, use it in many places. def copy(source, target, targ. X, targ. Y): target. X = targ. X for source. X in range(0, get. Width(source)): target. Y = targ. Y for source. Y in range(0, get. Height(source)): px=get. Pixel(source, source. X, source. Y) tx=get. Pixel(target, target. X, target. Y) set. Color(tx, get. Color(px)) target. Y=target. Y + 1 target. X=target. X + 1 63

Exact same collage! def create. Collage 2(): flower 1=make. Picture(get. Media. Path("flowe r 1. jpg")) print flower 1 flower 2=make. Picture(get. Media. Path("flowe r 2. jpg")) print flower 2 canvas=make. Picture(get. Media. Path("640 x 4 80. jpg")) print canvas #First picture, at left edge copy(flower 1, canvas, 0, get. Height(canvas)get. Height(flower 1)-5) #Second picture, 100 pixels over copy(flower 2, canvas, 100, get. Height(canvas) -get. Height(flower 2)-5) #Third picture, flower 1 negated negative(flower 1) copy(flower 1, canvas, 200, get. Height(canvas) -get. Height(flower 1)-5) #Fourth picture, flower 2 with no blue clear. Blue(flower 2) copy(flower 2, canvas, 300, get. Height(canvas) -get. Height(flower 2)-5) #Fifth picture, flower 1, negated with decreased red decrease. Red(flower 1) copy(flower 1, canvas, 400, get. Height(canvas) -get. Height(flower 2)-5) return canvas 64

Rotating the copy def copy. Barb. Sideways(): # Set up the source and target pictures barbf=get. Media. Path("barbara. jpg") barb = make. Picture(barbf) canvasf = get. Media. Path("7 in. X 95 in. jpg") canvas = make. Picture(canvasf) # Now, do the actual copying target. X = 0 for source. X in range(0, get. Width(barb)): target. Y = 0 for source. Y in range(0, get. Height(barb)): color = get. Color(get. Pixel(barb, source. X, source. Y)) set. Color(get. Pixel(canvas, target. Y, target. X), color) target. Y = target. Y + 1 target. X = target. X + 1 show(barb) show(canvas) return canvas 65

Rotating: How it works We increment the same, but we use target. X for the Y coordinate and target. Y for the X coordinate 66

Rotate: How it ends Same amount of increment, even same values in the variables, but a different result. 67

Cropping: Just the face def copy. Barbs. Face(): # Set up the source and target pictures barbf=get. Media. Path("barbara. jpg") barb = make. Picture(barbf) canvasf = get. Media. Path("7 in. X 95 in. jpg") canvas = make. Picture(canvasf) # Now, do the actual copying target. X = 100 for source. X in range(45, 200): target. Y = 100 for source. Y in range(25, 200): color = get. Color(get. Pixel(barb, source. X, source. Y)) set. Color(get. Pixel(canvas, target. X, target. Y), color) target. Y = target. Y + 1 target. X = target. X + 1 show(barb) show(canvas) return canvas 69

Cropping, another way def copy. Barbs. Face 2(): # Set up the source and target pictures barbf=get. Media. Path("barbara. jpg") barb = make. Picture(barbf) canvasf = get. Media. Path("7 in. X 95 in. jpg") canvas = make. Picture(canvasf) # Now, do the actual copying source. X = 45 for target. X in range(100, 100+(200 -45)): source. Y = 25 for target. Y in range(100, 100+(200 -25)): color = get. Color(get. Pixel(barb, source. X, source. Y)) set. Color(get. Pixel(canvas, target. X, target. Y), color) source. Y = source. Y + 1 source. X = source. X + 1 show(barb) show(canvas) 70 return canvas

Scaling a picture (smaller or larger) has to do with sampling the source picture differently When we just copy, we sample every pixel If we want a smaller copy, we skip some pixels We sample fewer pixels If we want a larger copy, we duplicate some pixels We over-sample some pixels 71

Scaling the picture down def copy. Barbs. Face. Smaller(): # Set up the source and target pictures barbf=get. Media. Path("barbara. jpg") barb = make. Picture(barbf) canvasf = get. Media. Path("7 in. X 95 in. jpg") canvas = make. Picture(canvasf) # Now, do the actual copying source. X = 45 for target. X in range(100, 100+((200 -45)/2)): source. Y = 25 for target. Y in range(100, 100+((200 -25)/2)): color = get. Color(get. Pixel(barb, source. X, source. Y)) set. Color(get. Pixel(canvas, target. X, target. Y), color) source. Y = source. Y + 2 source. X = source. X + 2 show(barb) show(canvas) return canvas 72

Scaling Up: Growing the picture To grow a picture, we simply duplicate some pixels We do this by incrementing by 0. 5, but only use the integer part. >>> print int(1) 1 >>> print int(1. 5) 1 >>> print int(2) 2 >>> print int(2. 5) 2 73

Scaling the picture up def copy. Barbs. Face. Larger(): # Set up the source and target pictures barbf=get. Media. Path("barbara. jpg") barb = make. Picture(barbf) canvasf = get. Media. Path("7 in. X 95 in. jpg") canvas = make. Picture(canvasf) # Now, do the actual copying source. X = 45 for target. X in range(100, 100+((200 -45)*2)): source. Y = 25 for target. Y in range(100, 100+((200 -25)*2)): color = get. Color(get. Pixel(barb, int(source. X), int(source. Y))) set. Color(get. Pixel(canvas, target. X, target. Y), color) source. Y = source. Y + 0. 5 source. X = source. X + 0. 5 show(barb) show(canvas) return canvas 74

Scaling up: How it works Same basic setup as copying and rotating: 75

Scaling up: How it works 2 But as we increment by only 0. 5, and we use the int() function, we end up taking every pixel twice. Here, the blank pixel at (0, 0) in the source gets copied twice onto the canvas. 76

Scaling up: How it works 3 Black pixels gets copied once… 77

Scaling up: How it works 4 And twice… 78

Scaling up: How it ends up We end up in the same place in the source, but twice as much in the target. Notice the degradation: Gaps that weren’t there previously Curves would get “choppy”: Pixelated 79

What to do? How do we clear up the degradation of scaling up? Variety of techniques, but mostly following the same basic idea: Use the pixels around to figure out what color a new pixel should be, then somehow (e. g. , by averaging) compute the right color. Different techniques look at different pixels and compute different averages in different ways. 80

Blurring out the pixelation 82

Things to try: Can you come up with general copy, rotate, copy, and scale functions? Take input pictures and parameters Return the canvas the correct transformation applied Also think about generalizing the transformations: Scaling up and down by non-integer amounts Rotating by something other than 90 degree increments 83