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[Object regions] --> im("Object intensity measurements") ii[Intensity image] --> im im --> table["Objects table
oid | sum | mean | mean_bg
001 | 222 | 24 | 12
002 | 500 | 21 | 12 "] style table text-align:left ii --> bgm("Background measurement") bgm --> table


H2b-mCherry widefield image of two cells with common object and background intensity measurements, using manually drawn regions and/or a label mask image to delineate the objects.


Measure background corrected intensities

Repeat the activity using larger object regions

Due to the diffraction blur there is some subjectivity to how excatly to delineate the objects. Thus is is useful to compare how the measured values change when using larger regions.

Show activity for:  


  • Requirements
    • “Vanilla” Fiji or even only ImageJ without any plugins
  • Use File > Open to open the intensity image that is mentioned in the activity
  • Use Image > Properties to convert the calibration to pixel units (if necessary)
    • Pixel units are more convenient because then area = num_pixels and one can relate the sum and mean intensity via sum = mean * area
  • Use Analyse > Tools > ROI Manager to open the ROI manager
  • Use the ROI tools, e.g. the Polygon selection in the Fiji menu bar to delineate the two nuclei and also a background region
  • Use ROI Manager > Add to record each ROI
  • Use ROI Manger > Rename... to give them good names
  • Use ROI Manager > More > Save... to store the ROIs
    • This is important to document your work; the ROI file can be opened via drag&drop on Fiji
  • Use Analyse > Set Measurements to configure what to measure:
    • Area
    • Mean gray value
    • Min & max gray value
    • Display label (adds a column with the object name)
  • Use ROI Manager > More > Multi Measure to measure all ROIs at once
  • Click on the resulting table and save it via File > Save As...
  • Open the object table in a spreadsheet software
    • In Excel use File > Import to parse the CSV
  • Compute new columns for
    • sum intensity = mean * number of pixels
    • bg corr mean = mean intensity - bg mean
    • bg corr max = max intensity - bg mean
    • bg corr sum = sum intensity - bg mean * number of pixels
  • Discuss the biophysical interpretation of the results
  • There is some subjectivity in how to exactly draw the ROIs, thus repeat the activity, drawing the ROIs larger than before and compare the results

ImageJ GUI MorphoLibJ

  • 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 background label, 
# 1, 2 are the cells and 3 is the manually labeled background.

# %%
# Use the intensity_image option of regionprops 
# to measure the 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)

# %%
# print the background intensity value
background_label = 3
background = fluo_measures[fluo_measures.label==background_label].intensity_mean.values[0]

# %%
# Append the sum intensity and 
# 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

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

# %%
# Load the larger labels
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')

# %%
# Measure the object intensites
fluo_measures_dilated = pd.DataFrame(
        intensity_image = image,
        properties = ('label','area','intensity_mean','intensity_max')

# %%
# Append the background-corrected values to the table 
# with the dilated labels, 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

# %%
# Compare the results
# Observe:
# 1. mean intensity is affected by label size
# 2. max intensity is not affected by label size
# 3. bg-corrected sum intensity is hardly affected by label size
print("Small labels:")
print("\nLarge labels:")

# %%
# 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: