Coverage for ezstitcher/core/pipeline_factories.py: 100%
22 statements
« prev ^ index » next coverage.py v7.3.2, created at 2025-04-30 13:20 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2025-04-30 13:20 +0000
1"""
2Pipeline factory system for the EZStitcher pipeline architecture.
4This module contains the AutoPipelineFactory class that creates pre-configured pipelines
5for all common workflows, leveraging specialized steps to reduce boilerplate code.
7The AutoPipelineFactory uses a unified approach that handles 2D multichannel, z-stack per plane stitch,
8and z-stack projection stitch with a single implementation, simplifying the pipeline architecture.
9"""
11from typing import List, Optional, Union, Dict, Any
12from pathlib import Path
14from .pipeline import Pipeline
15from .steps import Step, PositionGenerationStep, ImageStitchingStep, ZFlatStep, FocusStep, CompositeStep, NormStep
16from .image_processor import ImageProcessor as IP
19class AutoPipelineFactory:
20 """
21 Unified factory for creating pipelines for all common use cases.
23 This factory handles all types of stitching workflows with a single implementation:
24 - 2D multichannel stitching
25 - Z-stack per plane stitching
26 - Z-stack projection stitching
28 It automatically configures the appropriate steps based on the input parameters,
29 with no need to differentiate between different types of pipelines.
30 """
32 def __init__(
33 self,
34 input_dir: Union[str, Path],
35 output_dir: Optional[Union[str, Path]] = None,
36 normalize: bool = True,
37 normalization_params: Optional[Dict[str, Any]] = None,
38 well_filter: Optional[List[str]] = None,
39 flatten_z: bool = False,
40 z_method: str = "max",
41 channel_weights: Optional[Union[List[float], Dict[str, float]]] = None,
42 ):
43 """
44 Initialize with pipeline parameters.
46 Args:
47 input_dir: Input directory containing images
48 output_dir: Output directory for stitched images
49 normalize: Whether to include normalization
50 normalization_params: Parameters for normalization
51 well_filter: Wells to process
52 flatten_z: Whether to flatten Z-stacks (if Z-stacks are present)
53 z_method: Z-stack processing method:
54 - "max", "mean", "median" for projection methods
55 - "combined", "laplacian", "tenengrad" for focus detection methods
56 channel_weights: Weights for channel compositing (for reference image only).
57 Should be a list with length equal to the number of channels.
58 """
59 self.input_dir = Path(input_dir)
60 # Only use output_dir if explicitly provided, otherwise let the pipeline handle it
61 self.output_dir = Path(output_dir) if output_dir else None
63 self.normalize = normalize
64 # Default normalization parameters
65 self.normalization_params = normalization_params or {
66 'low_percentile': 1.0,
67 'high_percentile': 99.0
68 }
69 self.well_filter = well_filter
70 self.flatten_z = flatten_z
71 self.z_method = z_method
72 self.channel_weights = channel_weights
74 # Determine if z_method is a focus method or projection method
75 self.focus_methods = ["combined", "laplacian", "tenengrad", "normalized_variance", "fft"]
76 self.is_focus_method = self.z_method in self.focus_methods
78 def create_pipelines(self) -> List[Pipeline]:
79 """
80 Create pipeline configuration based on parameters.
82 This method creates two pipelines:
83 1. Position generation pipeline - Creates position files for stitching
84 2. Image assembly pipeline - Stitches images using the position files
85 """
86 # Create position generation pipeline
87 pos_pipeline = Pipeline(
88 input_dir=self.input_dir,
89 steps=[
90 # Always include Z-flattening for position generation
91 ZFlatStep(method="max"),
93 # Include normalization if enabled
94 NormStep(**self.normalization_params) if self.normalize else None,
96 # Always include channel compositing for reference image
97 CompositeStep(weights=self.channel_weights),
99 # Always include position generation
100 PositionGenerationStep()
101 ],
102 well_filter=self.well_filter,
103 name="Position Generation Pipeline"
104 )
106 # Get the position generation step's output directory
107 positions_dir = pos_pipeline.steps[-1].output_dir
109 # Create assembly pipeline
110 assembly_pipeline = Pipeline(
111 input_dir=self.input_dir,
112 output_dir=self.output_dir,
113 steps=[
114 # Include normalization if enabled (create new instance)
115 NormStep(**self.normalization_params) if self.normalize else None,
117 # Include Z-flattening for assembly if enabled
118 (FocusStep(
119 focus_options={'metric': self.z_method}
120 ) if self.is_focus_method else
121 ZFlatStep(
122 method=self.z_method
123 )) if self.flatten_z else None,
125 # Always include image stitching with explicit positions directory
126 ImageStitchingStep(positions_dir=positions_dir)
127 ],
128 well_filter=self.well_filter,
129 name="Image Assembly Pipeline"
130 )
132 # Return both pipelines
133 return [pos_pipeline, assembly_pipeline]