Mastering Bioimage Analysis with Python: A Deep Dive into Histograms
Written on
Chapter 1: Introduction to Histograms in Bioimage Analysis
Welcome to the tutorial series on Bioimage Analysis with Python. In this installment, we will focus on histograms, an essential component in the realm of computer vision and bioimage analysis. Our hands-on approach utilizes Python to demonstrate the significance of histograms in microscopy.
Creating a Histogram
Previously, we discussed that images are made up of pixels, each represented as numerical values in the eyes of a computer. When displayed, these pixel values are transformed into squares, providing a visual representation that helps us quickly comprehend the image's content. As images consist of data, histograms serve as a tool to better interpret this information.
Table of Contents
- Creating a Histogram
- Histograms and Image Acquisition
- Comparing Images and Histograms
- The Deceptive Nature of Appearances
- Utilizing Histograms as Analytical Tools
- Conclusion
- References
What is a Histogram?
A histogram visually depicts the distribution of pixel intensities within an image. It summarizes the intensity values, with the x-axis representing pixel intensity (typically from 0 to 255 for an 8-bit image) and the y-axis indicating the frequency of pixels at each intensity level.
The following Python code illustrates how to read an image, crop it, and display both the cropped image and its histogram.
# Import necessary libraries
from matplotlib_scalebar.scalebar import ScaleBar
import matplotlib.pyplot as plt
from skimage import exposure
import skimage as sk
import numpy as np
# Read an image using scikit-image
img = sk.io.imread("Single_channel_eisosome.tif")
# Crop the image to a specific region
img = img[400:480, 185:265]
# Print the dimensions of the cropped image
print(f"The dimensions of the image are: {img.shape[0]} x {img.shape[1]} pixels")
# Create a figure with two subplots
fig, axs = plt.subplots(1, 2, figsize=(6, 4))
# Display the cropped image
axs[0].imshow(img, cmap="gray")
axs[0].set_title("Image")
axs[0].set_axis_off()
# Add a scale bar
scalebar = ScaleBar(0.13, units='um', location='lower right', scale_loc='bottom', length_fraction=0.25)
axs[0].add_artist(scalebar)
# Create a histogram of pixel values
axs[1].hist(img.flatten(), bins=100)
axs[1].set_title("Histogram")
plt.tight_layout()
The dimensions of the image are: 80 x 80 pixels
Histograms and Image Acquisition
Histograms are integral to most microscopy software, especially in the initial stages of image analysis. For example, the histogram of the 8-bit image mentioned above ranges from 0 (black) to 255 (white). While fluorescence images may appear bright through the microscope, capturing satisfactory results often requires extended exposure, which can pose challenges in photomicrography.
The shape and distribution of a histogram can indicate whether the exposure time is appropriate. In many microscopy images, a dark field of view prevails, leading to histograms dominated by low intensity values. Optimal imaging conditions allow for the entire dynamic range to be utilized, enhancing image quality.
The following Python code demonstrates how to analyze images captured under varying exposure conditions.
# Read images with different exposure times
over = sk.io.imread("over.tif")
under = sk.io.imread("under.tif")
good = sk.io.imread("good.tif")
# Create a figure with two rows and three columns of subplots
fig, axs = plt.subplots(2, 3, figsize=(9, 9))
# Display the optimal exposure image
axs[0, 0].imshow(good[:,:,0], cmap="gray")
axs[0, 0].set_title("Optimal Exposure Image")
axs[0, 0].set_axis_off()
scalebar = ScaleBar(0.18, units='um', location='lower right', scale_loc='bottom', length_fraction=0.25)
axs[0,0].add_artist(scalebar)
# Histogram for optimal exposure
axs[1,0].hist(good[:,:,0].flatten(), bins=256)
axs[1,0].set_title("Optimal Exposure")
# Display the underexposed image
axs[0, 1].imshow(under[:,:,0], cmap="gray")
axs[0, 1].set_title("Underexposed Image")
axs[0, 1].set_axis_off()
scalebar = ScaleBar(0.180, units='um', location='lower right', scale_loc='bottom', length_fraction=0.25)
axs[0,1].add_artist(scalebar)
# Histogram for underexposed image
axs[1,1].hist(under[:,:,0].flatten(), bins=256)
axs[1,1].set_title("Underexposed Image")
# Display the overexposed image
axs[0, 2].imshow(over[:,:,0], cmap="gray")
axs[0, 2].set_title("Overexposed Image")
axs[0, 2].set_axis_off()
scalebar = ScaleBar(0.180, units='um', location='lower right', scale_loc='bottom', length_fraction=0.25)
axs[0,2].add_artist(scalebar)
# Histogram for overexposed image
axs[1,2].hist(over[:,:,0].flatten(), bins=255)
axs[1,2].set_title("Overexposed Image")
plt.tight_layout()
Comparing Images and Histograms
Histograms are essential for analyzing and comparing pixel intensity distributions in images. By examining histograms alongside summary statistics (such as mean and standard deviation), we can gain insights into overall brightness and contrast.
In bioimage processing, comparing histograms is critical for evaluating the effects of various treatments on subcellular staining intensities. Observable changes in histograms can indicate underlying biological variations resulting from different experimental conditions.
The Deceptive Nature of Appearances
Visual perception can often mislead. The following Python code illustrates this by showcasing two images: one inverted using a skimage utility and the other inverted visually with the gray_r colormap. While visual differences may be subtle, analyzing histograms and summary statistics reveals significant variations that may not be immediately apparent.
# Create a figure with two rows and two columns of subplots
fig, axs = plt.subplots(2, 2, figsize=(8, 8))
# Original Image
axs[0, 0].imshow(img, cmap="gray_r")
axs[0, 0].set_title("Original Image")
axs[0, 0].set_axis_off()
scalebar = ScaleBar(0.13, units='um', location='lower right', scale_loc='bottom', length_fraction=0.25)
axs[0, 0].add_artist(scalebar)
# Histogram of Original Image
axs[1, 0].hist(img.flatten(), bins=255)
axs[1, 0].set_title("Histogram of Original Image")
# Inverted Image
img_r = util.invert(img)
axs[0, 1].imshow(img_r, cmap="gray")
axs[0, 1].set_title("Inverted Image")
axs[0, 1].set_axis_off()
scalebar = ScaleBar(0.13, units='um', location='lower right', scale_loc='bottom', length_fraction=0.25)
axs[0, 1].add_artist(scalebar)
# Histogram of Inverted Image
axs[1, 1].hist(img_r.flatten(), bins=255)
axs[1, 1].set_title("Histogram of Inverted Image")
plt.tight_layout()
Histograms as Analytical Tools
Histograms are vital in bioimage processing and analysis. Common applications in biosciences include:
- Image Enhancement: Histogram equalization improves image contrast and brightness by redistributing pixel intensity values.
- Thresholding: Histograms assist in establishing thresholds for segmenting objects by analyzing pixel distributions.
Conclusion
Regularly reviewing histograms is a beneficial practice when working with new images, as it enhances data comprehension and aids in early detection of potential issues in image processing workflows.
References:
[2] I. Vangelatos et al., "Eisosome Organization in Aspergillus nidulans," Eukaryot. Cell, vol. 9, no. 10, pp. 1441–1454, 2010, doi: 10.1128/EC.00087–10.
[3] A. Athanasopoulos et al., "Characterization of AnNce102," Sci. Rep., vol. 5, no. 1, 2015, doi: 10.1038/srep15200.
[4] T. Ogama, "A beginner's guide to improving image acquisition," The Biochemist, vol. 42, pp. 22–27, 2020, doi: 10.1042/BIO20200075.
Interactive bioimage analysis with Python and Jupyter is the focus of this webinar, detailing practical applications and techniques in the field.
This video outlines the fundamental concepts of bioimage analysis using Python, providing foundational knowledge for practitioners.