or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-structures.mdfiltering.mdfinite-difference.mdgpu-computing.mdimage-adaptors.mdimage-functions.mdindex.mdio.mdmesh.mdnumpy-integration.mdregistration.mdsegmentation.mdspatial-objects.mdtransforms.md

finite-difference.mddocs/

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

```