phenotypic.measure.MeasureTexture#

class phenotypic.measure.MeasureTexture(scale: int | List[int] = 5, quant_lvl: Literal[8, 16, 32, 64] = 32, enhance: bool = False, warn: bool = False)[source]#

Bases: MeasureFeatures

Measure colony surface texture using Haralick features from gray-level co-occurrence matrices.

This class extracts second-order texture features (Haralick features) from colony grayscale images, quantifying surface roughness, regularity, and directional patterns. Features are computed at specified pixel offsets (scales) and across four directional angles (0°, 45°, 90°, 135°), then averaged.

Intuition: Colony texture reflects mycelial structure, growth patterns, and physiological state. Smooth, glabrous colonies have low texture contrast and entropy. Wrinkled, powdery, or sporulated colonies exhibit high contrast and energy. Radial growth patterns show angular correlation; random growth shows low correlation. Texture metrics capture morphological complexity beyond area and perimeter, enabling fine-grained phenotypic discrimination.

Use cases (agar plates): - Distinguish wild-type smooth colonies from rough/wrinkled mutants (e.g., Bacillus subtilis biofilm

morphologies, Pseudomonas aeruginosa rough variants).

  • Detect sporulation and powdery growth via high contrast and entropy.

  • Assess mycelial organization in fungi: organized radial hyphae (high correlation) vs diffuse cottony growth (low correlation).

  • Identify growth stress or nutrient depletion via texture changes within the same strain over time.

  • Enable multi-feature clustering combining size, shape, color, and texture for robust phenotyping.

Caveats: - Haralick features depend on image quantization level (quant_lvl); lower levels (8) reduce texture

nuance but are faster; higher levels (64) capture detail but are sensitive to noise.

  • Scale parameter affects the neighborhood size; small scales (1-2 px) capture fine texture (mycelial threads), large scales (5-10 px) capture coarse patterns (overall wrinkles). No single scale is universal; use multiple scales and average or compare within-plate.

  • Texture metrics are sensitive to uneven illumination and shadow; preprocess with illumination correction or histogram equalization if images show strong gradients.

  • Enhancement (rescale_intensity) improves texture detail but can inflate contrast in low-variance regions (e.g., uniform smooth colonies); use judiciously and validate with manual inspection.

  • Computation is slow for large colonies and high quantization levels; optimize scale and quant_lvl for your specific assay.

Attributes:
scale (list[int]): Distance parameter(s) for Haralick co-occurrence matrix, typically 1–10 pixels.

Larger values capture coarse texture; smaller values capture fine detail.

quant_lvl (Literal[8, 16, 32, 64]): Gray-level quantization (number of bins). Lower values

(8, 16) reduce dimensionality and computation time; higher values (32, 64) preserve texture nuance but increase noise sensitivity.

enhance (bool): Whether to rescale intensity within each colony to [0,1] before Haralick

computation. Improves contrast in low-variance regions but can bias comparisons. Defaults to False.

warn (bool): Whether to issue warnings if Haralick computation fails for specific objects.

Failures typically occur with very small colonies or empty regions. Defaults to False.

Returns:
pd.DataFrame: Object-level texture measurements with columns:
  • Label: Unique object identifier.

  • Texture measurements by scale and direction: AngularSecondMoment-deg000-scale##, Contrast-deg045-scale##, …, Correlation-avg-scale##, etc.

  • 13 Haralick features × 4 angles = 52 directional columns per scale.

  • Final 13 columns: averages across angles for each feature at the given scale.

References:

[1] https://mahotas.readthedocs.io/en/latest/api.html#mahotas.features.haralick [2] R. M. Haralick, K. Shanmugam, and I. Dinstein, “Textural Features for Image Classification,”

IEEE Transactions on Systems, Man, and Cybernetics, vol. SMC-3, no. 6, pp. 610–621, Nov. 1973, doi: 10.1109/TSMC.1973.4309314.

Examples:
Measure texture to distinguish morphotypes
from phenotypic import Image
from phenotypic.detect import OtsuDetector
from phenotypic.measure import MeasureTexture

# Load plate with smooth and wrinkled colonies
image = Image.from_image_path("morphotype_plate.jpg")
detector = OtsuDetector()
image = detector.operate(image)

# Measure texture at a single scale with default quantization
measurer = MeasureTexture(scale=3, quant_lvl=32, enhance=False)
texture = measurer.operate(image)

# High contrast and energy indicate wrinkled/rough morphology
wrinkled = texture[
    texture['TextureGray_Contrast-avg-scale03'] > texture['TextureGray_Contrast-avg-scale03'].quantile(0.75)
]
print(f"Wrinkled colonies: {len(wrinkled)}")
Multi-scale texture analysis for fine/coarse features
# Use multiple scales to capture fine and coarse texture
measurer = MeasureTexture(scale=[1, 3, 5], quant_lvl=32, enhance=True, warn=False)
texture = measurer.operate(image)

# Compare entropy across scales to assess texture organization
# Fine texture (scale 1): high entropy -> many small features
# Coarse texture (scale 5): low entropy -> organized large structures
for scale in [1, 3, 5]:
    col = f'TextureGray_Entropy-avg-scale0{scale}'
    if col in texture.columns:
        avg_entropy = texture[col].mean()
        print(f"Scale {scale}px: avg entropy = {avg_entropy:.2f}")
Category: TEXTURE#

Name

Description

AngularSecondMoment

Angular second moment (energy / uniformity). Measures the degree of local homogeneity

(Σ p(i,j)²). High values → uniform texture (e.g., smooth, yeast-like colonies with consistent mycelial density). Low values → heterogeneous surfaces (e.g., sectored, wrinkled, or mixed sporulation zones). Reflects colony surface regularity rather than brightness.

Contrast

Contrast (local intensity variation; Σ (i–j)² p(i,j)). High values indicate strong gray-level

differences (e.g., sharply defined rings, radial sectors, raised or folded regions). Low values indicate gradual tonal changes or uniformly pigmented colonies. Quantifies visual roughness and zonation amplitude.

Correlation

Linear gray-level correlation between neighboring pixels. Positive, high values suggest

structured spatial dependence (e.g., oriented radial hyphae or concentric patterns); near-zero values indicate uncorrelated, disordered growth (e.g., diffuse cottony mycelium). Sensitive to illumination gradients and directional GLCM computation.

HaralickVariance

GLCM variance (Σ (i–μ)² p(i,j)). Captures spread of co-occurring gray-level pairs, distinct

from raw intensity variance. High values → complex, multi-zone textures with variable hyphal/spore densities. Low values → consistent gray-level relationships and simpler colony surfaces.

InverseDifferenceMoment

Homogeneity (Σ p(i,j) / (1 + (i–j)²)). High values → smooth, locally uniform textures

(e.g., glabrous colonies, uniform aerial mycelium). Low values → abrupt gray-level changes (e.g., granular sporulation, wrinkled surfaces). Typically inversely correlated with Contrast.

SumAverage

Mean of gray-level sums (Σ k·p_{x+y}(k)). Reflects the average intensity combination of

neighboring pixels. In fungal colonies, can loosely parallel mean colony brightness when illumination and exposure are controlled, but remains a second-order rather than first-order intensity metric.

SumVariance

Variance of gray-level sum distribution. High values → heterogeneous brightness zones

(e.g., alternating dense/sparse or pigmented/non-pigmented regions). Low values → uniform tone across the colony. Often correlated with Contrast; use comparatively within one setup.

SumEntropy

Entropy of the gray-level sum distribution. High values → diverse brightness combinations

and irregular zonation. Low values → repetitive or periodic brightness patterns (e.g., evenly spaced rings). Indicates spatial unpredictability of summed intensities.

Entropy

Global GLCM entropy (–Σ p(i,j)·log p(i,j)). Measures total texture disorder and information

content. High values → complex, irregular colony surfaces (powdery, fuzzy, or sectored growth). Low values → simple, smooth, predictable patterns (glabrous or uniform colonies). Sensitive to gray-level quantization and image dynamic range.

DiffVariance

Variance of gray-level difference distribution. High values → mixture of smooth and textured

regions (e.g., smooth margins with wrinkled centers). Low values → consistent edge content. Highlights heterogeneity in edge magnitude across the colony.

DiffEntropy

Entropy of gray-level difference distribution. High values → irregular, unpredictable

intensity transitions (e.g., random sporulation or uneven mycelial networks). Low values → regular periodic transitions (e.g., concentric zonation). Reflects randomness of local contrast rather than its magnitude.

InfoCorrelation1

Information measure of correlation 1. Compares joint vs marginal entropies to quantify

mutual dependence between gray levels. Positive values → structured, predictable textures (e.g., organized radial growth); near-zero → independence between adjacent regions. Direction of sign varies with implementation.

InfoCorrelation2

Information measure of correlation 2 (√[1 – exp(–2 (H_xy2–H_xy))]). Always ≥ 0.

Values approaching 1 → strong spatial dependence and organized architecture (e.g., symmetric rings, radial structure). Values near 0 → random, independent patterns. Captures nonlinear organization missed by linear correlation.

Methods

__init__

Initializes an object with specific configurations for scale, quantization level, enhance, and warning behaviors.

measure

Execute the measurement operation on a detected-object image.

Parameters:
  • scale (int | List[int])

  • quant_lvl (Literal[8, 16, 32, 64])

  • enhance (bool)

  • warn (bool)

__init__(scale: int | List[int] = 5, quant_lvl: Literal[8, 16, 32, 64] = 32, enhance: bool = False, warn: bool = False)[source]#

Initializes an object with specific configurations for scale, quantization level, enhance, and warning behaviors. This constructor ensures that the ‘scale’ parameter is always stored as a list.

Parameters:
  • scale (int | List[int]) – A single integer or a list of integers representing the scale configuration. If a single integer is provided, it will be converted into a list containing that integer.

  • quant_lvl (Literal[8, 16, 32, 64]) – The quantization level. A higher level adds more computational complexity but captures more discrete texture changes. A higher value is not always more meaningful. Think of this like sensitivity to texture. Acceptable values are either 8, 16, 32, or 64.

  • enhance (bool) – A flag indicating whether to enhance the image before measuring texture. This can increase the amount of detail captured but can bias the measurements in cases where the relative variance between pixel intensities of an object is small.

  • warn (bool) – A flag indicating whether warnings should be issued.

__del__()#

Automatically stop tracemalloc when the object is deleted.

measure(image, include_meta=False)#

Execute the measurement operation on a detected-object image.

This is the main public API method for extracting measurements. It handles: input validation, parameter extraction via introspection, calling the subclass-specific _operate() method, optional metadata merging, and exception handling.

How it works (for users):

  1. Pass your processed Image (with detected objects) to measure()

  2. The method calls your subclass’s _operate() implementation

  3. Results are validated and returned as a pandas DataFrame

  4. If include_meta=True, image metadata (filename, grid info) is merged in

How it works (for developers):

When you subclass MeasureFeatures, you only implement _operate(). This measure() method automatically:

  • Extracts __init__ parameters from your instance (introspection)

  • Passes matched parameters to _operate() as keyword arguments

  • Validates the Image has detected objects (objmap)

  • Wraps exceptions in OperationFailedError with context

  • Merges grid/object metadata if requested

Parameters:
  • image (Image) – A PhenoTypic Image object with detected objects (must have non-empty objmap from a prior detection operation).

  • include_meta (bool, optional) – If True, merge image metadata columns (filename, grid position, etc.) into the results DataFrame. Defaults to False.

Returns:

Measurement results with structure:

  • First column: OBJECT.LABEL (integer IDs from image.objmap[:])

  • Remaining columns: Measurement values (float, int, or string)

  • One row per detected object

If include_meta=True, additional metadata columns are prepended before OBJECT.LABEL (e.g., Filename, GridRow, GridCol).

Return type:

pd.DataFrame

Raises:

OperationFailedError – If _operate() raises any exception, it is caught and re-raised as OperationFailedError with details including the original exception type, message, image name, and operation class. This provides consistent error handling across all measurers.

Notes

  • This method is the main entry point; do not override in subclasses

  • Subclasses implement _operate() only, not this method

  • Automatic memory profiling is available via logging configuration

  • Image must have detected objects (image.objmap should be non-empty)

Examples

Basic measurement extraction
from phenotypic import Image
from phenotypic.measure import MeasureSize
from phenotypic.detect import OtsuDetector

# Load and detect
image = Image.from_image_path('plate.jpg')
image = OtsuDetector().operate(image)

# Extract measurements
measurer = MeasureSize()
df = measurer.measure(image)
print(df.head())
Include metadata in measurements
# With image metadata (filename, grid info)
df_with_meta = measurer.measure(image, include_meta=True)
print(df_with_meta.columns)
# Output: ['Filename', 'GridRow', 'GridCol', 'OBJECT.LABEL',
#          'Area', 'IntegratedIntensity', ...]