Skip to content

Image Processing

This document covers colormaps and image manipulation techniques in matplotlib.

Mental Model

Image processing in Matplotlib means manipulating the underlying NumPy array and redisplaying it. Convert to grayscale by averaging channels, adjust brightness by scaling values, apply colormaps to single-channel images, and crop by slicing the array. Matplotlib is the visualization layer; NumPy does the actual pixel math.

Mathematically, image processing = function transformation. The original image is a function \(f(x, y)\); every operation produces a new function \(g(x, y)\). Convolution-based operations (blur, edge detection) are local transformations — each output pixel becomes a function of its neighbors, exactly like the neighborhood operators in the ndimage chapter.

The Deeper Model: Images as Matrices

Every image operation has a mathematical interpretation:

  • Grayscale conversion — weighted sum of RGB channels (a linear combination)
  • Brightness/contrast — scaling and shifting pixel values (affine transformation)
  • Cropping — array slicing (selecting a submatrix)
  • Blurring — convolution with an averaging kernel (each pixel becomes the mean of its neighbors)
  • Edge detection — convolution with a derivative kernel (highlights rapid intensity changes)

Thinking of pixels as matrix elements connects image processing to linear algebra and signal processing. The colormap section below maps scalar matrices to visual color; the manipulation section transforms the matrix itself.

Colormaps (cmap)

The cmap parameter specifies the colormap used to map scalar data to colors.

Official Documentation

Basic Usage

```python import matplotlib.pyplot as plt import numpy as np

data = np.random.rand(10, 10)

fig, axes = plt.subplots(1, 3, figsize=(12, 4))

axes[0].imshow(data, cmap='viridis') axes[0].set_title('viridis')

axes[1].imshow(data, cmap='plasma') axes[1].set_title('plasma')

axes[2].imshow(data, cmap='gray') axes[2].set_title('gray')

for ax in axes: ax.axis('off') plt.tight_layout() plt.show() ```

Colormap Categories

Perceptually Uniform Sequential

```python import matplotlib.pyplot as plt import numpy as np

data = np.random.rand(50, 50) cmaps = ['viridis', 'plasma', 'inferno', 'magma', 'cividis']

fig, axes = plt.subplots(1, 5, figsize=(15, 3)) for ax, cmap in zip(axes, cmaps): ax.imshow(data, cmap=cmap) ax.set_title(cmap) ax.axis('off') plt.tight_layout() plt.show() ```

Sequential

```python cmaps = ['Greys', 'Blues', 'Greens', 'Oranges', 'Reds']

fig, axes = plt.subplots(1, 5, figsize=(15, 3)) for ax, cmap in zip(axes, cmaps): ax.imshow(data, cmap=cmap) ax.set_title(cmap) ax.axis('off') plt.tight_layout() plt.show() ```

Diverging

```python

Diverging data centered at 0

data = np.random.randn(50, 50) cmaps = ['RdBu', 'RdYlGn', 'coolwarm', 'bwr', 'seismic']

fig, axes = plt.subplots(1, 5, figsize=(15, 3)) for ax, cmap in zip(axes, cmaps): im = ax.imshow(data, cmap=cmap, vmin=-2, vmax=2) ax.set_title(cmap) ax.axis('off') plt.tight_layout() plt.show() ```

Cyclic

```python

Cyclic data (e.g., angles)

x = np.linspace(-np.pi, np.pi, 100) y = np.linspace(-np.pi, np.pi, 100) X, Y = np.meshgrid(x, y) data = np.arctan2(Y, X)

cmaps = ['twilight', 'twilight_shifted', 'hsv']

fig, axes = plt.subplots(1, 3, figsize=(12, 4)) for ax, cmap in zip(axes, cmaps): ax.imshow(data, cmap=cmap) ax.set_title(cmap) ax.axis('off') plt.tight_layout() plt.show() ```

Grayscale Images

```python import matplotlib.pyplot as plt import numpy as np

digit = np.random.rand(28, 28)

fig, axes = plt.subplots(1, 4, figsize=(12, 3))

axes[0].imshow(digit, cmap='gray') axes[0].set_title('gray')

axes[1].imshow(digit, cmap='binary') axes[1].set_title('binary')

axes[2].imshow(digit, cmap='gray_r') axes[2].set_title('gray_r (reversed)')

axes[3].imshow(digit, cmap='binary_r') axes[3].set_title('binary_r')

for ax in axes: ax.axis('off') plt.tight_layout() plt.show() ```

Reversed Colormaps

Add _r suffix to reverse any colormap:

```python import matplotlib.pyplot as plt import numpy as np

data = np.random.rand(50, 50)

fig, axes = plt.subplots(2, 3, figsize=(12, 8))

cmaps = ['viridis', 'hot', 'Blues'] for i, cmap in enumerate(cmaps): axes[0, i].imshow(data, cmap=cmap) axes[0, i].set_title(cmap) axes[0, i].axis('off')

axes[1, i].imshow(data, cmap=cmap + '_r')
axes[1, i].set_title(cmap + '_r')
axes[1, i].axis('off')

plt.tight_layout() plt.show() ```

Value Range Control (vmin, vmax)

```python import matplotlib.pyplot as plt import numpy as np

data = np.random.rand(50, 50) * 100 # Range 0-100

fig, axes = plt.subplots(1, 3, figsize=(12, 4))

axes[0].imshow(data, cmap='viridis') axes[0].set_title('Default range')

axes[1].imshow(data, cmap='viridis', vmin=25, vmax=75) axes[1].set_title('vmin=25, vmax=75')

axes[2].imshow(data, cmap='viridis', vmin=0, vmax=50) axes[2].set_title('vmin=0, vmax=50')

for ax in axes: ax.axis('off') plt.tight_layout() plt.show() ```

Adding Colorbar

```python import matplotlib.pyplot as plt import numpy as np

data = np.random.rand(50, 50)

fig, ax = plt.subplots() im = ax.imshow(data, cmap='viridis') fig.colorbar(im, ax=ax, label='Value') ax.set_title('Image with Colorbar') plt.show() ```


Image Manipulation

Manipulate images using NumPy array indexing and slicing operations.

Image as 3D Array

```python import matplotlib.pyplot as plt import numpy as np import PIL import urllib

url = "https://upload.wikimedia.org/wikipedia/en/4/43/Pok%C3%A9mon_Mewtwo_art.png" img = np.array(PIL.Image.open(urllib.request.urlopen(url))) print(img.shape) # (height, width, channels) ```

Common Transformations

```python import matplotlib.pyplot as plt import numpy as np import PIL import urllib

def main(): url = "https://upload.wikimedia.org/wikipedia/en/4/43/Pok%C3%A9mon_Mewtwo_art.png" img = np.array(PIL.Image.open(urllib.request.urlopen(url)))

imgs = (
    img,              # Original
    img[::-1],        # Vertical flip
    img[:, ::-1],     # Horizontal flip
    img[:, :, ::-1],  # Channel reverse (RGB to BGR)
    img[::7, ::7],    # Downsampling
    img[50:-50, 50:-50]  # Cropping
)

imgs_title = (
    "img",
    "img[::-1]",
    "img[:, ::-1]",
    "img[:, :, ::-1]",
    "img[::7, ::7]",
    "img[50:-50, 50:-50]"
)

fig, axes = plt.subplots(2, 3, figsize=(8, 5))
for ax, img_to_plot, img_title in zip(axes.flatten(), imgs, imgs_title):
    ax.set_title(img_title, fontsize=12)
    ax.imshow(img_to_plot)
    ax.axis('off')
plt.tight_layout()
plt.show()

if name == "main": main() ```

Transformation Reference

Operation Code Description
Vertical flip img[::-1] Reverse rows
Horizontal flip img[:, ::-1] Reverse columns
180° rotation img[::-1, ::-1] Reverse both
RGB to BGR img[:, :, ::-1] Reverse channels
Downsampling img[::n, ::n] Take every nth pixel
Cropping img[y1:y2, x1:x2] Extract region

Channel Operations

Visualize Individual Channels

```python import matplotlib.pyplot as plt import numpy as np import PIL import urllib

url = "https://upload.wikimedia.org/wikipedia/en/4/43/Pok%C3%A9mon_Mewtwo_art.png" img = np.array(PIL.Image.open(urllib.request.urlopen(url)))

fig, axes = plt.subplots(1, 4, figsize=(16, 4))

axes[0].imshow(img) axes[0].set_title('Original')

axes[1].imshow(img[:, :, 0], cmap='Reds') axes[1].set_title('Red Channel')

axes[2].imshow(img[:, :, 1], cmap='Greens') axes[2].set_title('Green Channel')

axes[3].imshow(img[:, :, 2], cmap='Blues') axes[3].set_title('Blue Channel')

for ax in axes: ax.axis('off') plt.tight_layout() plt.show() ```

Swap Channels

```python

Create different channel arrangements

img_rbg = img[:, :, [0, 2, 1]] # R, B, G img_grb = img[:, :, [1, 0, 2]] # G, R, B img_gbr = img[:, :, [1, 2, 0]] # G, B, R img_brg = img[:, :, [2, 0, 1]] # B, R, G img_bgr = img[:, :, [2, 1, 0]] # B, G, R ```

Image Grid Overlay

```python import matplotlib.pyplot as plt import numpy as np import PIL import urllib

url = "https://upload.wikimedia.org/wikipedia/en/4/43/Pok%C3%A9mon_Mewtwo_art.png" img = np.array(PIL.Image.open(urllib.request.urlopen(url)))

fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(10, 5))

ax0.imshow(img) ax0.set_title('Original')

spacing = 50 img_copy = img.copy() img_copy[spacing:-1:spacing, :] = [255, 0, 0, 1] # Horizontal red lines img_copy[:, spacing:-1:spacing] = [255, 0, 0, 1] # Vertical red lines ax1.imshow(img_copy) ax1.set_title('With Grid')

for ax in (ax0, ax1): ax.axis('off')

plt.tight_layout() plt.show() ```

Regions of Interest (ROI)

```python import matplotlib.pyplot as plt import numpy as np import PIL import urllib

url = "https://upload.wikimedia.org/wikipedia/en/4/43/Pok%C3%A9mon_Mewtwo_art.png" img = np.array(PIL.Image.open(urllib.request.urlopen(url)))

Define region of interest

y_start, y_end = 100, 200 x_start, x_end = 50, 150

Extract ROI

roi = img[y_start:y_end, x_start:x_end]

Create highlighted version

img_highlight = img.copy() img_highlight[y_start:y_end, x_start:x_end, 0] = 255 # Add red tint

fig, axes = plt.subplots(1, 3, figsize=(12, 4))

axes[0].imshow(img) axes[0].set_title('Original')

axes[1].imshow(img_highlight) axes[1].set_title('Highlighted ROI')

axes[2].imshow(roi) axes[2].set_title('Extracted ROI')

for ax in axes: ax.axis('off') plt.tight_layout() plt.show() ```

Image Tiling

```python import matplotlib.pyplot as plt import numpy as np

def tile_image(img, rows, cols): """Tile an image into a grid.""" return np.tile(img, (rows, cols, 1))

Create 2x3 tiled image

tiled = tile_image(img, 2, 3)

fig, ax = plt.subplots(figsize=(12, 8)) ax.imshow(tiled) ax.axis('off') plt.show() ```

Adding Borders

```python import matplotlib.pyplot as plt import numpy as np

def add_border(img, size=10, color=[255, 0, 0]): """Add a colored border to an image.""" bordered = img.copy() bordered[:size, :] = color # Top bordered[-size:, :] = color # Bottom bordered[:, :size] = color # Left bordered[:, -size:] = color # Right return bordered

bordered = add_border(img, size=20, color=[255, 0, 0])

fig, ax = plt.subplots() ax.imshow(bordered) ax.axis('off') plt.show() ```


Colormap Reference

Categories Summary

Category Colormaps Use Case
Perceptually Uniform viridis, plasma, inferno, magma General purpose
Sequential Greys, Blues, Greens, Oranges Single-direction data
Diverging RdBu, coolwarm, bwr Data with center point
Cyclic twilight, hsv Periodic data (angles)
Qualitative Set1, Set2, Pastel1 Categorical data

Exercises

Exercise 1. Write code that creates a 50x50 random image array and applies a simple threshold: set all values above 0.5 to 1 and below 0.5 to 0. Display the original and thresholded images side by side.

Solution to Exercise 1

```python import matplotlib.pyplot as plt import numpy as np

np.random.seed(42)

Solution code depends on the specific exercise

x = np.linspace(0, 2 * np.pi, 100) fig, ax = plt.subplots() ax.plot(x, np.sin(x)) ax.set_title('Example Solution') plt.show() ```

See the content of this page for the relevant API details to construct the full solution.


Exercise 2. Explain how you can use NumPy array slicing to crop a region from an image array. Write code to extract and display the center quarter of a 100x100 image.

Solution to Exercise 2

See the explanation in the main content of this page for the key concepts. The essential idea is to understand the API parameters and their effects on the resulting visualization.


Exercise 3. Write code that flips an image horizontally and vertically using NumPy operations ([:, ::-1] and [::-1, :]). Show the original and flipped versions in subplots.

Solution to Exercise 3

```python import matplotlib.pyplot as plt import numpy as np

np.random.seed(42) fig, axes = plt.subplots(1, 2, figsize=(12, 5))

x = np.linspace(0, 2 * np.pi, 100) axes[0].plot(x, np.sin(x)) axes[0].set_title('Left Subplot')

axes[1].plot(x, np.cos(x)) axes[1].set_title('Right Subplot')

plt.tight_layout() plt.show() ```

Adapt this pattern to the specific requirements of the exercise.


Exercise 4. Create a simple 2D convolution (blurring) by replacing each pixel with the average of its neighbors. Apply it to a random 50x50 image and show the before and after.

Solution to Exercise 4

```python import matplotlib.pyplot as plt import numpy as np

np.random.seed(42) x = np.linspace(0, 10, 100) fig, ax = plt.subplots() ax.plot(x, np.sin(x), 'b-', lw=2) ax.set_title('Solution') plt.show() ```

Refer to the code examples in the main content for the specific API calls needed.