| 540 | |
| 541 | |
| 542 | class GaussianFilter(nn.Module): |
| 543 | |
| 544 | def __init__( |
| 545 | self, |
| 546 | spatial_dims: int, |
| 547 | sigma: Sequence[float] | float | Sequence[torch.Tensor] | torch.Tensor, |
| 548 | truncated: float = 4.0, |
| 549 | approx: str = "erf", |
| 550 | requires_grad: bool = False, |
| 551 | ) -> None: |
| 552 | """ |
| 553 | Args: |
| 554 | spatial_dims: number of spatial dimensions of the input image. |
| 555 | must have shape (Batch, channels, H[, W, ...]). |
| 556 | sigma: std. could be a single value, or `spatial_dims` number of values. |
| 557 | truncated: spreads how many stds. |
| 558 | approx: discrete Gaussian kernel type, available options are "erf", "sampled", and "scalespace". |
| 559 | |
| 560 | - ``erf`` approximation interpolates the error function; |
| 561 | - ``sampled`` uses a sampled Gaussian kernel; |
| 562 | - ``scalespace`` corresponds to |
| 563 | https://en.wikipedia.org/wiki/Scale_space_implementation#The_discrete_Gaussian_kernel |
| 564 | based on the modified Bessel functions. |
| 565 | |
| 566 | requires_grad: whether to store the gradients for sigma. |
| 567 | if True, `sigma` will be the initial value of the parameters of this module |
| 568 | (for example `parameters()` iterator could be used to get the parameters); |
| 569 | otherwise this module will fix the kernels using `sigma` as the std. |
| 570 | """ |
| 571 | if issequenceiterable(sigma): |
| 572 | if len(sigma) != spatial_dims: # type: ignore |
| 573 | raise ValueError |
| 574 | else: |
| 575 | sigma = [deepcopy(sigma) for _ in range(spatial_dims)] # type: ignore |
| 576 | super().__init__() |
| 577 | self.sigma = [ |
| 578 | torch.nn.Parameter( |
| 579 | torch.as_tensor(s, dtype=torch.float, device=s.device if isinstance(s, torch.Tensor) else None), |
| 580 | requires_grad=requires_grad, |
| 581 | ) |
| 582 | for s in sigma # type: ignore |
| 583 | ] |
| 584 | self.truncated = truncated |
| 585 | self.approx = approx |
| 586 | for idx, param in enumerate(self.sigma): |
| 587 | self.register_parameter(f"kernel_sigma_{idx}", param) |
| 588 | |
| 589 | def forward(self, x: torch.Tensor) -> torch.Tensor: |
| 590 | """ |
| 591 | Args: |
| 592 | x: in shape [Batch, chns, H, W, D]. |
| 593 | """ |
| 594 | _kernel = [gaussian_1d(s, truncated=self.truncated, approx=self.approx) for s in self.sigma] |
| 595 | return separable_filtering(x=x, kernels=_kernel) |
| 596 | |
| 597 | |
| 598 | class LLTMFunction(Function): |
no outgoing calls
searching dependent graphs…