.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples\08_extracting_information.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_08_extracting_information.py: ================================ Extracting Information (Masking) ================================ Arguably (because this is my personal opinion), the most common application of binary image is to extract information. Basic Concept ============= In this context, a binary image is often referred to as a *binary mask* because it is used to *mask* or filter specific regions of interest. This process is known as image masking. To demonstrate how this works, will use 8x8 grayscale and binary images. .. GENERATED FROM PYTHON SOURCE LINES 17-66 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt import matplotlib.patheffects as path_effects binary_image = np.array([[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]) grayscale_image = np.array([[0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.1, 0.2, 0.1, 0. , 0. ], [0. , 0. , 0.1, 0.3, 0.4, 0.2, 0.1, 0. ], [0. , 0.1, 0.3, 0.7, 0.8, 0.6, 0.2, 0.1], [0. , 0.2, 0.4, 0.8, 1. , 0.7, 0.3, 0.1], [0. , 0.1, 0.2, 0.6, 0.7, 0.4, 0.2, 0. ], [0. , 0. , 0.1, 0.2, 0.3, 0.2, 0. , 0. ], [0. , 0. , 0. , 0.1, 0.1, 0. , 0. , 0. ]]) # Function to display image with mask or pixel values def display_image(ax, img, title, mask=None, show_value=False): if mask is not None: masked_img = np.where(mask, img, np.nan) else: masked_img = img ax.imshow(masked_img, cmap='gray', vmin=img.min(), vmax=img.max()) ax.set_title(title) ax.axis("off") if show_value: for row in range(img.shape[0]): for col in range(img.shape[1]): if mask is None or mask[row, col]: text = ax.text(col, row, img[row, col], ha='center', va='center', fontsize=12, color='black', fontweight='bold') text.set_path_effects([path_effects.Stroke(linewidth=2, foreground='white'), path_effects.Normal()]) fig, axes = plt.subplots(1, 3, figsize=(12, 4)) display_image(axes[0], grayscale_image, "Grayscale Image", show_value=True) display_image(axes[1], binary_image, "Binary mask") display_image(axes[2], grayscale_image, "Masked Image", mask=binary_image, show_value=True) plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_08_extracting_information_001.png :alt: Grayscale Image, Binary mask, Masked Image :srcset: /auto_examples/images/sphx_glr_08_extracting_information_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 67-72 Essentially, we use a binary mask when we want to extract values only from the areas it defines. In python, using numpy this can simply be done by `boolean indexing `_. .. GENERATED FROM PYTHON SOURCE LINES 72-78 .. code-block:: Python # Extract the value by indexing masked_value = grayscale_image[binary_image.astype(bool)] print(masked_value) .. rst-class:: sphx-glr-script-out .. code-block:: none [0.1 0.2 0.1 0.3 0.4 0.2 0.1 0.3 0.7 0.8 0.6 0.2 0.2 0.4 0.8 1. 0.7 0.3 0.2 0.6 0.7 0.4 0.2 0.3] .. GENERATED FROM PYTHON SOURCE LINES 79-92 Practical example ================= To see this in action, we'll use use images of protein translocation described in `this paper `_ from our lab. The images were kindly provided by the corresponding author. Context and Objective --------------------- These fluorescence images capture the translocation of a protein of interest (POI) from the cytosol to the nucleus. The dataset consists of two channels: one for the POI and one for the nucleus. Let’s apply information extraction to visualize this process. .. GENERATED FROM PYTHON SOURCE LINES 92-102 .. code-block:: Python from tifffile import imread from skimage.filters import threshold_otsu POI_ch = imread("images/miRFP670nano_sample.tif") nucleus_ch = imread("images/mOrange2_sample.tif") print(POI_ch.shape, nucleus_ch.shape) # We have 71 frames of 150×185 images .. rst-class:: sphx-glr-script-out .. code-block:: none (71, 150, 185) (71, 150, 185) .. GENERATED FROM PYTHON SOURCE LINES 103-114 Extracting Fluorescence from Nucleus ------------------------------------ Let's say we want to know how much POI is located in the nucleus at each time point. First, we can locate the nucleus by generating a binary mask from the nucleus channel. Then, we extract the fluorescence intensity of the POI using this mask. To demonstrate this, we can use the images from the first frame. .. GENERATED FROM PYTHON SOURCE LINES 114-139 .. code-block:: Python # The first frame as an example nucleus_1 = nucleus_ch[0] POI_1 = POI_ch[0] # Thresholding to get the mask th = threshold_otsu(nucleus_1) nucleus_mask = nucleus_1 > th # Extract the fluorescence intensity from both channels POI_fl_1 = POI_1[nucleus_mask] nucleus_fl_1 = nucleus_1[nucleus_mask] fig, axes = plt.subplots(1, 4, figsize=(12, 3)) display_image(axes[0], nucleus_mask, "Nucleus Mask") display_image(axes[1], POI_1, "POI") display_image(axes[2], POI_1, "POI in nucleus", mask=nucleus_mask) display_image(axes[3], nucleus_1, "Nucleus fluorescence", mask=nucleus_mask) plt.tight_layout() plt.show() print(f"average fluorescence intensity of POI in nucleus: {POI_fl_1.mean()}") print(f"average fluorescence intensity of nucleus protein: {nucleus_fl_1.mean()}") .. image-sg:: /auto_examples/images/sphx_glr_08_extracting_information_002.png :alt: Nucleus Mask, POI, POI in nucleus, Nucleus fluorescence :srcset: /auto_examples/images/sphx_glr_08_extracting_information_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none average fluorescence intensity of POI in nucleus: 1032.8508311461067 average fluorescence intensity of nucleus protein: 258.5612423447069 .. GENERATED FROM PYTHON SOURCE LINES 140-146 Tracking Fluorescence Changes in Nucleus ---------------------------------------- Let's put it together into one function so we can apply the process (thresholding to get the mask -> extract fluorescence intensity) into all the frames. .. GENERATED FROM PYTHON SOURCE LINES 146-177 .. code-block:: Python def extract_fluorescence_intensity(image, mask_function): num_frames = image.shape[0] mean_intensity = [] for i in range(num_frames): mask = mask_function(image[i]) masked_values = image[i][mask] mean_intensity.append(masked_values.mean()) return mean_intensity # Function to get the mask by thresholding def nucleus_mask_function(frame): return frame > threshold_otsu(frame) # Apply function to all frames POI_nucleus_intensities = extract_fluorescence_intensity(POI_ch, nucleus_mask_function) nucleus_intensities = extract_fluorescence_intensity(nucleus_ch, nucleus_mask_function) # Plotting the mean fluorescence intensity over time fig, ax = plt.subplots(figsize=(6, 4)) ax.plot(POI_nucleus_intensities, label="POI in Nucleus", marker='o', c='red', mec='k') ax.plot(nucleus_intensities, label="Nucleus Fluorescence", marker='o', c='gray', mec='k') ax.set_xlabel("Frame") ax.set_ylabel("Mean Fl. Intensity") ax.set_title("POI in nucleus over time") ax.legend() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_08_extracting_information_003.png :alt: POI in nucleus over time :srcset: /auto_examples/images/sphx_glr_08_extracting_information_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 178-189 Creating Cytosol Mask --------------------- Okay, so now we can see the translocation of POI to and from nucleus. But how do we know that it's from cytosol? Well, we can get the mean fluorescence intensity from the cytosol and see the correlation. But we don't have a cytosol channel. One creative way to do that is by expanding the nucleus mask. Because we know that the cytosol surrounds the nucleus. .. GENERATED FROM PYTHON SOURCE LINES 189-207 .. code-block:: Python from skimage.morphology import binary_dilation, disk # Expand nucleus mask to define a surrounding region nucleus_dilate_1 = binary_dilation(nucleus_mask, disk(3)) nucleus_dilate_2 = binary_dilation(nucleus_mask, disk(5)) # Define cytosol region as the ring between two dilations cytosol_mask = nucleus_dilate_2 ^ nucleus_dilate_1 # Subtract (nucleus_dilate_2 - nucleus_dilate_1) also works in this case fig, axes = plt.subplots(1, 4, figsize=(12, 3)) display_image(axes[0], nucleus_mask, "Nucleus Mask") display_image(axes[1], nucleus_dilate_1, "Dilation 1 (A)") display_image(axes[2], nucleus_dilate_2, "Dilation 2 (B)") display_image(axes[3], cytosol_mask, "Around Nucleus (A ^ B)") plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_08_extracting_information_004.png :alt: Nucleus Mask, Dilation 1 (A), Dilation 2 (B), Around Nucleus (A ^ B) :srcset: /auto_examples/images/sphx_glr_08_extracting_information_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 208-213 Neat, huh?! This is actually an approach I followed from `this paper `_. Now, let's see if this can be used in our case .. GENERATED FROM PYTHON SOURCE LINES 213-221 .. code-block:: Python fig, axes = plt.subplots(1, 3, figsize=(12, 4)) display_image(axes[0], POI_1, "POI") display_image(axes[1], POI_1, "POI in nucleus", mask=nucleus_mask) display_image(axes[2], POI_1, "POI around nucleus", mask=cytosol_mask) plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_08_extracting_information_005.png :alt: POI, POI in nucleus, POI around nucleus :srcset: /auto_examples/images/sphx_glr_08_extracting_information_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 222-230 The cytosol(ish) mask also includes a little area outside of the cell, but overall, it looks pretty good! Comparing Nucleus and Cytosol Fluorescence ------------------------------------------ Let's apply this to all frames and compare it to the fluorescence intensity in the nucleus. .. GENERATED FROM PYTHON SOURCE LINES 230-260 .. code-block:: Python # Function to generate cytosol mask def cytosol_mask_function(frame): nucleus_mask = nucleus_mask_function(frame) nucleus_dilate_1 = binary_dilation(nucleus_mask, disk(3)) nucleus_dilate_2 = binary_dilation(nucleus_mask, disk(5)) return nucleus_dilate_2 ^ nucleus_dilate_1 # Cytosol mask # Apply function to all frames POI_cytosol_intensities = extract_fluorescence_intensity(POI_ch, cytosol_mask_function) cytosol_intensities = extract_fluorescence_intensity(nucleus_ch, cytosol_mask_function) # Plotting the mean fluorescence intensity of POI in nucleus and cytosol over time fig, ax1 = plt.subplots(figsize=(6,4)) ax1.plot(POI_nucleus_intensities, label="POI in Nucleus", marker='o', c='red', mec='k') ax1.set_xlabel("Frame") ax1.set_ylabel("Mean Fl. Intensity (Nucleus)") ax1.tick_params(axis='y', labelcolor='red') ax2 = ax1.twinx() ax2.plot(POI_cytosol_intensities, label="POI in Cytosol", marker='o', c='blue', mec='k') ax2.set_ylabel("Mean Fl. Intensity (Cytosol)") ax2.tick_params(axis='y', labelcolor='blue') fig.legend(bbox_to_anchor=(1, 1), bbox_transform=ax1.transAxes) ax1.set_title("POI Fl. Intensity Over Time") plt.show() .. image-sg:: /auto_examples/images/sphx_glr_08_extracting_information_006.png :alt: POI Fl. Intensity Over Time :srcset: /auto_examples/images/sphx_glr_08_extracting_information_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 261-272 We can clearly see that as the intensity of POI in the nucleus increases, the intensity in the cytosol decreases. Likewise, when the POI intensity in the nucleus decreases, it increases in the cytosol. This indicates that POI translocates between the nucleus and cytosol. .. note:: In the paper, the authors calculated the correlation between the two channels (Pearson's correlation coefficient) to quantify the translocation, instead of calculating the fluorescence intensity. Why do you think that is? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.312 seconds) .. _sphx_glr_download_auto_examples_08_extracting_information.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 08_extracting_information.ipynb <08_extracting_information.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 08_extracting_information.py <08_extracting_information.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 08_extracting_information.zip <08_extracting_information.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_