Object intensity measurements


Before starting this lesson, you should be familiar with:

Learning Objectives

After completing this lesson, learners should be able to:
  • Understand the correct biophysical interpretation of the most common object intensity measurements

  • Perform object intensity measurements, including background subtraction


The measurement of intensities in biological images is very common, e.g. to quantify expression levels of certain proteins by means of immuno-histochemistry. However, performing correct intensity measurements is very tricky and there are a lot of pitfalls. It is thus of utmost important to understand very well what one is doing. Without in-depth understanding the chance to publish wrong results based on intensity measurements is rather high.

Concept map

graph TD li[Label image] --> im("Object intensity measurements") ii[Intensity image] --> im im --> table["Results table"] ii --> bgm("Background measurement") bgm --> table table --> object_column["Columns are intensity features"] object_column -.- |"e.g."| ex["Mean, Sum, Max, ..., Background"] table --> object_row["Rows are objects"]


H2b-mCherry widefield image of two cells. Common object intensity measurements, using a label mask and a manual background measurement.


Measure intensities (with background subtraction)

Use the labels provided to measure objects intensities
Now try using larger labels (optional)

Show activity for:  

ImageJ GUI

  • Requirements
    • Update site: IJPB-Plugins (MorpholibJ)
  • Set binary options: [ Process > Binary > Options.. ]
    • iterations=1, count=1, black, do=Nothing
  • Open the images mentioned in the activity
    • Rename the intensity image: [ Image > Rename… ]: “intensity”
    • Rename the label image: [ Image > Rename… ]: “labels”
  • Measure object intensities: [ Plugins › MorphoLibJ › Analyze › Intensity Measurements 2D/3D ]
    • input=intensity
    • labels=labels
    • mean
    • max
    • numberofvoxels
  • Manually measure the background intensity
    • Change LUT to see the noise in the background: [ Ctrl/Cmd + C ]
    • Draw a ROI in the background
    • [ Analyze › Set Measurements… ]
      • Mean gray value
      • Median
    • [ Analyze › Measure ]
  • Open the object intensity measurements table in a spreadsheet software (e.g. Excel or R)
  • Add the manual background measurment as a new column
  • Add new columns for background corrected sum and mean intensity

skimage napari

# %% [markdown]
# ### Measure intensities (with background subtraction)

# %%
# Import python packages.
from OpenIJTIFF import open_ij_tiff, save_ij_tiff
from skimage.io import imsave
import numpy as np
from napari.viewer import Viewer
import pandas as pd
from skimage.measure import regionprops_table

# %%
# load image from url
fpath = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_16bit__h2b.tif"
image, axes_image, voxel_image, units_image = open_ij_tiff(fpath)
fpath = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit_labels__h2b.tif"
labels, axes_labels, voxel_labels, units_labels = open_ij_tiff(fpath)

# %%
# Create a napari_viewer and visualize image and labels
napari_viewer = Viewer()
napari_viewer.add_image(image, name='image')
napari_viewer.add_labels(labels, name='labels')

# %% [markdown]
# ## Compute the intensities 
# ### Background label  
# We can have an estimation of background intensity with the "0" label or create a specific background label.\
# **Napari GUI** Using the `layer controls` for the `labels` layer, manually create an additional label ("3" in this case) that measures the background.

# %%
objects_labels = np.unique(labels.flatten())

# %% [markdown]
# Observe that there are 4 values, 0 being the label of the background, 
# 1,2 are the cells and 3 is the manually labeled background.

# %%
# Use the intensity_image option to measure fluorescence intensity of objects
fluo_regionprops = regionprops_table(
        intensity_image = image,
        properties = ('label','area','intensity_mean','intensity_max')

# %%
# Wrap in a panda dataframe for better visualization nd export
fluo_measures = pd.DataFrame(fluo_regionprops)

# %%
# Compute background value
background = fluo_measures[fluo_measures.label==3].intensity_mean.values[0]

# %%
# Append the background-corrected values to the table
fluo_measures['intensity_sum'] = fluo_measures.intensity_mean * fluo_measures.area
fluo_measures['intensity_mean_corr'] = fluo_measures.intensity_mean - background
fluo_measures['intensity_max_corr'] = fluo_measures.intensity_max - background
fluo_measures['intensity_sum_corr'] = fluo_measures.intensity_mean_corr * fluo_measures.area

# %%
# Save as table

# %% [markdown]
# ### Larger labels for intensitiy measures  

# %%
# Load the data
fpath = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit_labels__h2b_dilate_labels.tif"
dilated_labels, axes_labels, voxel_labels, units_labels = open_ij_tiff(fpath)
objects_labels = np.unique(dilated_labels.flatten())

# %%
# Display the labels 
napari_viewer.add_labels(dilated_labels, name='dilated_labels')

# %%
# Use the intensity_image to compute the fluorescence parameters
fluo_measures_dilated = pd.DataFrame(
        intensity_image = image,
        properties = ('label','area','intensity_mean','intensity_max')

# %%
# Append the background-corrected values to the table using the same background
fluo_measures_dilated['intensity_sum'] = fluo_measures_dilated.intensity_mean * fluo_measures_dilated.area
fluo_measures_dilated['intensity_mean_corr'] = fluo_measures_dilated.intensity_mean - background
fluo_measures_dilated['intensity_max_corr'] = fluo_measures_dilated.intensity_max - background
fluo_measures_dilated['intensity_sum_corr'] = fluo_measures_dilated.intensity_mean_corr * fluo_measures_dilated.area
# Export the data

# %%

Difficult quantification

Show activity for:  

skimage napari

# %% [markdown]
# ### Difficult quantification
# %%
# Import python packages.
from OpenIJTIFF import open_ij_tiff, save_ij_tiff
from skimage.io import imsave
import numpy as np
from napari.viewer import Viewer
import pandas as pd
from skimage.measure import regionprops_table

# %%
# load image from url
fpath = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyc_16bit__embryo_transmission_fluorescence.tif"
image, axes_image, voxel_image, units_image = open_ij_tiff(fpath)

# Create a napari_viewer and visualize image and labels
napari_viewer1 = Viewer()
napari_viewer1.add_image(image[0], name='brightfield')
napari_viewer1.add_image(image[1], name='fluo', colormap='magenta', opacity=0.5)


Show exercise/solution for:

ImageJ GUI

  • Open the intensity image xy_8bit__nup.tif.
    • The image contains the signal of a single confocal slice of a nuclear pore protein (NUP) on the nuclear membrane.
  • Open the binary image xy_8bit_binary__nup.tif
  • Generate a label mask image from the binary image
  • Measure the both the mean and sum intensity of the NUP for each nucleus
    • Don’t forget to measure and take into account the image background
  • Think about the biophysical meaning of the mean and sum intensity.


Label Mean NumberOfVoxels BG Mean_corr Sum_corr
1 34.3762 2092 25 9.38 19622
2 31.9296 2343 25 6.93 16236
3 32.4747 1342 25 7.47 10024
  • Interpretation of the mean intensity: The label masks seem generally wider than the nuclear envelope, thus an interpreation of the mean intensity as the local NUP density on the membrane is problematic. However, if the width of the label masks is kept constant across the experiment the mean intensity could indeed be a number that is proportional to the NUP density.
  • Interpretation of the sum intensity: The sum intensity is very much affected by the size of the measured region. It could be that in this image the nuclei were optically sectioned at different z-positions, cutting a more or less big region out of the nucleus. The sum intensity seem thus not very useful here.
  • ImageJ GUI workflow
    • Required update sites
      • IJPB-Plugins (MorpholibJ)
    • open(“https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nup.tif”);
    • [ Image > Rename ] “intensity”
    • open(“httpR://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit_binary__nup.tif”);
    • [ Plugins › MorphoLibJ › Binary Images › Connected Components Labeling ]
      • connectivity = 4
      • type = [8 bits]
    • [ Image > Rename ] “labels”
    • [ Plugins > MorpholibJ > Analyze > Intensity Measurements 2D/3D ]
      • input = intensity
      • labels = labels
      • mean
      • numberofvoxels
    • Measure background intensity by drawing an ROI and [ Analyze > Measure ]
    • Measure the corrected mean and sum intensity using the formulas given in the main text of this module
  • Display the label image on top of the intensity image using an Overlay ([Image > Overlay > Add Image…]).
  • Based on this overlay, do you think the quantification of the signal of one of the nuclei may be problematic?


  • The label mask for label 3 also includes regions that are probably not part of the nuclear membrane and all intensity measurements may be affected by this.


Fill in the blanks (discuss with your neighbour)

Fill in the blanks, using these words: number of pixels, integrated, mean, decrease, increase, increase, sum, decrease

  1. Average intensity is just another word for ____ intensity.
  2. Sum intensity is sometimes also called ____ intensity.
  3. The ____ intensity is equal to the mean intensity times the ____ in the measured region.
  4. In an unsigned integer image, increasing the size of the measurement region can only _____ the sum intensity.
  5. In an unsigned integer image, decreasing the size of the measurement region can ____ or ____ the mean intensity.
  6. In a floating point image, increasing the size of the measurement region could ____ the sum intensity.


  1. mean
  2. integrated
  3. sum, number of pixels
  4. increase
  5. decrease, increase
  6. decrease, increase



  • median
  • mean = average
  • sum = total = integrated
  • bg = background


mean_corr = mean - bg
sum_corr = mean_corr * num_pixels = ( mean - bg ) * num_pixels = sum - ( bg * num_pixels )

Biophysical interpretation

  • mean often resembles the concentration of a protein
  • sum often represents the total expression level of a protein
  • For the correct biophysical interpretation you need to know the PSF of your microscope.
    • More specifically, you need to know how the 3D extend of the PSF relates to 3D extend of your biological structures of interest. Essentially, you need to exactly know where your microscope system is measuring the intensities.
    • It is thus critical whether you used a confocal or a widefield microscope, because widefield microscope have an unbounded PSF along the z-axis.

Key points

  • Intensity measurements are generally very tricky and most likely the source of many scientific mistakes.
    • Please consider consulting a bioimage analysis expert.
  • Intensity measurements need a background correction.
    • Finding the correct background value can be very difficult and sometimes even impossible and, maybe, the project just cannot be done like this!
  • At least, think carefully about whether the mean or sum intensity is the right readout for your biological question.
  • If you publish or present something, label your measurement properly, e.g. “Sum Intensity” (just “Intensity” is not enough)!

Follow-up material

Recommended follow-up modules:

Learn more: