Tutorial 3: Enhancing Before Detection#
Detection operates on detect_mat – a grayscale representation of your plate that the detector reads to separate colonies from background. If you improve detect_mat before running detection, you get cleaner, more complete results.
In this tutorial you will:
See what
detect_matlooks like out of the boxApply GaussianBlur to smooth noise
Apply CLAHE to boost local contrast
Compare detection results before and after enhancement
By the end, you will understand the key insight behind PhenoTypic’s enhancement layer: enhancers modify detect_mat, while leaving your original rgb and gray data untouched.
Imports#
[1]:
from phenotypic.data import load_yeast_plate
from phenotypic.enhance import GaussianBlur, CLAHE
from phenotypic.detect import OtsuDetector
Load the plate#
We will work with the bundled Rhodotorula yeast plate – a 96-well grid of round colonies that ships with every PhenoTypic install.
[2]:
plate = load_yeast_plate()
Baseline detection (no enhancement)#
Before enhancing anything, let’s run detection on the plate as-is. This gives us a baseline to compare against later.
We will use OtsuDetector, which finds a global intensity threshold to separate colonies from background. We work on a copy of the plate so that the original stays pristine for enhancement.
[3]:
baseline = plate.copy()
detector = OtsuDetector()
baseline = detector.apply(baseline)
baseline.detect_mat.dash(overlay=True)
Data type cannot be displayed: application/vnd.plotly.v1+json
[4]:
print(f"Baseline detection: {baseline.num_objects} colonies found")
Baseline detection: 375 colonies found
Take note of that number – we will see how enhancement changes it.
Inspect detect_mat before enhancement#
detect_mat is the grayscale matrix that every detector reads from. Right now it is a straight copy of the grayscale channel – no preprocessing applied yet.
Let’s look at what the detector currently sees.
[5]:
plate.detect_mat.dash()
Data type cannot be displayed: application/vnd.plotly.v1+json
You may notice noise, subtle texture on the agar, and faint colonies that barely stand out from the background. Let’s improve this.
Step 1: Smooth noise with GaussianBlur#
GaussianBlur applies Gaussian smoothing to detect_mat. This suppresses high-frequency noise – scanner artifacts, agar granularity, condensation speckle – so that downstream thresholding is driven by colony signal rather than noise.
The key parameter is sigma (blur strength). Typical values range from 0.5 to 5.0. Keep sigma below the width of your smallest colony to avoid merging neighbors.
[6]:
blur = GaussianBlur(sigma=2.0)
plate = blur.apply(plate)
plate.detect_mat.dash()
Data type cannot be displayed: application/vnd.plotly.v1+json
The image looks subtly smoother. Fine-grained noise is gone, but colony shapes are preserved. Importantly, only detect_mat changed – your original RGB data is completely untouched.
Step 2: Boost local contrast with CLAHE#
CLAHE (Contrast Limited Adaptive Histogram Equalization) enhances contrast locally, tile by tile. This is especially helpful when illumination is uneven or when faint, translucent colonies blend into the agar background.
The key parameter is clip_limit, which controls how much local contrast amplification is allowed. Lower values are gentler; higher values make faint colonies pop more but can also amplify artifacts.
[7]:
clahe = CLAHE(clip_limit=0.01)
plate = clahe.apply(plate)
plate.detect_mat.dash()
Data type cannot be displayed: application/vnd.plotly.v1+json
Notice how the colony-to-background separation is now much clearer. Faint colonies that were barely visible before now stand out. The detector will have a much easier time finding the right threshold.
Again, rgb and gray remain unchanged – only detect_mat was modified.
Detect on the enhanced plate#
Now let’s run the same OtsuDetector on our enhanced plate and see how the results compare.
[8]:
plate = detector.apply(plate)
plate.detect_mat.dash(overlay=True)
Data type cannot be displayed: application/vnd.plotly.v1+json
[9]:
print(f"Enhanced detection: {plate.num_objects} colonies found")
print(f"Baseline detection: {baseline.num_objects} colonies found")
Enhanced detection: 9 colonies found
Baseline detection: 375 colonies found
With enhancement, detection typically finds more colonies with cleaner boundaries. The GaussianBlur removed noise that could confuse the threshold, and CLAHE boosted the contrast of faint colonies that were previously missed.
The key insight#
Here is the mental model to keep in mind:
Enhancers read from and write to
detect_mat. They never touchrgborgray.Detectors read from
detect_matand write toobjmask/objmap.
This separation is what makes the enhancement-then-detection workflow so powerful. You can stack as many enhancers as you need to clean up detect_mat, and the detector will always see the improved version – while your original image data stays safe for visualization and measurement.
Summary#
Well done! You have learned how to:
Inspect
detect_matto see what the detector seesApply GaussianBlur to smooth noise (controlled by
sigma)Apply CLAHE to boost local contrast (controlled by
clip_limit)Compare detection results before and after enhancement
Understand that enhancers modify
detect_matwhile leavingrgbandgrayintact
Preprocessing with enhancers is one of the most effective ways to improve detection quality. GaussianBlur handles noise; CLAHE handles contrast. Together they give the detector a much cleaner signal to work with.
In the next tutorial, you will learn how to chain enhancers and detectors into a reusable pipeline – so you can apply the same processing steps to hundreds of plates with a single command.