Exercise: Disaster at the Microscope#

Duration ~45 min  ·  Session Day 2, Python notebooks

Operation Dataset Rescue#

Picture this: It is 1:00 AM on a Friday. Two exhausted researchers are finishing up a grueling, week-long microscope session. Halfway through a third cup of stale coffee, a catastrophic misclick happens. Instead of creating separate directories, they accidentally dump all of their analyzed images into one single, chaotic folder. Worse yet, the original images and biological samples are already gone, and their thesis deadline is in 48 hours. Sorting through thousands of files manually would take weeks. Desperate, caffeinated, and on the verge of tears, they knock on your door. They heard you are taking the Image Analysis course and possess the “data magic” required to fix this nightmare. You are handed a single folder containing a subset of 160 segmentation masks mixed together. Half of them are microscopic images of long, wriggly C. elegans worms. The other half are round, clustered Chinese Hamster Ovary (CHO) cells.

Can you untangle the worms from the cells and save their thesis?

Your Mission:

Don’t panic. Use your Python and image processing skills. Your job is to rescue the experiment by splitting the images into two groups using morphology alone.

The biological story gives you a useful visual clue: C. elegans in one condition tend to be curled, while worms in the other tend to be rod-like and straight. But the computer does not know what “curled” or “straight” means.

Your mission is to turn that visual idea into measurable morphological features, then use those features to separate the images.

The important skill is not memorising one feature. It is learning a workflow you can reuse on other image-analysis problems:

Data:

data/bbbc010_030/: 160 tif labeled images. We will use those labels here so that you can concentrate on the feature-extraction and classification ideas rather than segmentation errors.

import os
import glob
import shutil
import numpy as np
import pandas as pd
from PIL import Image
import tifffile
import matplotlib.pyplot as plt
import os; os.environ["DISPLAY"] = ":1"

from pathlib import Path
from skimage.measure import regionprops_table
from skimage.color import label2rgb
from iaf.plot import imshow, show_labels

import napari
import ipywidgets as widgets
from IPython.display import display

from course import DATA, show

ds = DATA / "bbbc010_030"
img_list = sorted((ds).glob("*.tif"))
print(len(img_list), "images", type(img_list))

Task 1: rescue the visual clue#

Before measuring anything, look at one image from each group and its object labels.

What makes the two groups look different?

  • Describe the difference in terms of shape, not brightness.

Hint

Display the first and second image in the folder and inspect the data.

# --- your turn ---
# ... plot the first two images ...

After inspecting the images, which two morphological features could capture “curled” versus “round”?

  • For each feature, predict which group should have the larger value.

(edit this cell to add your answer)

Task 2: turn shapes into numbers#

A labelled image is a collection of objects. regionprops_table lets us measure each object and turn the image into a table.

Build one table with one row per object. Keep the source image in a column so that you can trace back each object to its original image.

In terms of features, use morphological features only and not any fluorescent channel intensity.

Hint 1: useful measurements

Try area, perimeter, eccentricity, solidity, extent, axis_major_length, and axis_minor_length.

Hint 2: the loop

For every path in annotations: read the labels, call regionprops_table, convert the result to a DataFrame, add filename, and collect the tables. Finish with pd.concat.

SHAPE_FEATURES = ("area", "perimeter", "eccentricity", "solidity", "extent",
                  "axis_major_length", "axis_minor_length")

# --- your turn ---
# ... display the morphological features ...

A useful morphological idea: solidity#

solidity is the object area divided by the area of its convex hull.

Think about what happens when a worm curls: the convex hull spans the space inside the curl, so the worm occupies a smaller fraction of its hull. A more rod-like worm fills its hull more completely.

That is the kind of feature we want: a number with a geometric interpretation.

Task 3: can one morphological feature split the objects?#

For each candidate feature, find the best single threshold for separating the two groups.

This is deliberately a simple classifier: one feature, one cut-off. The goal is to learn how a morphological measurement can become a decision rule.

Hint

For every possible cut-off v, check both directions:

  • group A is above v

  • group A is at or below v

Use the fraction classified correctly in each group and keep the best result.

# --- your turn ---
# ... use otsu, plot histogram for each feature classification ...

After inspecting the histogram, which morphological feature gives the strongest split?

  • Look at the solidity distributions. Why can a good shape feature still fail to classify every individual object?

(edit this cell to add your answer)

Task 4: Split the data using each feature into subfolders#

Use the Otsu cut-off found for each morphological feature to classify individual masks as C. elegans or CHO, depending on whether the feature is expected to be high or low for C. elegans. Aggregate the mask-level predictions for each image and assign the whole image using majority vote (>50% C. elegans). Finally, copy each image into c_elegans or cho subfolders within a separate folder for each feature.

Hint

For each feature, use its Otsu cut-off and the appropriate direction (high or low) to classify each mask. Then use the majority of mask predictions to determine the class of the whole image.

# --- your turn ---
# ... count how many images per feature go into which folder ...

The feature classification likely gave different results per class and feature.

  • Which one is correct? How could you check this quickly?

Hint

You learned how to use napari to display images:

  • load all images you classified as C.elegans cells as one stack

  • load all images you classified as CHO cells as another stack

(edit this cell to add your answer)