Monday, March 23rd, 2026¶

Before the break, we started to discuss representing RGB images as 3D numpy arrays.

In [1]:
import numpy as np
import matplotlib.pyplot as plt

RGB(s) image arrays¶

Recall: Most computer images are stored as arrays of RGB(A) values. We can read an image file into an RGB(A) array using plt.imread. The syntax is: plt.imread(<path to some image file>). For example, download the image mario.png from the course webpage and place it into the same folder as this Jupyter notebook.

In [37]:
mario = plt.imread('mario.png')
print(mario.shape)

plt.imshow(mario)
(224, 256, 4)
Out[37]:
<matplotlib.image.AxesImage at 0x23c9ab62490>
No description has been provided for this image
In [ ]:
 

We can look at the shape of the array to see if it contains RGB or RGBA values. In this case, the mario.png image file includes a transparency channel.

In [3]:
print(mario.shape)
(224, 256, 4)

Exercise: Use NumPy slicing to remove the transparency channel from the mario array.**

In [38]:
mario = mario[:, :, :3]
In [5]:
plt.imshow(mario)
Out[5]:
<matplotlib.image.AxesImage at 0x23c92747390>
No description has been provided for this image

Exercise: Use NumPy slicing and plt.imshow to zoom in on Mario (in the lower-left corner).

In [7]:
plt.imshow(mario[175:210, 25:75])
Out[7]:
<matplotlib.image.AxesImage at 0x23c91f84690>
No description has been provided for this image
In [ ]:
 

Exercise: Create an array blueless_mario where the blue channel information from mario has been removed (i.e. set to 0) and plot using plt.imshow.

In [22]:
plt.imshow(mario[:,:,2],cmap='Blues',vmin=0,vmax=1)
Out[22]:
<matplotlib.image.AxesImage at 0x23c9926fc50>
No description has been provided for this image
In [10]:
blueless_mario = mario.copy()

blueless_mario[:, :, 2] = 0
plt.imshow(blueless_mario)
Out[10]:
<matplotlib.image.AxesImage at 0x23c91fe2490>
No description has been provided for this image
In [ ]:
 

Exercise: Create an array mixed_mario where:

  • the red channel of mixed_mario matches the green channel of mario,
  • the green channel of mixed_mario matches the blue channel of mario,
  • the blue channel of mixed_mario matches the red channel of mario.
In [23]:
mixed_mario = mario.copy()

mixed_mario[:,:,0] = mario[:,:,1]
mixed_mario[:,:,1] = mario[:,:,2]
mixed_mario[:,:,2] = mario[:,:,0]
In [24]:
plt.imshow(mixed_mario)
Out[24]:
<matplotlib.image.AxesImage at 0x23c992ef110>
No description has been provided for this image
In [25]:
mario[0,0]
Out[25]:
array([0.36078432, 0.5803922 , 0.9882353 ], dtype=float32)

Note: For the next project, we will be working with integer-valued RGB triples. The integer-values will range from 0 to 255. An integer 0 means no color while an integer 255 means full color (equivalent to a float of 1).

Exercise: Convert the mario array to an integer-type array mario_RGB_int containing RGB triples with values between 0 and 255.

In [31]:
mario_int = (255 * mario).astype(int)

mario_int[0,0]
Out[31]:
array([ 92, 148, 252])
In [32]:
plt.imshow(mario_int)
Out[32]:
<matplotlib.image.AxesImage at 0x23c99515810>
No description has been provided for this image

Exercise: Convert the mario_RGB_int array into a float-type array containing RGB triples with values between 0 and 1.

In [43]:
mario_float = mario_int / 255
plt.imshow(mario_float)
Out[43]:
<matplotlib.image.AxesImage at 0x23c9abed590>
No description has been provided for this image

Project 3: Tartans¶

Let's get started working with tartans by generating vertical and horizontal stripes for the following pattern (see project page for details):

Pattern :

B14 K6 B6 K6 B6 K32 OG32

where the colors B, K, and OG are given by the RGB triples:

B : [52, 80, 100]
K : [16, 16, 16]
OG : [92, 100, 40]

To get started, we'll need to initialize an array with the correct shape. What is the total width of this pattern?

In [44]:
total_width = 14 + 6 + 6 + 6 + 6 + 32 + 32
print(total_width)
102
In [49]:
vertical_stripes = np.zeros((102, 102, 3), dtype=int)

Right now, our array is a pure black picture. Let's add the first vertical stripe, which has color B = [52, 80, 100] and has width 14.

In [55]:
vertical_stripes[:, :14] = (52, 80, 100)
vertical_stripes[:, 14:20] = (16, 16, 16)


