Chapter 3: Modifying Pictures Using Loops
Chapter 3: Modifying Pictures Using Loops
Loops
We perceive light
different
from
how
it
Color is continuous
actually is
nanometers
perception is based on
comparison to
backgrounds, not raw
values.
Luminanceisactually
colorblind.Completely
differentpartofthebrain
doesluminancevs.color.
Digitizing pictures as
bunches
of
little
dots
particulary low
a pixel
Pixels
Pixels are picture elements
Each pixel object knows its color
It also knows where it is in its picture
Whenwezoomthe
pictureto500%,we
canseeindividual
pixels.
A Picture is a matrix
of
Its pixels
not a
continuous line of
elements, that is,
an array
A picture has two
dimensions: Width
and Height
We need a twodimensional array:
a matrix
Referencing a matrix
We talk about
positions in a
matrix as (x,y),
or (horizontal,
vertical)
Element (1,0) in
the matrix at left
is the value 12
Element (0,2) is 6
Encoding color
Each pixel encodes color at that
Encoding RGB
Each component color
(200,200,200) at (3,1)
in example) is black
(255,255,255) is white
0 and 1.
If we have two bits, we can represent four patterns:
00, 01, 10, and 11.
If we have three bits, we can represent eight
patterns: 000, 001, 010, 011, 100, 101, 110, 111
patterns
Is that enough?
Were representing color in 24 (3 * 8) bits.
Thats 16,777,216 (224) possible colors
Our eye can discern millions of colors, so
its probably pretty close
But the real limitation is the physical
devices: We dont get 16 million colors out
of a monitor
Some graphics systems support 32 bits per
pixel
Size of images
320 x 240
image
640 x 480
image
1024 x 768
monitor
24 bit color
230,400
bytes
32 bit color
307,200
bytes
1,228,800
bytes
3,145,728
bytes
>>>file=pickAFile()
>>>printfile
/Users/guzdial/mediasources/barbara.jpg
>>>picture=makePicture(file)
>>>show(picture)
>>>printpicture
Picture,filename/Users/guzdial/mediasources/barbara.jpg
height294width222
Whats a picture?
An encoding that represents an image
Knows its height and width
Knows its filename
Knows its window if its opened (via
show and repainted with repaint)
Manipulating pixels
getPixel(picture,x,y)getsasinglepixel.
getPixels(picture)getsalloftheminanarray.
(Squarebracketsisastandardarrayreference
notationwhichwellgenerallynotuse.)
>>>pixel=getPixel(picture,1,1)
>>>printpixel
Pixel,color=colorr=168g=131b=105
>>>pixels=getPixels(picture)
>>>printpixels[0]
Pixel,color=colorr=168g=131b=105
TheMediaToolsmenu
knowswhatvariables
youhaveinthe
CommandAreathat
containpictures
Distance between
colors?
Sometimes you need to, e.g., when deciding
if something is a close enough match
How do we measure distance?
Pretend its cartesian coordinate system
Distance between two points:
>>>printgetRed(pixel)
168
>>>setRed(pixel,255)
>>>printgetRed(pixel)
255
>>>color=getColor(pixel)
>>>printcolor
colorr=255g=131b=105
>>>setColor(pixel,color)
>>>newColor=makeColor(0,100,0)
>>>printnewColor
colorr=0g=100b=0
>>>setColor(pixel,newColor)
>>>printgetColor(pixel)
colorr=0g=100b=0
>>>printcolor
colorr=81g=63b=51
>>>printnewcolor
colorr=255g=51b=51
>>>printdistance(color,newcolor)
174.41330224498358
>>>printcolor
colorr=168g=131b=105
>>>printmakeDarker(color)
colorr=117g=91b=73
>>>printcolor
colorr=117g=91b=73
>>>newcolor=pickAColor()
>>>printnewcolor
colorr=255g=51b=51
>>>file="/Users/guzdial/mediasources/barbara.jpg"
>>>pict=makePicture(file)
>>>show(pict)
>>>setColor(getPixel(pict,10,100),yellow)
>>>setColor(getPixel(pict,11,100),yellow)
>>>setColor(getPixel(pict,12,100),yellow)
>>>setColor(getPixel(pict,13,100),yellow)
>>>repaint(pict)
Butthatsreallydullandboringto
changeeachpixelatatime
Isntthereabetterway?
defdecreaseRed(picture):
forpingetPixels(picture):
value=getRed(p)
setRed(p,value*0.5)
Usedlikethis:
>>>file="/Users/guzdial/mediasources/barbara.jpg"
>>>picture=makePicture(file)
>>>show(picture)
>>>decreaseRed(picture)
>>>repaint(picture)
The loop
- Note the
indentation!
How for
loops are
written
for is the name
def decreaseRed(pict):
allPixels = getPixels(pict)
for p in allPixels:
value = getRed(p)
setRed(p, value * 0.5)
of the command
An index variable is used to hold each of
the different values of a sequence
The word in
A function that generates a sequence
The index variable will be the name for
one value in the sequence, each time
through the loop
A colon (:)
And a block (the indented lines of code)
the sequence
The block is executed
The variable is often used inside the
block
getPixels returns a
sequence
of
pixels
Each pixel knows
its color and
place in the
original picture
Change the pixel,
you change the
picture
So the loops here
assign the index
variable p to
each pixel in the
picture picture,
one at a time.
def decreaseRed(picture):
allPixels = getPixels(picture)
for p in allPixels
originalRed = getRed(p)
setRed(p, originalRed * 0.5)
or equivalently
def decreaseRed(picture):
for p in getPixels(picture):
originalRed = getRed(p)
setRed(p, originalRed * 0.5)
def decreaseRed(picture):
for p in getPixels(picture):
originalRed = getRed(p)
setRed(p, originalRed * 0.5)
def decreaseRed(picture):
for p in getPixels(picture):
setRed(p, getRed(p) * 0.5)
objectinasaparameterto
thefunctionandcallit
picture
picture
Wegetallthepixelsfrom
thepicture,thenmakepbe
thenameofeachoneoneat
atime
picture
Pixel,
color
r=135
g=131
b=105
p
Pixel,
color
r=133
g=114
b=46
Pixel,
color
r=134
g=114
b=45
getPixels()
def decreaseRed(picture):
for p in getPixels(picture):
originalRed = getRed(p)
setRed(p, originalRed * 0.5)
Wegettheredvalueof
pixelpandnameit
originalRed
picture
Pixel,
color
r=135
g=131
b=105
p
Pixel,
color
r=133
g=114
b=46
Pixel,
color
r=134
g=114
b=45
getPixels()
originalRed= 135
Settheredvalueofpixelp
to0.5(50%)of
originalRed
picture
Pixel,
color
r=67
g=131
b=105
p
Pixel,
color
r=133
g=114
b=46
Pixel,
color
r=134
g=114
b=45
getPixels()
originalRed = 135
Moveontothenextpixel
andnameitp
picture
Pixel,
color
r=67
g=131
b=105
Pixel,
color
r=133
g=114
b=46
p
Pixel,
color
r=134
g=114
b=45
getPixels()
originalRed = 135
def decreaseRed(picture):
for p in getPixels(picture):
originalRed = getRed(p)
setRed(p, originalRed * 0.5)
SetoriginalRedtothered
valueatthenewp,then
changetheredatthatnew
pixel.
picture
Pixel,
color
r=67
g=131
b=105
Pixel,
color
r=133
g=114
b=46
p
Pixel,
color
r=134
g=114
b=45
getPixels()
originalRed = 133
def decreaseRed(picture):
for p in getPixels(picture):
originalRed = getRed(p)
setRed(p, originalRed * 0.5)
Changetheredvalueatpixelpto
50%ofvalue
picture
Pixel,
color
r=67
g=131
b=105
Pixel,
color
r=66
g=114
b=46
p
Pixel,
color
r=134
g=114
b=45
value = 133
getPixels()
And eventually, we do
all
We go pixels
from this
to this!
Tracing/Stepping/Walki
ng
through
the
program
What we just did is called stepping or
whatever picture we
provided as input!
forpingetPixels(picture):
value=getRed(p)
setRed(p,value*0.5)
NOTE:Ifyouhavea
variablepictureinyour
CommandArea,thats
notthesameasthe
pictureindecreaseRed.
Read it as a Recipe
defdecreaseRed(pict):
forpingetPixels(pict):
value=getRed(p)
setRed(p,value*0.5)
Recipe: To decrease the red
Ingredients: One picture, name it pict
Step 1: Get all the pixels of pict. For
Youcanalsouse:
explore(pic)
toopentheMediaTools
Whathappenedhere?!?
Increasing Red
Rememberthatthelimit
def increaseRed(picture):
for p in getPixels(picture):
value=getRed(p)
setRed(p,value*1.2)
forrednessis255.
Ifyougobeyond255,all
kindsofweirdthingscan
happenifyouhave
Modulocheckedin
Options.
Clearing Blue
defclearBlue(picture):
forpingetPixels(picture):
setBlue(p,0)
Again,thiswillworkforany
picture.
Trysteppingthroughthisone
yourself!
A Sunset-generation
defmakeSunset(picture):
Function
forpingetPixels(picture):
value=getBlue(p)
setBlue(p,value*0.7)
value=getGreen(p)
setGreen(p,value*0.7)
Lightening and
darkening an image
def lighten(picture):
for px in
getPixels(picture):
color = getColor(px)
color =
makeLighter(color)
setColor(px ,color)
def darken(picture):
for px in
getPixels(picture):
color = getColor(px)
color =
makeDarker(color)
setColor(px ,color)
Creating a negative
Lets think it through
R,G,B go from 0 to 255
Lets say Red is 10. Thats very light
red.
10
defnegative(picture):
forpxingetPixels(picture):
red=getRed(px)
green=getGreen(px)
blue=getBlue(px)
negColor=makeColor(255red,255green,255blue)
setColor(px,negColor)
Converting to
greyscale
defgreyScale(picture):
forpingetPixels(picture):
intensity=(getRed(p)+getGreen(p)+getBlue(p))/3
setColor(p,makeColor(intensity,intensity,intensity))
as brighter
Even if, physically, the same amount of
light is coming off of each
Building a better
greyscale
Well weight red, green, and blue
based
on how light we perceive them to be,
based on laboratory experiments.
defgreyScaleNew(picture):
forpxingetPixels(picture):
newRed=getRed(px)*0.299
newGreen=getGreen(px)*0.587
newBlue=getBlue(px)*0.114
luminance=newRed+newGreen+newBlue
setColor(px,makeColor(luminance,luminance,luminance))
def reduceBlue(picture):
for p in
getPixels(picture):
value=getBlue(p)
setBlue(p,value
*0.7)
def
reduceGreen(picture):
for p in
getPixels(picture):
value=getGreen(p)
setGreen(p,value
*0.7)
like
picture in both a function and in the
Command Area?
Why do we write the functions like
this? Would other ways be just as
good?
Is there such a thing as a better or
worse function?
Why dont we just build in calls to
pickAFile and makePicture?
make them
reusable?
A reusable function does One and Only One
Thing
defmakeSunset(picture):
forpingetPixels(picture):
value=getBlue(p)
setBlue(p,value*0.7)
value=getGreen(p)
setGreen(p,value*0.7)
Yes,theydotheexact
samething!
makeSunset(somepict)
worksthesameinboth
cases
defmakeSunset(picture):
reduceBlue(picture)
reduceGreen(picture)
defreduceBlue(picture):
forpingetPixels(picture):
value=getBlue(p)
setBlue(p,value*0.7)
defreduceGreen(picture):
forpingetPixels(picture):
value=getGreen(p)
setGreen(p,value*0.7)
reduceBlue and
reduceGreen
Thats important!
defmakeSunset(picture):
reduceBlue(picture)
reduceGreen(picture)
defreduceBlue(picture):
forpingetPixels(picture):
value=getBlue(p)
setBlue(p,value*0.7)
defreduceGreen(picture):
forpingetPixels(picture):
value=getGreen(p)
setGreen(p,value*0.7)
Programsarewrittenforpeople,notcomputers!
Considering
variations
We can only do this because
reduceBlue and reduceGreen,
do one and only one thing.
If we put pickAFile and
makePicture in them, wed
have to pick a file twice
(better be the same file),
make the picturethen save
the picture so that the
next one could get it!
defmakeSunset(picture):
reduceBlue(picture)
reduceGreen(picture)
defreduceBlue(picture):
forpingetPixels(picture):
value=getBlue(p)
setBlue(p,value*0.7)
defreduceGreen(picture):
forpingetPixels(picture):
value=getGreen(p)
setGreen(p,value*0.7)
thing.
Its built on lower-level one and only one
thing
defmakeSunset(picture):
reduceBlue(picture)
reduceGreen(picture)
defreduceBlue(picture):
forpingetPixels(picture):
value=getBlue(p)
setBlue(p,value*0.7)
defreduceGreen(picture):
forpingetPixels(picture):
value=getGreen(p)
setGreen(p,value*0.7)
makeSunset(picture)
Whatever object that is in the Command Area variable
placeholder
It takes the place of the input object
decreaseRed is created
within the scope of
decreaseRed
That means that it only
If we tried to print
defdecreaseRed(picture):
forpingetPixels(picture):
value=getRed(p)
setRed(p,value*0.5)
Writing real
functions
Functions in the mathematics
sense
take input and usually return output.
Like ord() or makePicture()
defdecreaseRed(picture,amount):
forpingetPixels(picture):
value=getRed(p)
setRed(p,value*amount)
First,itsperfectlyokaytohavemultipleinputstoafunction.
ThenewdecreaseRednowtakesaninputofthemultiplierforthe
redvalue.
decreaseRed(picture,0.5)woulddothesamething
decreaseRed(picture,1.25)wouldincreasered25%
should probably be
called changeRed
because thats what
it does.
Is it more general?
Yes.
less understandable.
You can be too general
defdecreaseRed(picture,amount):
forpingetPixels(picture):
value=getRed(p)
setRed(p,value*amount)
Understandability
comes
first
Consider these two functions below
They do the same thing!
The one on the right looks like the other
defclearBlue(picture):
forpingetPixels(picture):
setBlue(p,0)
defclearBlue(picture):
forpingetPixels(picture):
value=getBlue(p)
setBlue(p,value*0)