How to Add a Custom DSC Deconvolution Method¶
Add a new deconvolution method to osipy in a single file.
Steps¶
1. Create your deconvolver¶
Create a new file, e.g., osipy/dsc/deconvolution/my_deconv.py:
Define a custom deconvolver
"""Custom deconvolution method for DSC-MRI."""
from typing import TYPE_CHECKING, Any
import numpy as np
from osipy.common.backend.array_module import get_array_module
from osipy.dsc.deconvolution.base import BaseDeconvolver
from osipy.dsc.deconvolution.registry import register_deconvolver
from osipy.dsc.deconvolution.svd import DeconvolutionResult
if TYPE_CHECKING:
from numpy.typing import NDArray
@register_deconvolver("my_method")
class MyDeconvolver(BaseDeconvolver):
"""Custom deconvolution method."""
@property
def name(self) -> str:
return "My Custom Deconvolution"
def deconvolve(self, concentration, aif, time, mask=None, **kwargs):
xp = get_array_module(concentration, aif, time)
spatial_shape = concentration.shape[:-1]
n_timepoints = concentration.shape[-1]
dt = float(time[1] - time[0]) if len(time) > 1 else 1.0
# Your deconvolution algorithm here
# ...
# Return a DeconvolutionResult
return DeconvolutionResult(
residue_function=residue,
cbf=cbf,
mtt=mtt,
delay=delay,
threshold_used=0.0,
)
2. Use it¶
Use the registered deconvolver
# Import to trigger registration
import osipy.dsc.deconvolution.my_deconv
from osipy.dsc.deconvolution.registry import (
get_deconvolver,
list_deconvolvers,
)
# Verify registration
print(list_deconvolvers())
# ['cSVD', 'my_method', 'oSVD', 'sSVD']
# Use it
deconvolver = get_deconvolver("my_method")
result = deconvolver.deconvolve(concentration, aif, time, mask)
print(result.cbf) # CBF map
print(result.mtt) # MTT map
Adding a custom leakage correction method¶
The same pattern applies:
Define a custom leakage corrector
from osipy.dsc.leakage.base import BaseLeakageCorrector
from osipy.dsc.leakage.registry import register_leakage_corrector
@register_leakage_corrector("my_correction")
class MyLeakageCorrector(BaseLeakageCorrector):
@property
def name(self) -> str:
return "My Leakage Correction"
def correct(self, delta_r2, aif, time, mask=None, **kwargs):
# Your correction algorithm
# Return a LeakageCorrectionResult
...
Key conventions¶
- Use
xp = get_array_module(...)for GPU/CPU agnostic code - Return the standard result dataclasses (
DeconvolutionResult,LeakageCorrectionResult) - Use
DataValidationErrorfromosipy.common.exceptionsfor input validation errors - Do not use scipy — use
xp.linalgfor linear algebra