plt.imshow(vertical_stripes)
Out[55]:
<matplotlib.image.AxesImage at 0x23c9b127ed0>
No description has been provided for this image
In [ ]:
widths = [14, 6, 6, 6, 6, 32, 32]
colors = ...
In [52]:
first_names = ['Jon', 'Callen', 'Morgan']
last_names = ['Lottes', 'Dalton', 'Gunther']

for first_name, last_name in zip(first_names, last_names):
    print(first_name, last_name)
Jon Lottes
Callen Dalton
Morgan Gunther

Exercise: Add the remaining stripes from the sample pattern to the vertical_stripes array.

Pattern :

B14 K6 B6 K6 B6 K32 OG32

where the colors B, K, and OG are given by the RGB triples:

B : [52, 80, 100]
K : [16, 16, 16]
OG : [92, 100, 40]

In [56]:
B = (52, 80, 100)
K = (16, 16, 16)
OG = (92, 100, 40)

vertical_stripes[:, :14] = B
vertical_stripes[:, 14:20] = K
vertical_stripes[:, 20:26] = B
vertical_stripes[:, 26:32] = K
vertical_stripes[:, 32:38] = B
vertical_stripes[:, 38:70] = K
vertical_stripes[:, 70:102] = OG

plt.imshow(vertical_stripes)
Out[56]:
<matplotlib.image.AxesImage at 0x23c9b2f5d10>
No description has been provided for this image
In [ ]:
 

Some thoughts:

  • We need a much better way to generate this vertical stripes array. There was far too much manual typing/calculation to add each stripe. We'll come back and address this shortly.
  • Now that we have an array of vertical stripes, we can easily generate an array of horizontal stripes. This can be done transposing our array (see below).
  • Once we have vertical and horizontal stripes, we need to super-impose them somehow to generate the tartan pattern.

Array transposes¶

For a 2-dimensional matrix, the transpose flips rows and columns. That is, the first row becomes the first column, the second row becomes the second column, etc. In Python, we can use the .T method on a 2D array to get its transpose:

In [60]:
A = np.arange(25).reshape(5,5)
print(A)
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]]
In [61]:
print(A.T)
[[ 0  5 10 15 20]
 [ 1  6 11 16 21]
 [ 2  7 12 17 22]
 [ 3  8 13 18 23]
 [ 4  9 14 19 24]]

We would like to take the transpose of our vertical_stripes array so that the columns of vertical_stripes become the rows of horizontal_stripes. In other words, the vertical stripes will become horizontal stripes.

Problem: The vertical_stripes array is a 3-dimensional array (rows, columns, color channels). What does vertical_stripes.T give us in this case?

In [64]:
vertical_stripes.T.shape
Out[64]:
(3, 102, 102)
In [ ]:
 

It turns out that the .T attribute reverses the order of the axes. That is, the first axis (rows) becomes the last axis, the second axis (columns) becomes the second-last axis, etc. In the case of the vertical_stripes array, the color channel axis became the row axis, the column axis remained as the column axis, and the row axis became the color channel axis. For our needs, this is not useful. Instead, we just want to swap the row and column axes.

We can use the np.transpose function to do more targeted transposing:

In [68]:
#help(np.transpose)

When calling np.transpose, we can optionally supply a keyword argument axes which gives a permutation of the axes of the array. In particular, using axes = [1, 0, 2] will give a transposed matrix where:

  • the old axis 1 (i.e. the columns) becomes the new axis 0 (i.e. the rows),
  • the old axis 0 becomes the new axis 1, and
  • the old axis 2 (i.e. the color channel) remains as axis 2.

Let's use this to define the horizontal_stripes array.

In [71]:
horizontal_stripes = np.transpose(vertical_stripes, axes=[1,0,2])
In [72]:
plt.imshow(horizontal_stripes)
Out[72]:
<matplotlib.image.AxesImage at 0x23c9b1cfc50>
No description has been provided for this image

Creating a tartan from vertical and horizontal arrays¶

We now have vertical and horizontal stripes. How can we combine them to get a tartan pattern?

One simple idea is to take the average of the horizontal and vertical stripe arrays.

In [75]:
averaged_tartan = (horizontal_stripes + vertical_stripes) // 2
In [76]:
plt.imshow(averaged_tartan)
Out[76]:
<matplotlib.image.AxesImage at 0x23c9c503890>
No description has been provided for this image

This gives flat colors rather than an interleaved combination. Can we instead generate a checkerboard pattern to interleave these stripes? To do so, we want to go row by row, column by column, and alternatingly select a color from the vertical_stripes and horizontal_stripes arrays.

Exercise: Create a checkerboard_tartan array that combines the vertical_stripes and horizontal_stripes arrays in checkerboard pattern.

In [ ]:
checkerboard_tartan = np.zeros((102, 102, 3))

for row in range(102):
    for col in range(102):
        
In [ ]: