Digital image basics

Learning Objectives

After completing this lesson, learners should be able to:
  • Understand that a digital image is typically stored as an N-dimensional array.

  • Learn that the image array elements are called pixels (2D) or voxels (3D).

  • Examine the values and locations of pixels/voxels in an image.

Motivation

Digital images are a very important subset of the more general mathematical definition of an image. The vast majority of available algorithms and visualisation tools operate on digital images and all (as far as we know) scientific microscopes output digital images. Thus, for microscopy based science, it is crucial to understand the basic properties of digitial images and how to effectively inspect their content.

Concept map

graph TD Im("Digital image") --- A("N-D array") A --- E("Elements/Pixels/Voxels") A --- DT("Data type") A --- D("Shape/Size/Dimensions") E --- V("Value") E --- I("Indices")



Figure


Digital image pixel array and gray-scale rendering. This array (image) has two dimensions with 21 x 21 elements (pixels). The pixel values (black numbers) can be addressed by their respective pixel indices (green numbers).



Digital image dimensions

There are several ways to describe the size of a digital image. For example, the following sentences describe the same image.

  • The image has 2 dimensions, the length of dimension 0 is 200 and the length of dimension 1 is 100.
  • The image has 2 dimensions, the length of dimension 1 is 200 and the length of dimension 2 is 100.
  • The image has a size/shape of (200, 100).
  • The image has 200 x 100 pixels.

Note that “images” in bioimaging can also have more than two dimensions and one typically specifies how to map those dimensions to the physical space (x,y,z, and t). For example, if you acquire a 2-D movie with 100 time points and each movie frame consisting of 256 x 256 pixels it is quite common to represent this as a 3-D array with a shape of ( 256, 256, 100 ) accompanied with metadata such as ( (“x”, 100 nm), (“y”, 100 nm), (“t”, 1 s) ); check out the module on spatial calibration for more details on this.




Activities

Inspect a 2D image

Explore the content of a 2D image:

Example data:


Show activity for:  

ImageJ GUI

Explore pixel values and indices

  • Open image: xy_8bit__nuclei_noisy_different_intensity.tif
  • Explore different ways to inspect pixel values and indices
    • Mouse hover
      • Orient yourself by checking where the lowest pixel indices are
    • Line profile. Draw a line and [Analyze > Plot Profile] or [Ctrl + K].
    • Histogram [Analyze > Histogram] or [Ctrl + H]

skimage napari

# %%
# 2D image inspection using skimage and napari

# %%
# Load an image
from OpenIJTIFF import open_ij_tiff
image_url = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_noisy_different_intensity.tif"
image, *_ = open_ij_tiff(image_url)

# %%
# Inspect what the image actually is
print(type(image))

# %%
# Inspect the pixel values
print(image)

# %%
# Inspect the image dimensions
print(image.shape)

# %%
# Create a napari viewer for looking at the image
from napari.viewer import Viewer
napari_viewer = Viewer()

# %%
# Jupyter notebook exercise:
# Code completion: Type `napari_viewer.` and press `TAB`
# Get help: Type `napari_viewer.add_image` and press `SHIFT-TAB` 

# %%
# Add the image the viewer 
napari_viewer.add_image(image)

# %%
# Pixel value inspection in napari: 
# However with the mouse over the image and observe the pixel indices and values

# %%
# Fetch single pixel values
print(image[4, 8]) # in the background
print(image[31, 42]) # inside a nucleus

# %%
# Extract a line of pixel values across the objects
print(image[20,:])

# %% 
# Napari:
# Use the plot profile plugin to inspect a line of pixel values
 
# %%
# Extract one object as a square of pixel values
print(image[7:30,10:26])

# %%
# Compute the image min and max
# Jupyter: Use TAB to find the min and max functions
print(image.min(), image.max())

# %%
# Compute the image histogram
import matplotlib.pyplot as plt
import numpy as np
plt.hist(image.flatten(), bins=np.arange(image.min(), image.max() + 1));

# %%
# Napari:
# Alternative loading of data
# Remove the currently shown image
# Drag and drop image from browser onto napari
# Rename the layer to: image

# %%
# Fetch the image data from napari and check its shape
image = napari_viewer.layers['image'].data
print(image.shape)

MATLAB

% This MATLAB script illustrates how to explore different ways % to inspect pixel values and indices % It is recommended to read comments and to run sections separately % one after the other with the corresponding command in the Editor Toolstrip %% Choose and load the image %% % Read input image in_image = webread('https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_noisy_different_intensity.tif'); % Display input image figure imagesc(in_image) axis equal %% 1 - Explore pixels with mouse (Data Tips) %% % In the Figure window, click the Data Tips symbol % (text baloon icon on the top right corner of the image) % or select from [Tools>Data Cursor] in the Figure Toolstrip % Now if you click on the image a Data Tip window will appear % showing the coordinates [X,Y], the pixel intensity [Index] % and the assigned colour in the current display [R,G,B] % To exit the Data Tips mode, click again on the Data Tips icon % To stop displaying Data Tips, right click on the image and select % [Delete All Data Tips] % N.B. The point with the lowest coordinates [X,Y = 0,0] is normally found % on the top left corner %% 2 - Explore by linescans %% % Draw a line across the image to evaluate its intensity profile % 1. Click on the starting point of the line on the image % 2. Click on the end point of the line on the image % 3. Press [Enter] [x_coord, y_coord, line_profile] = improfile; % Plot sampled line on the image hold on plot(x_coord, y_coord, 'w.') % Create new figure showing the line profile figure plot(line_profile, 'k', 'LineWidth', 2) xlabel('Distance (pixels)') ylabel('Gray value') set(findall(gcf, '-property', 'FontSize'), 'FontSize', 14) %% 3 - Explore by plotting the image histogram %% % Produce the image histogram figure histogram(in_image) xlabel('Gray value') ylabel('Counts') set(findall(gcf, '-property', 'FontSize'), 'FontSize', 14) % Calculate some metrics from the histogram % Number of pixels included in the count: px_count = size(in_image,1)*size(in_image,2); % Mean gray value px_mean = nanmean(in_image(:)); % Standard deviation for gray values px_std = nanstd(double(in_image(:))); % Minimum gray value px_min = nanmin(in_image(:)); % Maximum gray value px_max = nanmax(in_image(:)); % Mode for gray values [px_mode, px_mode_frequency] = mode(in_image(:)); % Print metrics to screen fprintf('Count = %i\n', px_count); fprintf('Mean = %.3f\n', px_mean); fprintf('StdDev = %.3f\n', px_std); fprintf('Min = %i\n', px_min); fprintf('Max = %i\n', px_max); fprintf('Mode = %i (%i)\n', px_mode, px_mode_frequency);

Galaxy

Pixel operation in Galaxy

  • Navigate to Galaxy
  • In the tools panel on the left, click Upload Data
  • Click Paste/Fetch data button
  • Paste the URL of xy_8bit__nuclei_noisy_different_intensity.tif and click Start .
  • After the upload finishes, click the Close button. The image will then be available in your Galaxy history.
  • Pixel operations
    • In the Tools panel, search for Operate on pixels with ImageJ2, and click on it.
    • In the main window
      • Select image: select the image xy_8bit__nuclei_noisy_different_intensity.tif from the dropdown list.
      • Operation: Explore different operations from the dropdown list. Refer to the What it does section for explainations of each operation.
      • Value: Some operations requires a value, input corresponding the value.
      • Click Run Tool to start the operation.
      • Results will be available in the Galaxy History panel once the process bar turns green.



Inspect a 3D image

Explore the content of a 3D image:

Example data:


Show activity for:  

skimage napari

# %%
# 3D image inspection using skimage and napari

# %%
# Load an image
from OpenIJTIFF import open_ij_tiff
image_url = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_8bit__mri_head.tif"
image, axes, *_ = open_ij_tiff(image_url)

# %%
# Inspect the image shape
print(image.shape)

# %%
# Inspect the image axes
print(axes)

# %%
# Inspect all image pixel values, and appreciate that this is not useful for larger 3D data
print(image)

# %%
# Create a napari viewer and add the image
from napari.viewer import Viewer
napari_viewer = Viewer()
napari_viewer.add_image(image)

# %%
# Napari: 
# - However with the mouse over the image and observe the pixel indices and values
# - Use the slider to change the position of the 3rd dimension

# %%
# Extract the pixels that belong to the tip of the nose
print(image[1, 9:19, 89:102])

# %%
# Compute the image min and max
print(image.min(), image.max())

# %%
# Compute the image histogram
import matplotlib.pyplot as plt
import numpy as np
plt.hist(image.flatten(), bins=np.arange(image.min(), image.max() + 1));



Inspect tissue culture collagen secretion image


Show activity for:  

ImageJ GUI

Collagen image inspection using the ImageJ GUI

  • Open the image mentioned in the activity preface
  • Read image dimensions in image header
  • Mouse hover to see gray value and pixel position in the ImageJ status bar
  • Zoom in and out using the arrow up and down keys
  • Draw a line ROI and use Analyze > Plot Profile
    • Use the Live button to explore different image regions
  • Create a histogram using Analyze > Histogram
    • Draw a rectangluar ROI to restrict the histogram computation to a small region
    • Use the Live button to explore different image regions
      • Understand what you see in the histogram






Assessment

Answer the question

  1. If someome gives you a 2D image file and tells you to measure the value of the pixel at the indices (7,8) without telling you which programming language to use. Is that a precise enough instruction? If not, how many different pixels could that actually refer to?

Solution

  1. Unfortunately this instruction is not precise enough and, in practice it could refer to four different pixels, depending on whether this is meant to be zero or one-based indexing and depending whether this is row or column-major ordering. See here for more details.




Follow-up material

Recommended follow-up modules:

Learn more: