API Reference
This section provides detailed documentation for all Twocan classes and functions.
Core Classes
|
A scikit-learn compatible estimator for multimodal image registration. |
Preprocessors
|
Preprocessing pipeline for Immunofluorescence (IF) images. |
|
Preprocessing pipeline for Imaging Mass Cytometry (IMC) images. |
Optimization Functions
|
Objective function that optimizes for IoU (Intersection over Union). |
|
Multi-objective function that optimizes for both correlation and IoU. |
|
Callbacks
|
Callback to save optimization trials to a CSV file during study execution. |
|
Callback to stop optimization when a target metric threshold is reached. |
Callback to monitor transformation matrix convergence during optimization. |
Utilities
|
Convert an image to 8-bit grayscale by stretching its range to [0, 255]. |
Parse a string representation of an affine transformation matrix. |
|
|
Calculate correlation coefficients between all pairs of channels from two images. |
|
Apply a transformation to align two spatial elements in a new coordinate system. |
|
Create a SpatialData object from IF and IMC arrays with their channel panels. |
|
Calculate triangle score and return best trial from optimization results. |
Plotting
|
Plot a cartoon representation of an affine transformation. |
|
Merge two images into a color-coded overlay. |
Complete API
Twocan: Bayesian optimization for multimodal registration of spatial proteomics.
Twocan is a Python package that uses Bayesian optimization (via Optuna) to automatically find optimal parameters for registering images from spatial proteomics technologies such as IF (Immunofluorescence), IMC (Imaging Mass Cytometry), FISH, IMS, etc.
The package provides: - Automated parameter optimization for preprocessing and registration - Modality-specific preprocessing functions - Quality metrics for registration assessment - Visualization tools for registration results - Extensible design for custom objectives and preprocessors
- class twocan.IFProcessor(binarize=True, binarization_threshold=0.1, sigma=1)[source]
Bases:
objectPreprocessing pipeline for Immunofluorescence (IF) images.
This class provides a standardized preprocessing pipeline for IF images including channel summation, normalization, Gaussian blurring, and optional binarization. The processor can be configured with trial parameters from Optuna optimization.
- Parameters:
- configure(trial_params)[source]
Configure processor parameters from Optuna trial parameters.
This method updates the processor parameters based on values suggested by an Optuna trial. It looks for specific parameter names in the trial params dictionary and updates the corresponding attributes.
- Parameters:
trial_params (dict) – Dictionary of trial parameters from Optuna optimization. Expected keys: ‘IF_binarization_threshold’, ‘IF_gaussian_sigma’, ‘binarize_images’.
- Returns:
self – Returns self for method chaining.
- Return type:
- class twocan.IMCProcessor(arcsinh_normalize=True, arcsinh_cofactor=5, winsorize_limits=[None, None], binarize=True, binarization_threshold=2, sigma=1)[source]
Bases:
objectPreprocessing pipeline for Imaging Mass Cytometry (IMC) images.
This class provides a comprehensive preprocessing pipeline specifically designed for IMC images, including arcsinh transformation for variance stabilization, winsorization for outlier handling, normalization, Gaussian blurring, and optional binarization.
- Parameters:
arcsinh_normalize (bool, default=True) – Whether to apply arcsinh transformation for variance stabilization.
arcsinh_cofactor (float, default=5) – Cofactor for arcsinh transformation. Lower values increase the transformation strength.
winsorize_limits (list of float, default=[None, None]) – Lower and upper percentile limits for winsorization. [0.01, 0.01] means clip bottom 1% and top 1% of values.
binarize (bool, default=True) – Whether to apply binarization after preprocessing.
binarization_threshold (float, default=2) – Threshold value for binarization.
sigma (float, default=1) – Standard deviation for Gaussian blur kernel.
Notes
The arcsinh transformation is particularly useful for IMC data because it stabilizes variance across the intensity range, which is important for count-based mass spectrometry data.
- configure(trial_params)[source]
Configure processor parameters from Optuna trial parameters.
This method updates the processor parameters based on values suggested by an Optuna trial. It looks for specific IMC parameter names in the trial params dictionary.
- Parameters:
trial_params (dict) – Dictionary of trial parameters from Optuna optimization. Expected keys: ‘IMC_arcsinh_normalize’, ‘IMC_arcsinh_cofactor’, ‘IMC_winsorization_lower_limit’, ‘IMC_winsorization_upper_limit’, ‘IMC_binarization_threshold’, ‘IMC_gaussian_sigma’, ‘binarize_images’.
- Returns:
self – Returns self for method chaining.
- Return type:
- class twocan.MatrixConvergenceCallback(window_size: int = 10, tolerance: float = 0.01, min_trials: int = 20)[source]
Bases:
objectCallback to monitor transformation matrix convergence during optimization.
This callback tracks the transformation matrices from recent trials and stops optimization when they converge (have low variance), indicating that the registration has stabilized. Useful for detecting when further optimization is unlikely to improve results.
- Parameters:
window_size (int, default=10) – Number of recent trials to consider for convergence assessment.
tolerance (float, default=0.01) – Maximum allowed variance in matrix elements for convergence. Lower values require tighter convergence.
min_trials (int, default=20) – Minimum number of trials before convergence checking begins.
- matrices
List storing recent transformation matrices.
- Type:
List[np.ndarray]
- class twocan.RegEstimator(registration_max_features: int = 10000, registration_percentile: float = 0.9)[source]
Bases:
TransformerMixin,BaseEstimator,ABCA scikit-learn compatible estimator for multimodal image registration.
This class implements feature-based image registration using OpenCV’s ORB (Oriented FAST and Rotated BRIEF) detector and a partial affine transformation model. It follows scikit-learn’s estimator API with fit, transform, and fit_transform methods, making it easy to integrate into machine learning pipelines.
The registration process consists of: 1. Feature detection using ORB on both images 2. Feature matching using brute-force Hamming distance 3. Affine transformation estimation using RANSAC 4. Image transformation using the estimated parameters
- Parameters:
registration_max_features (int, default=10000) – Maximum number of features to detect in each image using ORB. Higher values can improve registration accuracy but increase computation time.
registration_percentile (float, default=0.9) – Percentile of features to keep after sorting by match quality (0-1). Only the top percentile of matches by distance are used for transformation estimation, which helps remove outliers.
- M_
The estimated 2x3 affine transformation matrix after fitting. Shape is (2, 3) representing the transformation [R|t] where R is rotation/scaling and t is translation.
- Type:
np.ndarray
- y_shape_
Shape (height, width) of the target image used during fitting. Used as the default output shape for transformations.
Notes
The estimator automatically converts input images to 8-bit grayscale for feature detection using the stretch_255 utility function. This ensures consistent feature detection regardless of input image dynamic range.
The partial affine transformation model allows rotation, scaling, and translation but not shearing, which is appropriate for most microscopy registration tasks where imaging geometry is approximately preserved.
For best results: - Ensure sufficient overlap between images - Use images with distinct features (not uniform regions) - Consider preprocessing to enhance relevant structures - Adjust max_features based on image complexity and computational budget
- fit(X: ndarray, y: ndarray) RegEstimator[source]
Estimate the affine transformation matrix between source (X) and target (y) images.
This method detects features in both images using ORB, matches them, and estimates the best affine transformation that maps source features to target features using OpenCV’s robust estimation.
- Parameters:
X (np.ndarray) – Source image to be registered. Shape can be (H, W) for single-channel or (C, H, W) for multi-channel. If multi-channel, all channels are summed for feature detection.
y (np.ndarray) – Target (reference) image to register to. Shape can be (H, W) for single-channel or (C, H, W) for multi-channel. If multi-channel, all channels are summed for feature detection.
- Returns:
self – The fitted estimator with estimated transformation matrix in
self.M_.- Return type:
- Raises:
cv2.error – If affine transformation cannot be estimated, typically due to insufficient or poorly matched features.
Notes
The fitting process: 1. Convert images to 8-bit for ORB compatibility 2. Detect up to max_features keypoints in each image 3. Compute ORB descriptors for each keypoint 4. Match descriptors using brute-force Hamming distance 5. Keep top percentile of matches by distance 6. Estimate partial affine transformation using RANSAC
The method uses OpenCV’s estimateAffinePartial2D which finds the optimal similarity transformation (rotation, scaling, translation) rather than a full affine transformation. This is more robust for most registration scenarios.
- fit_transform(X: ndarray, y: ndarray) ndarray[source]
Fit to data, then transform it.
This convenience method combines fitting and transformation in a single call. It’s equivalent to calling fit(X, y).transform(X, y) but slightly more efficient.
- Parameters:
X (np.ndarray) – Source image to fit the transformation to and then transform.
y (np.ndarray) – Target image to fit the transformation against. This image will also be included in the output stack.
- Returns:
Stacked array containing the transformed X channels followed by the original y channels. Shape is (C_x + C_y, H_y, W_y) where C_x, C_y are the channel counts and H_y, W_y are target dimensions.
- Return type:
np.ndarray
- score(source: ndarray, target: ndarray) Dict[str, float][source]
Calculate registration quality metrics between source and target images.
This method computes various metrics to assess the quality of registration between binary or continuous-valued images. Metrics are calculated only in regions where both images have valid data after transformation.
- Parameters:
source (np.ndarray) – Source image, shape (H, W). Should be the same image used for fitting or a similar image from the same modality.
target (np.ndarray) – Target image, shape (H, W). Should be the same image used for fitting or a similar image from the same modality.
- Returns:
Dictionary containing registration quality metrics:
- ’and’float
Count of pixels where both source and target are positive (logical AND operation). Higher values indicate better overlap.
- ’or’float
Count of pixels where either source or target is positive (logical OR operation).
- ’xor’float
Count of pixels where source and target disagree (logical XOR operation). Lower values indicate better agreement.
- ’iou’float
Intersection over Union ratio (and/or). Values range from 0-1 with 1 indicating perfect overlap. Returns 0.0 if no positive pixels exist.
- ’source_sum’float
Sum of all source pixel intensities in the overlap region.
- ’target_sum’float
Sum of all target pixel intensities in the overlap region.
- Return type:
Notes
Metrics are computed only in the intersection region where both images have valid data after transformation. This ensures fair comparison and avoids edge effects from the transformation.
For binary images, the metrics have intuitive interpretations: - IoU is the standard Jaccard index - ‘and’ counts overlapping positive pixels - ‘xor’ counts disagreement pixels
For continuous images, the logical operations are applied after implicit conversion to boolean (non-zero values are True).
- set_score_request(*, source: bool | None | str = '$UNCHANGED$', target: bool | None | str = '$UNCHANGED$') RegEstimator
Request metadata passed to the
scoremethod.Note that this method is only relevant if
enable_metadata_routing=True(seesklearn.set_config()). Please see User Guide on how the routing mechanism works.The options for each parameter are:
True: metadata is requested, and passed toscoreif provided. The request is ignored if metadata is not provided.False: metadata is not requested and the meta-estimator will not pass it toscore.None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.str: metadata should be passed to the meta-estimator with this given alias instead of the original name.
The default (
sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.Added in version 1.3.
Note
This method is only relevant if this estimator is used as a sub-estimator of a meta-estimator, e.g. used inside a
Pipeline. Otherwise it has no effect.- Parameters:
- Returns:
self – The updated object.
- Return type:
- transform(X: ndarray, y: ndarray | None = None) ndarray[source]
Apply the estimated transformation to the source image(s).
This method transforms the source image(s) using the affine transformation estimated during fitting. Optionally, a target image can be provided which will be stacked with the transformed source without transformation.
- Parameters:
X (np.ndarray) – Source image(s) to transform. Shape can be (H, W) for single-channel or (C, H, W) for multi-channel. All channels are transformed using the same transformation matrix.
y (Optional[np.ndarray], default=None) – Target image to stack with transformed source. If provided, this image is NOT transformed but is included in the output for direct comparison. Shape should be (H, W) or (C, H, W).
- Returns:
Transformed image(s). If y is None, returns transformed X with shape (C, H_out, W_out) where H_out, W_out match the target image from fitting. If y is provided, returns stacked array with transformed X channels followed by untransformed y channels.
- Return type:
np.ndarray
- Raises:
NotFittedError – If transform is called before fitting the estimator.
AssertionError – If the stored transformation matrix has invalid shape.
Notes
The transformation uses scikit-image’s warp function with the inverse transformation matrix. This ensures proper interpolation and handles edge cases automatically.
Output image dimensions match the target image used during fitting unless a different y image is provided during transformation.
- class twocan.SaveTrialsDFCallback(filepath: str, save_frequency: int = 1)[source]
Bases:
objectCallback to save optimization trials to a CSV file during study execution.
This callback writes trial results to a CSV file after each trial completion, allowing for real-time monitoring and persistent storage of optimization progress. Useful for long-running optimizations or when resuming studies.
- Parameters:
- class twocan.ThresholdReachedCallback(threshold: float, metric_name: str = 'iou', direction: str = 'maximize')[source]
Bases:
objectCallback to stop optimization when a target metric threshold is reached.
This callback monitors a specified metric during optimization and raises optuna.TrialPruned to stop the study when the threshold is reached. Useful for stopping optimization early when satisfactory results are achieved.
- Parameters:
threshold (float) – Target threshold value for the monitored metric.
metric_name (str, default='iou') – Name of the metric to monitor in trial.user_attrs. Must be a key present in the user attributes of trials.
direction (str, default='maximize') – Whether to stop when metric goes ‘above’ (‘maximize’) or ‘below’ (‘minimize’) the threshold.
- twocan.iou_corr_multi_objective(trial, images, registration_channels, moving_image='IMC', static_image='IF', moving_preprocesser=<twocan.utils.IMCProcessor object>, static_preprocesser=<twocan.utils.IFProcessor object>)[source]
Multi-objective function that optimizes for both correlation and IoU.
- twocan.iou_corr_single_objective(trial, images, registration_channels, moving_image='IMC', static_image='IF', moving_preprocesser=<twocan.utils.IMCProcessor object>, static_preprocesser=<twocan.utils.IFProcessor object>)[source]
Objective function that optimizes for IoU (Intersection over Union).
- twocan.multi_channel_corr(source: ndarray, target: ndarray) ndarray[source]
Calculate correlation coefficients between all pairs of channels from two images.
This function computes the Pearson correlation coefficient between every channel in the source image and every channel in the target image. The images are first normalized (z-scored) channel-wise before correlation calculation.
- Parameters:
source (np.ndarray) – Source image array of shape (n_channels_1, n_pixels). Each row represents a flattened channel.
target (np.ndarray) – Target image array of shape (n_channels_2, n_pixels). Each row represents a flattened channel.
- Returns:
Correlation matrix of shape (n_channels_1, n_channels_2). Element (i, j) contains the correlation between source channel i and target channel j.
- Return type:
np.ndarray
Notes
The function assumes the input arrays have the same number of pixels (same second dimension). Channels are normalized to have zero mean and unit standard deviation before correlation calculation.
- twocan.pick_best_registration(study_df)[source]
Calculate triangle score and return best trial from optimization results.
This function implements a balanced scoring approach for selecting the best registration trial from a set of optimization results. It combines three key metrics (logical AND, IoU, and correlation) using a triangular scoring scheme that balances all three aspects of registration quality.
The triangle score is calculated as:
(1/3) * |norm_and * norm_corr + norm_corr * norm_iou + norm_iou * norm_and|
where each metric is normalized to [0,1] within the group.
- Parameters:
study_df (pd.DataFrame) – DataFrame containing trial results with required columns: - ‘user_attrs_logical_and’: Logical AND overlap between images - ‘user_attrs_logical_iou’: Intersection over Union score - ‘user_attrs_reg_image_max_corr’: Maximum correlation between channels
- Returns:
DataFrame row containing the trial with the highest balanced score. The returned series includes all original columns plus computed normalization columns and the final ‘balanced_score’.
- Return type:
pd.Series
Notes
The logical AND values are log-transformed before normalization because they typically span several orders of magnitude. The triangle score approach ensures that no single metric dominates the selection, leading to more robust registration quality assessment.
Missing or NaN values in any of the required columns will result in NaN normalized scores, which may affect the final ranking.
- twocan.plot_cartoon_affine(w1: float, h1: float, M: ndarray, w2: float, h2: float, ax: Axes | None = None, show_source: bool = False, source_color: str = 'green', target_color: str = 'purple') Tuple[Axes, List[Line2D]][source]
Plot a cartoon representation of an affine transformation.
Visualizes how a rectangle is transformed by an affine matrix, useful for understanding registration transformations.
- Parameters:
w1 (float) – Width and height of source rectangle.
h1 (float) – Width and height of source rectangle.
M (np.ndarray) – 2x3 affine transformation matrix.
w2 (float) – Width and height of target rectangle.
h2 (float) – Width and height of target rectangle.
ax (Optional[Axes], default=None) – Matplotlib axes for plotting. If None, current axes will be used.
show_source (bool, default=False) – Whether to show the original source rectangle.
source_color (str, default='green') – Color for source rectangle and its transformation.
target_color (str, default='purple') – Color for target rectangle.
- Returns:
The matplotlib axes object and list of plotted lines.
- Return type:
Tuple[Axes, List[Line2D]]
- twocan.prep_zarr(IF_arr: ndarray, IMC_arr: ndarray, IF_panel: List[str], IMC_panel: List[str]) SpatialData[source]
Create a SpatialData object from IF and IMC arrays with their channel panels.
This function takes raw image arrays and their corresponding channel names to create a properly formatted SpatialData object containing both modalities. The function handles both 2D and 3D input arrays, automatically adding a channel dimension if needed.
- Parameters:
IF_arr (np.ndarray) – Immunofluorescence array of shape (H, W) or (C, H, W). If 2D, will be expanded to (1, H, W).
IMC_arr (np.ndarray) – Imaging mass cytometry array of shape (H, W) or (C, H, W). If 2D, will be expanded to (1, H, W).
IF_panel (List[str]) – List of channel names for IF data. Must match the number of channels in IF_arr.
IMC_panel (List[str]) – List of channel names for IMC data. Must match the number of channels in IMC_arr.
- Returns:
SpatialData object containing both modalities with proper channel information and coordinate systems.
- Return type:
sd.SpatialData