Title: Lecture 18: Multidimensional Arrays
1Lecture 18 Multidimensional Arrays
2Some Announcements
- Since the midterm was on the long side, I will
potentially compute your final average
differently - Ill take whichever of these makes your grade
better - Midterm 15, Final 20
- Midterm 10, Final 25
- If youre not happy with your grade, do well on
the final!
3Some Announcements
- Labs are getting more involved
- Next two in particular are going to be hard
- Were doing stuff with arrays
- If you are having difficulty on lab assignments,
then be sure to ask me for help! - Email me
- I respond. Try it. Some of you know this too
well. - Come to office hours
- See me sometime outside office hours (Just email!)
4Multidimensional Arrays
- We learned how to declare an array of integers
- We could just as easily declare a two-dimensional
array
int array
int array
5Arrays of Arrays
- You can think of a 2-dimensional array as an
array of arrays - An array, each of whose elements is an array
- 3 x 6 array of arrays
int array new int36
arr
arr0
arr1
arr2
6Arrays of Arrays
- Java does internally represent this as an array
of arrays - But its usually easier for us to think of it as
a grid - arrij is how we refer to the element in the
ith row and the jth column in Java
7Constructing Multidimensional Arrays
- You can construct a 2d array how youd expect,
just provide two sets of square brackets with
numbers in them instead of one - This builds the array, along with all of its
subarrays - You can also leave the second dimension blank
- Youll need to construct each subarray separately
- This is for if you dont want something
rectangular - 1 is all youll need for most cases
int array new int36
int array new int3 for (int row0 row
lt array.length row) arrayrow new
introw1
8Touching all the elements
- A nested for loop is the most common way to
access all the elements of a two-dimensional
array - This assigns numbers 1 through 24 to the
different elements of a 6x4 array
for (int row 0 row lt 6 row) for
(int col 0 col lt 4 col)
arowcol 4row col 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23 24
9Touching all the elements
- What do you think this does?
- Should look familiar
- Something you saw in 3rd grade
for (int row 0 row lt 6 row) for
(int col 0 col lt 4 col)
arowcol row col
10Touching all the elements
- What do you think this does?
- Should look familiar
- Something you saw in 3rd grade
- Its a multiplication table!
- Unbelievable.
for (int row 0 row lt 6 row) for
(int col 0 col lt 4 col)
arowcol row col
0
1
2
3
0
0
0
0
0
0
1
2
3
1
0
2
4
6
2
0
3
6
9
3
0
4
8
12
4
0
5
10
15
5
11Switching order
- If you want to traverse the array column by
column instead of row by row, just swap the order
of the loops
for (int row 0 row lt 6 row) for
(int col 0 col lt 4 col)
arowcol row col
for (int col 0 col lt 4 col) for
(int row 0 row lt 6 row)
arowcol row col
12Switching order
for (int row 0 row lt 6 row) for
(int col 0 col lt 4 col)
arowcol row col
- In general, it doesnt matter which order you
use, if all youre going to do is touch each
element - Its a good idea to traverse things in the order
they appear in memory though - In Java, C, and C, this is row-first
- In other languages, namely FORTRAN, you would
want to traverse columns first, because arrays
are stored with columns together instead of with
rows together
for (int col 0 col lt 4 col) for
(int row 0 row lt 6 row)
arowcol row col
13Images and Arrays
- Pictures on your computer screen are a lot like
2d arrays - Theyre grids of pixels
- Each pixel has a color
- You can see this in the image of Ramses
- Its blown up at left, to show pixels
14Images and Arrays
- Could represent this in Java as a 2D array of
Colors - Each element of the array represents a pixel with
a particular color - Indices in the array are the coordinates of the
pixels in the image.
15ImageEdit
- Ive got a program with a few methods that can
turn an Image into an array of Colors - You dont have to know how to do this
- In the program we declare an array of Colors, and
a method I wrote fills it up from an image.
Image source getImage(old_well.jpg) Color
sourcePixels getPixelMap(source)
16Transforming Images
- Ive got another method to create an Image from
an array of Colors - We can thus make changes to the array of colors
and then convert it back to an image - Lets us mess with the pixels and change how the
image looks - Dont need to worry about how these work were
more concerned with how to manipulate the image
Image source getImage(old_well.jpg) Color
sourcePixels getPixelMap(source) Color
transformed new ColororigWidthorigHeight /
/fill up transformed with pixels of some
sort Image newImage makeImage(transformed)
17Minor detail -- flipped cols/rows
- The routine Im using, getPixelMap() returns the
image data as an array of Colors with one catch - The columns of pixels in the original image are
in the rows of the Java array - This is most likely to mirror the order of data
on disk - This is kind of annoying
- But this is the kind of idiosyncrasy youll find
in a real program - If you continue with computer science, there are
little details like this all over the place that
youll need to sort out
18Some graphics effects
- Ive implemented the following effects in
ImageEdit - Grayscale - converts image to black white
- Flip Horizontal - flips image horizontally
- Flip Vertical - flips image vertically
- Blur - makes the image fuzzy
- Rotate - rotates the image an arbitrary angle
- Well go through how to do these
- All of them involve looping over the original
image and filling the new image up with pixels
19Grayscale
- Calculates absolute brightness of each pixel
- This loops through the source image
- For each pixel in the source image, assigns its
brightness to the corresponding pixel in the
destination image
private void adjustSaturation() Color
transformed new Color(int)
origWidth(int) origHeight for (int
col 0 col lt transformed.length col)
for (int row 0 row lt transformedcol.len
gth row) transformedcolro
w grayscalePixel(sourcePixelscolrow)
displayPreview(transfo
rmed)
20Grayscale
- The grayscalePixel() method calculates the
brightness of the color its passed - You dont need to memorize the formula
- If you care to know, its just the L2-norm of the
(r,g,b) vector for the color passed in.
private Color grayscalePixel(Color c)
int red c.getRed() int green
c.getGreen() int blue c.getBlue()
int brightness (int)
Math.sqrt(red red green green blue
blue) return new Color(brightness,
brightness, brightness)
- The point here is that you could use any effect
- Just iterate over source image, do something to
the Colors, and assign the results to the
destination image - Were just treating Colors like numbers and
adjusting them somehow
21Flip Horizontal
- Remember how the columns of this image are in the
rows of the java array? - flipHoriz() takes advantage of this
- We only need one for loop b/c we can deal with
entire columns at once - B/c the columns are each a subarray
- Assign columns in the source image to columns on
the opposite side of the destination image
private void flipHoriz() Color
transformed new Color(int)
origWidth(int) origHeight // columns
are entire arrays, so we can assign them
directly. for (int col 0 col lt
transformed.length col)
transformedcol sourcePixelstransformed.length
- col - 1
displayPreview(transformed)
22Flip Vertical
- Cant do this the same way we did flipHoriz()
- Rows of the image (columns of the java array) are
spread across the subarrays in memory - This means we cant assign entire rows directly
- We have to use the two for loops
- Swaps pixel positions individually
- We couldve written flipHoriz() like this, but we
got extra speed by assigning arrays directly - This way is a bit slower.
private void flipVert() Color
transformed new Color(int)
origWidth(int) origHeight for (int
col 0 col lt transformed.length col)
for (int row 0 row lt transformed0.lengt
h row) transformedcolrow
sourcePixelscoltransforme
dcol.length - row - 1
displayPreview(transformed)
23Blur
- This is more complicated
- For each pixel in the destination image
- Take the average of its neighbors (outlined
below) and assign that value to the pixel (the
orange one below) - Makes the image fuzzy, because neighboring pixels
are blended together
24Blur
- Etc.
- Go through each pixel, assign the average of a
box of neighbors to that pixel in the destination
image. - On the edges, we have to make sure we dont read
columns or rows outside the array.
25Blur Code
private void blur(int range) Color
transformed new Color(int)
origWidth(int) origHeight for (int
col 0 col lt transformed.length col)
for (int row 0 row lt transformedcol.len
gth row) int counted 0
double redSum, greenSum, blueSum
redSum greenSum blueSum 0
for (int nearbyCol Math.max(0,
col - range) nearbyCol lt
Math.min(transformed.length, col range 1)
nearbyCol)
for (int rearbyRow Math.max(0, row -
range) rearbyRow lt
Math.min(transformednearbyCol.length, row
range 1)
rearbyRow) redSum
sourcePixelsnearbyColrearbyRow.getRed()
blueSum sourcePixelsnearbyC
olrearbyRow.getBlue()
greenSum sourcePixelsnearbyColrearbyRow.get
Green() counted
transformedcolrow new
Color( (int)
(Math.round(redSum / counted)),
(int) (Math.round(greenSum /
counted)), (int)
(Math.round(blueSum / counted))
)
displayPreview(transformed)
Outer loops go over all the pixels in the
destination image
26Blur Code
private void blur(int range) Color
transformed new Color(int)
origWidth(int) origHeight for (int
col 0 col lt transformed.length col)
for (int row 0 row lt transformedcol.len
gth row) int counted 0
double redSum, greenSum, blueSum
redSum greenSum blueSum 0
for (int nearbyCol Math.max(0,
col - range) nearbyCol lt
Math.min(transformed.length, col range 1)
nearbyCol)
for (int rearbyRow Math.max(0, row -
range) rearbyRow lt
Math.min(transformednearbyCol.length, row
range 1)
rearbyRow) redSum
sourcePixelsnearbyColrearbyRow.getRed()
blueSum sourcePixelsnearbyC
olrearbyRow.getBlue()
greenSum sourcePixelsnearbyColrearbyRow.get
Green() counted
transformedcolrow new
Color( (int)
(Math.round(redSum / counted)),
(int) (Math.round(greenSum /
counted)), (int)
(Math.round(blueSum / counted))
)
displayPreview(transformed)
Inner loops traverse the square of neighboring
pixels for each pixel in the source image. The
variable range determines how big the square is
27Blur Code
private void blur(int range) Color
transformed new Color(int)
origWidth(int) origHeight for (int
col 0 col lt transformed.length col)
for (int row 0 row lt transformedcol.len
gth row) int counted 0
double redSum, greenSum, blueSum
redSum greenSum blueSum 0
for (int nearbyCol Math.max(0,
col - range) nearbyCol lt
Math.min(transformed.length, col range 1)
nearbyCol)
for (int rearbyRow Math.max(0, row -
range) rearbyRow lt
Math.min(transformednearbyCol.length, row
range 1)
rearbyRow) redSum
sourcePixelsnearbyColrearbyRow.getRed()
blueSum sourcePixelsnearbyC
olrearbyRow.getBlue()
greenSum sourcePixelsnearbyColrearbyRow.get
Green() counted
transformedcolrow new
Color( (int)
(Math.round(redSum / counted)),
(int) (Math.round(greenSum /
counted)), (int)
(Math.round(blueSum / counted))
)
displayPreview(transformed)
Add to separate sums for each color component
(red, green, blue), and keep count of how many
numbers were added up
At the end, we build a color out of the average
values for each component color and put it in the
transformed image
28Rotate
- Source and destination are different sizes here
- Destination is a square the size of the sources
largest dimension - For each pixel in the destination, we figure out
its distance and angle from the center - find the un-rotated pixel in the source image
- assign its color value to the current pixel in
the transformed image - You can look over the code for this if youre
interested - I wont ask you this much math on a test. But
know that you can do this! - Its just another set of for loops, iterating
over all the pixels in a 2d-array