0
# Finite Difference Framework
1
2
PDE-based image processing framework for level set methods, segmentation, and deformable models. This framework provides the foundation for implementing iterative algorithms that solve partial differential equations using finite difference methods, commonly used in image segmentation, denoising, and registration.
3
4
## Capabilities
5
6
### Base Finite Difference Classes
7
8
Foundation classes for implementing PDE-based image processing algorithms.
9
10
```python { .api }
11
class FiniteDifferenceImageFilter[TInputImage, TOutputImage]:
12
"""
13
Base class for finite difference image filters implementing PDE solvers.
14
15
Template Parameters:
16
- TInputImage: Input image type
17
- TOutputImage: Output image type
18
"""
19
def SetNumberOfIterations(self, iterations: IdentifierType) -> None: ...
20
def GetNumberOfIterations(self) -> IdentifierType: ...
21
def SetTimeStep(self, time_step: TimeStepType) -> None: ...
22
def GetTimeStep(self) -> TimeStepType: ...
23
def SetElapsedIterations(self, iterations: IdentifierType) -> None: ...
24
def GetElapsedIterations(self) -> IdentifierType: ...
25
def SetUseImageSpacing(self, flag: bool) -> None: ...
26
def GetUseImageSpacing(self) -> bool: ...
27
def SetMaximumRMSError(self, error: double) -> None: ...
28
def GetMaximumRMSError(self) -> double: ...
29
def GetRMSChange(self) -> double: ...
30
def SetIsInitialized(self, flag: bool) -> None: ...
31
def GetIsInitialized(self) -> bool: ...
32
def SetManualReinitialization(self, flag: bool) -> None: ...
33
def GetManualReinitialization(self) -> bool: ...
34
35
class DenseFiniteDifferenceImageFilter[TInputImage, TOutputImage]:
36
"""Dense finite difference solver where all pixels are updated each iteration."""
37
def New() -> DenseFiniteDifferenceImageFilter[TInputImage, TOutputImage]: ...
38
def GetFiniteDifferenceFunction(self) -> FiniteDifferenceFunctionType: ...
39
def SetFiniteDifferenceFunction(self, function: FiniteDifferenceFunctionType) -> None: ...
40
41
class SparseFiniteDifferenceImageFilter[TInputImage, TOutputImage, TSparseOutputImage]:
42
"""Sparse finite difference solver that updates only active pixels."""
43
def New() -> SparseFiniteDifferenceImageFilter[TInputImage, TOutputImage, TSparseOutputImage]: ...
44
def SetNumberOfLayers(self, layers: ValueType) -> None: ...
45
def GetNumberOfLayers(self) -> ValueType: ...
46
def SetIsoSurfaceValue(self, value: ValueType) -> None: ...
47
def GetIsoSurfaceValue(self) -> ValueType: ...
48
def SetInterpolateSurfaceLocation(self, flag: bool) -> None: ...
49
def GetInterpolateSurfaceLocation(self) -> bool: ...
50
```
51
52
### Finite Difference Functions
53
54
Functions that define the PDE update rules for different types of evolution equations.
55
56
```python { .api }
57
class FiniteDifferenceFunction[TImageType]:
58
"""
59
Base class for finite difference functions that compute PDE updates.
60
61
Template Parameters:
62
- TImageType: Image type for the PDE evolution
63
"""
64
def ComputeUpdate(self, neighborhood: NeighborhoodType, global_data: GlobalDataStruct,
65
gd: GlobalDataStruct) -> PixelType: ...
66
def GetRadius(self) -> RadiusType: ...
67
def GetScaleCoefficients(self) -> ScalarValueType: ...
68
def SetScaleCoefficients(self, coeffs: ScalarValueType) -> None: ...
69
def InitializeIteration(self) -> None: ...
70
def ComputeGlobalTimeStep(self, global_data: GlobalDataStruct) -> TimeStepType: ...
71
72
class LevelSetFunction[TImageType]:
73
"""Base class for level set evolution functions."""
74
def New() -> LevelSetFunction[TImageType]: ...
75
def SetAdvectionWeight(self, weight: ScalarValueType) -> None: ...
76
def GetAdvectionWeight(self) -> ScalarValueType: ...
77
def SetPropagationWeight(self, weight: ScalarValueType) -> None: ...
78
def GetPropagationWeight(self) -> ScalarValueType: ...
79
def SetCurvatureWeight(self, weight: ScalarValueType) -> None: ...
80
def GetCurvatureWeight(self) -> ScalarValueType: ...
81
def SetLaplacianSmoothingWeight(self, weight: ScalarValueType) -> None: ...
82
def GetLaplacianSmoothingWeight(self) -> ScalarValueType: ...
83
def SetEpsilonMagnitude(self, epsilon: ScalarValueType) -> None: ...
84
def GetEpsilonMagnitude(self) -> ScalarValueType: ...
85
def ComputeSpeedImage(self) -> None: ...
86
def ComputeAdvectionImage(self) -> None: ...
87
def Initialize(self, radius: RadiusType) -> None: ...
88
def CalculateAdvectionImage(self) -> None: ...
89
def CalculateSpeedImage(self) -> None: ...
90
def CalculateCurvatureImage(self) -> None: ...
91
92
class SegmentationLevelSetFunction[TImageType, TFeatureImageType]:
93
"""Level set function for image segmentation applications."""
94
def New() -> SegmentationLevelSetFunction[TImageType, TFeatureImageType]: ...
95
def SetFeatureImage(self, image: TFeatureImageType) -> None: ...
96
def GetFeatureImage(self) -> TFeatureImageType: ...
97
def SetSpeedImage(self, image: ImageType) -> None: ...
98
def GetSpeedImage(self) -> ImageType: ...
99
def SetAdvectionImage(self, image: VectorImageType) -> None: ...
100
def GetAdvectionImage(self) -> VectorImageType: ...
101
def ReverseExpansionDirection(self) -> None: ...
102
def GetReverseExpansionDirection(self) -> bool: ...
103
def SetUseMinimalCurvature(self, flag: bool) -> None: ...
104
def GetUseMinimalCurvature(self) -> bool: ...
105
```
106
107
### Level Set Segmentation Functions
108
109
Specialized level set functions for different segmentation approaches.
110
111
```python { .api }
112
class ShapeDetectionLevelSetFunction[TImageType, TFeatureImageType]:
113
"""Shape detection level set for boundary-based segmentation."""
114
def New() -> ShapeDetectionLevelSetFunction[TImageType, TFeatureImageType]: ...
115
def CalculateSpeedImage(self) -> None: ...
116
def CalculateAdvectionImage(self) -> None: ...
117
def Initialize(self, radius: RadiusType) -> None: ...
118
119
class GeodesicActiveContourLevelSetFunction[TImageType, TFeatureImageType]:
120
"""Geodesic active contour level set function."""
121
def New() -> GeodesicActiveContourLevelSetFunction[TImageType, TFeatureImageType]: ...
122
def CalculateSpeedImage(self) -> None: ...
123
def CalculateAdvectionImage(self) -> None: ...
124
def Initialize(self, radius: RadiusType) -> None: ...
125
126
class ThresholdSegmentationLevelSetFunction[TImageType, TFeatureImageType]:
127
"""Threshold-based segmentation using level sets."""
128
def New() -> ThresholdSegmentationLevelSetFunction[TImageType, TFeatureImageType]: ...
129
def SetUpperThreshold(self, value: ScalarValueType) -> None: ...
130
def GetUpperThreshold(self) -> ScalarValueType: ...
131
def SetLowerThreshold(self, value: ScalarValueType) -> None: ...
132
def GetLowerThreshold(self) -> ScalarValueType: ...
133
def CalculateSpeedImage(self) -> None: ...
134
def SetEdgeWeight(self, weight: ScalarValueType) -> None: ...
135
def GetEdgeWeight(self) -> ScalarValueType: ...
136
def SetSmoothingIterations(self, iterations: int) -> None: ...
137
def GetSmoothingIterations(self) -> int: ...
138
def SetSmoothingTimeStep(self, time_step: ScalarValueType) -> None: ...
139
def GetSmoothingTimeStep(self) -> ScalarValueType: ...
140
def SetSmoothingConductance(self, conductance: ScalarValueType) -> None: ...
141
def GetSmoothingConductance(self) -> ScalarValueType: ...
142
143
class CannySegmentationLevelSetFunction[TImageType, TFeatureImageType]:
144
"""Canny edge-based level set segmentation."""
145
def New() -> CannySegmentationLevelSetFunction[TImageType, TFeatureImageType]: ...
146
def SetThreshold(self, threshold: ScalarValueType) -> None: ...
147
def GetThreshold(self) -> ScalarValueType: ...
148
def SetVariance(self, variance: double) -> None: ...
149
def GetVariance(self) -> double: ...
150
def CalculateSpeedImage(self) -> None: ...
151
def CalculateAdvectionImage(self) -> None: ...
152
```
153
154
### Boundary Conditions
155
156
Classes that define how finite difference operations handle image boundaries.
157
158
```python { .api }
159
class ZeroFluxNeumannBoundaryCondition[TImageType]:
160
"""Neumann boundary condition with zero flux (zero derivative)."""
161
def New() -> ZeroFluxNeumannBoundaryCondition[TImageType]: ...
162
def GetPixel(self, index: IndexType, image: TImageType) -> PixelType: ...
163
def GetInputRequestedRegion(self, input_requested_region: RegionType,
164
input_largest_region: RegionType) -> RegionType: ...
165
def RequiresCompleteNeighborhood(self) -> bool: ...
166
167
class ConstantBoundaryCondition[TImageType]:
168
"""Constant boundary condition that returns a fixed value outside the image."""
169
def New() -> ConstantBoundaryCondition[TImageType]: ...
170
def SetConstant(self, constant: PixelType) -> None: ...
171
def GetConstant(self) -> PixelType: ...
172
def GetPixel(self, index: IndexType, image: TImageType) -> PixelType: ...
173
174
class PeriodicBoundaryCondition[TImageType]:
175
"""Periodic boundary condition that wraps around image boundaries."""
176
def New() -> PeriodicBoundaryCondition[TImageType]: ...
177
def GetPixel(self, index: IndexType, image: TImageType) -> PixelType: ...
178
```
179
180
### Neighborhood Iterators
181
182
Iterators for accessing image neighborhoods used in finite difference operations.
183
184
```python { .api }
185
class NeighborhoodIterator[TImage, TBoundaryCondition]:
186
"""Iterator for read-write access to image neighborhoods."""
187
def New() -> NeighborhoodIterator[TImage, TBoundaryCondition]: ...
188
def SetRadius(self, radius: RadiusType) -> None: ...
189
def GetRadius(self) -> RadiusType: ...
190
def GoToBegin(self) -> None: ...
191
def GoToEnd(self) -> None: ...
192
def IsAtBegin(self) -> bool: ...
193
def IsAtEnd(self) -> bool: ...
194
def GetCenterPixel(self) -> PixelType: ...
195
def SetCenterPixel(self, pixel: PixelType) -> None: ...
196
def GetPixel(self, offset: OffsetType) -> PixelType: ...
197
def SetPixel(self, offset: OffsetType, pixel: PixelType) -> None: ...
198
def GetIndex(self) -> IndexType: ...
199
def SetLocation(self, index: IndexType) -> None: ...
200
def InBounds(self) -> bool: ...
201
202
class ConstNeighborhoodIterator[TImage, TBoundaryCondition]:
203
"""Iterator for read-only access to image neighborhoods."""
204
def New() -> ConstNeighborhoodIterator[TImage, TBoundaryCondition]: ...
205
def SetRadius(self, radius: RadiusType) -> None: ...
206
def GetRadius(self) -> RadiusType: ...
207
def GoToBegin(self) -> None: ...
208
def GoToEnd(self) -> None: ...
209
def IsAtBegin(self) -> bool: ...
210
def IsAtEnd(self) -> bool: ...
211
def GetCenterPixel(self) -> PixelType: ...
212
def GetPixel(self, offset: OffsetType) -> PixelType: ...
213
def GetIndex(self) -> IndexType: ...
214
def SetLocation(self, index: IndexType) -> None: ...
215
```
216
217
### Anisotropic Diffusion
218
219
Functions for anisotropic diffusion-based image smoothing and enhancement.
220
221
```python { .api }
222
class AnisotropicDiffusionFunction[TImage]:
223
"""Base class for anisotropic diffusion functions."""
224
def ComputeUpdate(self, neighborhood: NeighborhoodType, global_data: GlobalDataStruct,
225
gd: GlobalDataStruct) -> PixelType: ...
226
def SetTimeStep(self, time_step: TimeStepType) -> None: ...
227
def GetTimeStep(self) -> TimeStepType: ...
228
def SetConductanceParameter(self, conductance: double) -> None: ...
229
def GetConductanceParameter(self) -> double: ...
230
def InitializeIteration(self) -> None: ...
231
232
class GradientAnisotropicDiffusionFunction[TImage]:
233
"""Gradient-based anisotropic diffusion function."""
234
def New() -> GradientAnisotropicDiffusionFunction[TImage]: ...
235
def ComputeUpdate(self, neighborhood: NeighborhoodType, global_data: GlobalDataStruct,
236
gd: GlobalDataStruct) -> PixelType: ...
237
238
class CurvatureAnisotropicDiffusionFunction[TImage]:
239
"""Curvature-based anisotropic diffusion function."""
240
def New() -> CurvatureAnisotropicDiffusionFunction[TImage]: ...
241
def ComputeUpdate(self, neighborhood: NeighborhoodType, global_data: GlobalDataStruct,
242
gd: GlobalDataStruct) -> PixelType: ...
243
```
244
245
### Morphological Operations for Level Sets
246
247
Mathematical morphology operations adapted for level set frameworks.
248
249
```python { .api }
250
class MorphologicalWatershedFromMarkersImageFilter[TInputImage, TLabelImage]:
251
"""Watershed segmentation from marker points using morphological operations."""
252
def New() -> MorphologicalWatershedFromMarkersImageFilter[TInputImage, TLabelImage]: ...
253
def SetInput1(self, input: TInputImage) -> None: ...
254
def SetInput2(self, markers: TLabelImage) -> None: ...
255
def SetMarkWatershedLine(self, flag: bool) -> None: ...
256
def GetMarkWatershedLine(self) -> bool: ...
257
def SetFullyConnected(self, flag: bool) -> None: ...
258
def GetFullyConnected(self) -> bool: ...
259
```
260
261
## Usage Examples
262
263
### Basic Level Set Segmentation
264
265
```python
266
import itk
267
import numpy as np
268
269
# Create a test image with a circular object
270
ImageType = itk.Image[itk.F, 2]
271
image = ImageType.New()
272
273
size = itk.Size[2]([100, 100])
274
region = itk.ImageRegion[2]()
275
region.SetSize(size)
276
image.SetRegions(region)
277
image.SetSpacing([1.0, 1.0])
278
image.Allocate()
279
280
# Create a circular object
281
center_x, center_y = 50, 50
282
radius = 20
283
for x in range(100):
284
for y in range(100):
285
idx = itk.Index[2]([x, y])
286
dist = np.sqrt((x - center_x)**2 + (y - center_y)**2)
287
if dist < radius:
288
image.SetPixel(idx, 200.0) # Inside object
289
else:
290
image.SetPixel(idx, 50.0) # Background
291
292
# Create initial level set (signed distance function)
293
initial_level_set = ImageType.New()
294
initial_level_set.SetRegions(region)
295
initial_level_set.SetSpacing([1.0, 1.0])
296
initial_level_set.Allocate()
297
298
# Initialize level set as signed distance to a smaller circle
299
init_radius = 15
300
for x in range(100):
301
for y in range(100):
302
idx = itk.Index[2]([x, y])
303
dist = np.sqrt((x - center_x)**2 + (y - center_y)**2)
304
signed_dist = dist - init_radius
305
initial_level_set.SetPixel(idx, signed_dist)
306
307
# Create threshold segmentation level set function
308
LevelSetFunctionType = itk.ThresholdSegmentationLevelSetFunction[ImageType, ImageType]
309
level_set_function = LevelSetFunctionType.New()
310
level_set_function.SetFeatureImage(image)
311
level_set_function.SetPropagationWeight(1.0)
312
level_set_function.SetAdvectionWeight(0.0)
313
level_set_function.SetCurvatureWeight(0.1)
314
level_set_function.SetUpperThreshold(150.0)
315
level_set_function.SetLowerThreshold(100.0)
316
317
# Create segmentation filter
318
SegmentationFilterType = itk.SegmentationLevelSetImageFilter[ImageType, ImageType, itk.F]
319
segmentation_filter = SegmentationFilterType.New()
320
segmentation_filter.SetInput(initial_level_set)
321
segmentation_filter.SetFeatureImage(image)
322
segmentation_filter.SetSegmentationFunction(level_set_function)
323
segmentation_filter.SetMaximumRMSError(0.02)
324
segmentation_filter.SetNumberOfIterations(100)
325
326
# Run segmentation
327
try:
328
segmentation_filter.Update()
329
result = segmentation_filter.GetOutput()
330
print(f"Segmentation completed in {segmentation_filter.GetElapsedIterations()} iterations")
331
print(f"Final RMS error: {segmentation_filter.GetRMSChange():.6f}")
332
except Exception as e:
333
print(f"Segmentation failed: {e}")
334
```
335
336
### Anisotropic Diffusion
337
338
```python
339
import itk
340
import numpy as np
341
342
# Create noisy test image
343
ImageType = itk.Image[itk.F, 2]
344
image = ImageType.New()
345
346
size = itk.Size[2]([100, 100])
347
region = itk.ImageRegion[2]()
348
region.SetSize(size)
349
image.SetRegions(region)
350
image.Allocate()
351
352
# Create image with edges and noise
353
np.random.seed(42)
354
for x in range(100):
355
for y in range(100):
356
idx = itk.Index[2]([x, y])
357
358
# Create step edges
359
base_value = 100.0 if x > 50 else 50.0
360
if y > 50:
361
base_value += 75.0
362
363
# Add noise
364
noise = np.random.normal(0, 10)
365
value = base_value + noise
366
image.SetPixel(idx, value)
367
368
# Create anisotropic diffusion filter
369
DiffusionFilterType = itk.GradientAnisotropicDiffusionImageFilter[ImageType, ImageType]
370
diffusion_filter = DiffusionFilterType.New()
371
diffusion_filter.SetInput(image)
372
diffusion_filter.SetNumberOfIterations(20)
373
diffusion_filter.SetTimeStep(0.0625) # Should be <= 0.25 for stability in 2D
374
diffusion_filter.SetConductanceParameter(3.0)
375
376
# Run diffusion
377
diffusion_filter.Update()
378
smoothed_image = diffusion_filter.GetOutput()
379
380
print(f"Anisotropic diffusion completed")
381
print(f"Iterations: {diffusion_filter.GetElapsedIterations()}")
382
print(f"Final RMS change: {diffusion_filter.GetRMSChange():.6f}")
383
384
# Compare original and smoothed values at a few points
385
test_points = [
386
itk.Index[2]([25, 25]), # Uniform region
387
itk.Index[2]([50, 25]), # Vertical edge
388
itk.Index[2]([25, 50]), # Horizontal edge
389
itk.Index[2]([50, 50]) # Corner
390
]
391
392
for idx in test_points:
393
original = image.GetPixel(idx)
394
smoothed = smoothed_image.GetPixel(idx)
395
print(f"Point {idx}: Original={original:.1f}, Smoothed={smoothed:.1f}")
396
```
397
398
### Shape Detection Level Set
399
400
```python
401
import itk
402
import numpy as np
403
404
# Create feature image with edge information
405
ImageType = itk.Image[itk.F, 2]
406
feature_image = ImageType.New()
407
408
size = itk.Size[2]([80, 80])
409
region = itk.ImageRegion[2]()
410
region.SetSize(size)
411
feature_image.SetRegions(region)
412
feature_image.SetSpacing([1.0, 1.0])
413
feature_image.Allocate()
414
415
# Create edge map (lower values at edges)
416
center_x, center_y = 40, 40
417
radius = 25
418
for x in range(80):
419
for y in range(80):
420
idx = itk.Index[2]([x, y])
421
dist = np.sqrt((x - center_x)**2 + (y - center_y)**2)
422
423
# Create edge feature: low values at circle boundary
424
edge_strength = abs(dist - radius)
425
edge_feature = 1.0 / (1.0 + edge_strength) # High at edges
426
speed = 1.0 - edge_feature # Low speed at edges (for stopping)
427
428
feature_image.SetPixel(idx, speed)
429
430
# Create initial level set (smaller circle inside)
431
initial_level_set = ImageType.New()
432
initial_level_set.SetRegions(region)
433
initial_level_set.SetSpacing([1.0, 1.0])
434
initial_level_set.Allocate()
435
436
init_radius = 15
437
for x in range(80):
438
for y in range(80):
439
idx = itk.Index[2]([x, y])
440
dist = np.sqrt((x - center_x)**2 + (y - center_y)**2)
441
signed_dist = init_radius - dist # Negative outside, positive inside
442
initial_level_set.SetPixel(idx, signed_dist)
443
444
# Create shape detection level set function
445
ShapeDetectionType = itk.ShapeDetectionLevelSetFunction[ImageType, ImageType]
446
shape_function = ShapeDetectionType.New()
447
shape_function.SetFeatureImage(feature_image)
448
shape_function.SetPropagationWeight(1.0)
449
shape_function.SetAdvectionWeight(0.0)
450
shape_function.SetCurvatureWeight(0.05)
451
452
# Create shape detection filter
453
FilterType = itk.ShapeDetectionLevelSetImageFilter[ImageType, ImageType]
454
shape_filter = FilterType.New()
455
shape_filter.SetInput(initial_level_set)
456
shape_filter.SetFeatureImage(feature_image)
457
shape_filter.SetSegmentationFunction(shape_function)
458
shape_filter.SetMaximumRMSError(0.01)
459
shape_filter.SetNumberOfIterations(100)
460
461
# Run shape detection
462
shape_filter.Update()
463
result = shape_filter.GetOutput()
464
465
print(f"Shape detection completed in {shape_filter.GetElapsedIterations()} iterations")
466
print(f"Final RMS error: {shape_filter.GetRMSChange():.6f}")
467
468
# Extract zero level set (the detected shape boundary)
469
ThresholdFilterType = itk.BinaryThresholdImageFilter[ImageType, itk.Image[itk.UC, 2]]
470
threshold_filter = ThresholdFilterType.New()
471
threshold_filter.SetInput(result)
472
threshold_filter.SetLowerThreshold(-1000.0)
473
threshold_filter.SetUpperThreshold(0.0)
474
threshold_filter.SetInsideValue(255)
475
threshold_filter.SetOutsideValue(0)
476
threshold_filter.Update()
477
478
binary_result = threshold_filter.GetOutput()
479
print("Binary segmentation created")
480
```
481
482
### Custom Finite Difference Function
483
484
```python
485
import itk
486
487
# This example shows the structure for creating custom finite difference functions
488
# Note: In practice, you would typically use existing ITK functions
489
490
class CustomDiffusionFunction(itk.FiniteDifferenceFunction[itk.Image[itk.F, 2]]):
491
"""Custom diffusion function example (simplified)."""
492
493
def __init__(self):
494
super().__init__()
495
self.time_step = 0.1
496
self.conductance = 1.0
497
498
def ComputeUpdate(self, neighborhood, global_data, gd):
499
"""Compute the update for a single pixel."""
500
# Get center pixel
501
center_pixel = neighborhood.GetCenterPixel()
502
503
# Compute gradients using neighborhood
504
dx_forward = neighborhood.GetNext(0, 1) - center_pixel # Right neighbor
505
dx_backward = center_pixel - neighborhood.GetPrevious(0, 1) # Left neighbor
506
dy_forward = neighborhood.GetNext(1, 1) - center_pixel # Bottom neighbor
507
dy_backward = center_pixel - neighborhood.GetPrevious(1, 1) # Top neighbor
508
509
# Simple diffusion update (this is a simplified example)
510
laplacian = dx_forward + dx_backward + dy_forward + dy_backward - 4 * center_pixel
511
update = self.time_step * laplacian
512
513
return update
514
515
def GetRadius(self):
516
"""Return the neighborhood radius."""
517
return itk.Size[2]([1, 1]) # 3x3 neighborhood
518
519
def ComputeGlobalTimeStep(self, global_data):
520
"""Return the time step for this iteration."""
521
return self.time_step
522
523
# Example usage would involve registering this custom function
524
# with a finite difference image filter (implementation details omitted)
525
print("Custom finite difference function structure defined")
526
```
527
528
### Working with Boundary Conditions
529
530
```python
531
import itk
532
import numpy as np
533
534
# Create test image
535
ImageType = itk.Image[itk.F, 2]
536
image = ImageType.New()
537
538
size = itk.Size[2]([50, 50])
539
region = itk.ImageRegion[2]()
540
region.SetSize(size)
541
image.SetRegions(region)
542
image.Allocate()
543
544
# Fill with gradient
545
for x in range(50):
546
for y in range(50):
547
idx = itk.Index[2]([x, y])
548
value = float(x + y)
549
image.SetPixel(idx, value)
550
551
# Create different boundary condition objects
552
ZeroFluxType = itk.ZeroFluxNeumannBoundaryCondition[ImageType]
553
ConstantType = itk.ConstantBoundaryCondition[ImageType]
554
555
zero_flux_bc = ZeroFluxType.New()
556
constant_bc = ConstantType.New()
557
constant_bc.SetConstant(999.0)
558
559
# Create neighborhood iterators with different boundary conditions
560
NeighborhoodIteratorType = itk.NeighborhoodIterator[ImageType, ZeroFluxType]
561
radius = itk.Size[2]([1, 1]) # 3x3 neighborhood
562
563
# Iterator with zero flux boundary condition
564
zero_flux_iterator = NeighborhoodIteratorType.New()
565
zero_flux_iterator.SetRadius(radius)
566
zero_flux_iterator.SetImage(image)
567
zero_flux_iterator.SetBoundaryCondition(zero_flux_bc)
568
569
# Test boundary handling at image edge
570
edge_index = itk.Index[2]([0, 0]) # Top-left corner
571
zero_flux_iterator.SetLocation(edge_index)
572
573
print("Testing boundary conditions at corner (0,0):")
574
print(f"Center pixel: {zero_flux_iterator.GetCenterPixel()}")
575
576
# Access pixels that would be outside the image
577
# With zero flux, these should return edge values
578
for offset_x in [-1, 0, 1]:
579
for offset_y in [-1, 0, 1]:
580
offset = itk.Offset[2]([offset_x, offset_y])
581
pixel_value = zero_flux_iterator.GetPixel(offset)
582
print(f"Offset ({offset_x}, {offset_y}): {pixel_value}")
583
584
print("\nBoundary condition testing completed")
585
```
586
587
### Neighborhood Iterator Usage
588
589
```python
590
import itk
591
592
# Create test image
593
ImageType = itk.Image[itk.F, 2]
594
image = ImageType.New()
595
596
size = itk.Size[2]([20, 20])
597
region = itk.ImageRegion[2]()
598
region.SetSize(size)
599
image.SetRegions(region)
600
image.Allocate()
601
602
# Fill with simple pattern
603
for x in range(20):
604
for y in range(20):
605
idx = itk.Index[2]([x, y])
606
value = float(x * y)
607
image.SetPixel(idx, value)
608
609
# Create neighborhood iterator
610
BoundaryConditionType = itk.ZeroFluxNeumannBoundaryCondition[ImageType]
611
IteratorType = itk.NeighborhoodIterator[ImageType, BoundaryConditionType]
612
613
boundary_condition = BoundaryConditionType.New()
614
iterator = IteratorType.New()
615
iterator.SetRadius(itk.Size[2]([1, 1])) # 3x3 neighborhood
616
iterator.SetImage(image)
617
iterator.SetBoundaryCondition(boundary_condition)
618
619
# Perform a simple averaging filter
620
output_image = ImageType.New()
621
output_image.SetRegions(region)
622
output_image.Allocate()
623
624
# Iterate through all pixels
625
for iterator.GoToBegin(); not iterator.IsAtEnd(); iterator.__iadd__(1):
626
# Compute local average
627
total = 0.0
628
count = 0
629
630
# Sum all pixels in neighborhood
631
for i in range(iterator.Size()):
632
total += iterator.GetPixel(i)
633
count += 1
634
635
average = total / count
636
637
# Set output pixel
638
output_image.SetPixel(iterator.GetIndex(), average)
639
640
print("Neighborhood averaging completed")
641
642
# Compare a few values
643
test_indices = [
644
itk.Index[2]([5, 5]),
645
itk.Index[2]([10, 10]),
646
itk.Index[2]([15, 15])
647
]
648
649
for idx in test_indices:
650
original = image.GetPixel(idx)
651
smoothed = output_image.GetPixel(idx)
652
print(f"Index {idx}: Original={original}, Smoothed={smoothed:.1f}")
653
```