예제 #1
0
파일: array.py 프로젝트: Nic-Ma/MONAI
    def __init__(
        self,
        spatial_dims: int = 2,
        sigma: Union[Sequence[float], float, Sequence[torch.Tensor],
                     torch.Tensor] = 0.0,
        prob_threshold: float = 0.5,
        box_size: Union[int, Sequence[int]] = 48,
    ) -> None:
        self.sigma = sigma
        self.spatial_dims = spatial_dims
        if self.sigma != 0:
            self.filter = GaussianFilter(spatial_dims=spatial_dims,
                                         sigma=sigma)
        if prob_threshold < 0:
            raise ValueError("prob_threshold should be no less than 0.0.")
        self.prob_threshold = prob_threshold
        if isinstance(box_size, int):
            self.box_size = np.asarray([box_size] * spatial_dims)
        elif len(box_size) != spatial_dims:
            raise ValueError(
                "the sequence length of box_size should be the same as spatial_dims."
            )
        else:
            self.box_size = np.asarray(box_size)
        if self.box_size.min() <= 0:
            raise ValueError("box_size should be larger than 0.")

        self.box_lower_bd = self.box_size // 2
        self.box_upper_bd = self.box_size - self.box_lower_bd
예제 #2
0
 def __call__(self, img: np.ndarray) -> np.ndarray:
     gaussian_filter1 = GaussianFilter(img.ndim - 1, self.sigma1, approx=self.approx)
     gaussian_filter2 = GaussianFilter(img.ndim - 1, self.sigma2, approx=self.approx)
     input_data = torch.as_tensor(np.ascontiguousarray(img), dtype=torch.float).unsqueeze(0)
     blurred_f = gaussian_filter1(input_data)
     filter_blurred_f = gaussian_filter2(blurred_f)
     return (blurred_f + self.alpha * (blurred_f - filter_blurred_f)).squeeze(0).detach().numpy()
    def test_train(self, input_args):
        input_dims = input_args.get("dims", (2, 3, 8))
        device = (torch.device("cuda") if
                  (input_args.get("device") == "cuda"
                   and torch.cuda.is_available()) else torch.device("cpu:0"))

        base = torch.ones(*input_dims).to(device)
        gt = torch.tensor(input_args["gt"], requires_grad=False).to(device)
        g_type = input_args["type"]
        lr = input_args.get("lr", 0.1)
        init_sigma = input_args.get("init", 1.0)

        # static filter to generate a target
        spatial_dims = len(base.shape) - 2
        filtering = GaussianFilter(spatial_dims=spatial_dims,
                                   sigma=gt,
                                   approx=g_type,
                                   requires_grad=False)
        filtering.to(device)
        target = filtering(base)
        self.assertFalse(filtering.sigma[0].requires_grad)

        # build trainable
        init_sigma = torch.tensor(init_sigma).to(device)
        trainable = GaussianFilter(spatial_dims=spatial_dims,
                                   sigma=init_sigma,
                                   approx=g_type,
                                   requires_grad=True)
        trainable.to(device)
        self.assertTrue(trainable.sigma[0].requires_grad)

        # train
        optimizer = torch.optim.Adam(trainable.parameters(), lr=lr)
        for s in range(1000):
            optimizer.zero_grad()
            pred = trainable(base)
            loss = torch.square(pred - target).mean()
            loss.backward()
            if (s + 1) % 50 == 0:
                var = list(trainable.parameters())[0]
                print(f"step {s} loss {loss}")
                print(var, var.grad)
            if loss.item() < 1e-7:
                break
            optimizer.step()
        # check the result
        print(s, gt)
        for idx, s in enumerate(trainable.sigma):
            np.testing.assert_allclose(
                s.cpu().item(),
                gt.cpu() if len(gt.shape) == 0 else gt[idx].cpu().item(),
                rtol=1e-2)
    def test_2d(self):
        a = torch.ones(1, 1, 3, 3)
        g = GaussianFilter(2, 3, 3).to(torch.device("cpu:0"))
        expected = np.array([[[
            [0.13239081, 0.13932934, 0.13239081],
            [0.13932936, 0.14663152, 0.13932936],
            [0.13239081, 0.13932934, 0.13239081],
        ]]])

        np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-5)
        if torch.cuda.is_available():
            g = GaussianFilter(2, 3, 3).to(torch.device("cuda:0"))
            np.testing.assert_allclose(g(a.cuda()).cpu().numpy(),
                                       expected,
                                       rtol=1e-2)
예제 #5
0
    def _get_signal(self, image, guidance):
        dimensions = 3 if len(image.shape) > 3 else 2
        guidance = guidance.tolist() if isinstance(guidance, np.ndarray) else guidance
        if dimensions == 3:
            signal = np.zeros((len(guidance), image.shape[-3], image.shape[-2], image.shape[-1]), dtype=np.float32)
        else:
            signal = np.zeros((len(guidance), image.shape[-2], image.shape[-1]), dtype=np.float32)

        sshape = signal.shape
        for i in range(len(guidance)):
            for point in guidance[i]:
                if np.any(np.asarray(point) < 0):
                    continue

                if dimensions == 3:
                    p1 = max(0, min(int(point[-3]), sshape[-3] - 1))
                    p2 = max(0, min(int(point[-2]), sshape[-2] - 1))
                    p3 = max(0, min(int(point[-1]), sshape[-1] - 1))
                    signal[i, p1, p2, p3] = 1.0
                else:
                    p1 = max(0, min(int(point[-2]), sshape[-2] - 1))
                    p2 = max(0, min(int(point[-1]), sshape[-1] - 1))
                    signal[i, p1, p2] = 1.0

            if np.max(signal[i]) > 0:
                signal_tensor = torch.tensor(signal[i])
                pt_gaussian = GaussianFilter(len(signal_tensor.shape), sigma=self.sigma)
                signal_tensor = pt_gaussian(signal_tensor.unsqueeze(0).unsqueeze(0))
                signal_tensor = signal_tensor.squeeze(0).squeeze(0)
                signal[i] = signal_tensor.detach().cpu().numpy()
                signal[i] = (signal[i] - np.min(signal[i])) / (np.max(signal[i]) - np.min(signal[i]))
        return signal
예제 #6
0
 def test_3d(self):
     a = torch.ones(1, 1, 4, 3, 4)
     g = GaussianFilter(3, 3, 3).to(torch.device("cpu:0"))
     expected = np.array([[[
         [
             [0.07294822, 0.08033235, 0.08033235, 0.07294822],
             [0.07680509, 0.08457965, 0.08457965, 0.07680509],
             [0.07294822, 0.08033235, 0.08033235, 0.07294822],
         ],
         [
             [0.08033235, 0.08846395, 0.08846395, 0.08033235],
             [0.08457965, 0.09314119, 0.09314119, 0.08457966],
             [0.08033235, 0.08846396, 0.08846396, 0.08033236],
         ],
         [
             [0.08033235, 0.08846395, 0.08846395, 0.08033235],
             [0.08457965, 0.09314119, 0.09314119, 0.08457966],
             [0.08033235, 0.08846396, 0.08846396, 0.08033236],
         ],
         [
             [0.07294822, 0.08033235, 0.08033235, 0.07294822],
             [0.07680509, 0.08457965, 0.08457965, 0.07680509],
             [0.07294822, 0.08033235, 0.08033235, 0.07294822],
         ],
     ]]])
     np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-5)
예제 #7
0
파일: array.py 프로젝트: lsho76/MONAI
 def __call__(self, img: np.ndarray) -> np.ndarray:
     gaussian_filter = GaussianFilter(img.ndim - 1,
                                      self.sigma,
                                      approx=self.approx)
     input_data = torch.as_tensor(np.ascontiguousarray(img),
                                  dtype=torch.float).unsqueeze(0)
     return gaussian_filter(input_data).squeeze(0).detach().numpy()
    def test_3d(self):
        a = torch.ones(1, 1, 4, 3, 4)
        g = GaussianFilter(3, 3, 3).to(torch.device("cpu:0"))

        expected = np.array([[[
            [
                [0.07189433, 0.07911152, 0.07911152, 0.07189433],
                [0.07566228, 0.08325771, 0.08325771, 0.07566228],
                [0.07189433, 0.07911152, 0.07911152, 0.07189433],
            ],
            [
                [0.07911152, 0.08705322, 0.08705322, 0.07911152],
                [0.08325771, 0.09161563, 0.09161563, 0.08325771],
                [0.07911152, 0.08705322, 0.08705322, 0.07911152],
            ],
            [
                [0.07911152, 0.08705322, 0.08705322, 0.07911152],
                [0.08325771, 0.09161563, 0.09161563, 0.08325771],
                [0.07911152, 0.08705322, 0.08705322, 0.07911152],
            ],
            [
                [0.07189433, 0.07911152, 0.07911152, 0.07189433],
                [0.07566228, 0.08325771, 0.08325771, 0.07566228],
                [0.07189433, 0.07911152, 0.07911152, 0.07189433],
            ],
        ]]])
        np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-5)
예제 #9
0
    def test_2d(self):
        a = torch.ones(1, 1, 3, 3)
        g = GaussianFilter(2, 3, 3, torch.device('cpu:0'))
        expected = np.array([[[[0.13380532, 0.14087981, 0.13380532],
                               [0.14087981, 0.14832835, 0.14087981],
                               [0.13380532, 0.14087981, 0.13380532]]]])

        np.testing.assert_allclose(g(a).cpu().numpy(), expected)
예제 #10
0
    def test_2d(self):
        a = torch.ones(1, 1, 3, 3)
        g = GaussianFilter(2, 3, 3).to(torch.device("cpu:0"))
        expected = np.array(
            [
                [
                    [
                        [0.13380532, 0.14087981, 0.13380532],
                        [0.14087981, 0.14832835, 0.14087981],
                        [0.13380532, 0.14087981, 0.13380532],
                    ]
                ]
            ]
        )

        np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-5)
        if torch.cuda.is_available():
            g = GaussianFilter(2, 3, 3).to(torch.device("cuda:0"))
            np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-2)
예제 #11
0
 def test_3d_sigmas(self):
     a = torch.ones(1, 1, 4, 3, 2)
     g = GaussianFilter(3, [3, 2, 1], 3).to(torch.device("cpu:0"))
     expected = np.array([[[
         [[0.1422854, 0.1422854], [0.15806103, 0.15806103],
          [0.1422854, 0.1422854]],
         [[0.15668818, 0.15668817], [0.17406069, 0.17406069],
          [0.15668818, 0.15668817]],
         [[0.15668818, 0.15668817], [0.17406069, 0.17406069],
          [0.15668818, 0.15668817]],
         [[0.1422854, 0.1422854], [0.15806103, 0.15806103],
          [0.1422854, 0.1422854]],
     ]]])
     np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-5)
     if torch.cuda.is_available():
         g = GaussianFilter(3, [3, 2, 1], 3).to(torch.device("cuda:0"))
         np.testing.assert_allclose(g(a.cuda()).cpu().numpy(),
                                    expected,
                                    rtol=1e-2)
예제 #12
0
    def _get_signal(self, image, guidance):
        dimensions = 3 if len(image.shape) > 3 else 2
        guidance = guidance.tolist() if isinstance(guidance,
                                                   np.ndarray) else guidance
        guidance = json.loads(guidance) if isinstance(guidance,
                                                      str) else guidance

        # In inference the user may not provide clicks for some channels/labels
        if len(guidance):
            if dimensions == 3:
                # Assume channel is first and depth is last CHWD
                signal = np.zeros(
                    (1, image.shape[-3], image.shape[-2], image.shape[-1]),
                    dtype=np.float32)
            else:
                signal = np.zeros((1, image.shape[-2], image.shape[-1]),
                                  dtype=np.float32)

            sshape = signal.shape
            for point in guidance:  # TO DO: make the guidance a list only - it is currently a list of list
                if np.any(np.asarray(point) < 0):
                    continue

                if dimensions == 3:
                    # Making sure points fall inside the image dimension
                    p1 = max(0, min(int(point[-3]), sshape[-3] - 1))
                    p2 = max(0, min(int(point[-2]), sshape[-2] - 1))
                    p3 = max(0, min(int(point[-1]), sshape[-1] - 1))
                    signal[:, p1, p2, p3] = 1.0
                else:
                    p1 = max(0, min(int(point[-2]), sshape[-2] - 1))
                    p2 = max(0, min(int(point[-1]), sshape[-1] - 1))
                    signal[:, p1, p2] = 1.0

            # Apply a Gaussian filter to the signal
            if np.max(signal[0]) > 0:
                signal_tensor = torch.tensor(signal[0])
                pt_gaussian = GaussianFilter(len(signal_tensor.shape),
                                             sigma=self.sigma)
                signal_tensor = pt_gaussian(
                    signal_tensor.unsqueeze(0).unsqueeze(0))
                signal_tensor = signal_tensor.squeeze(0).squeeze(0)
                signal[0] = signal_tensor.detach().cpu().numpy()
                signal[0] = (signal[0] - np.min(signal[0])) / (
                    np.max(signal[0]) - np.min(signal[0]))
            return signal
        else:
            if dimensions == 3:
                signal = np.zeros(
                    (1, image.shape[-3], image.shape[-2], image.shape[-1]),
                    dtype=np.float32)
            else:
                signal = np.zeros((1, image.shape[-2], image.shape[-1]),
                                  dtype=np.float32)
            return signal
예제 #13
0
 def test_1d(self):
     a = torch.ones(1, 8, 10)
     g = GaussianFilter(1, 3, 3, torch.device('cpu:0'))
     expected = np.array([[
         [
             0.56658804, 0.69108766, 0.79392236, 0.86594427, 0.90267116,
             0.9026711, 0.8659443, 0.7939224, 0.6910876, 0.56658804
         ],
     ]])
     expected = np.tile(expected, (1, 8, 1))
     np.testing.assert_allclose(g(a).cpu().numpy(), expected)
    def test_3d_sigmas(self):
        a = torch.ones(1, 1, 4, 3, 2)
        g = GaussianFilter(3, [3, 2, 1], 3).to(torch.device("cpu:0"))

        expected = np.array([[[
            [[0.13690521, 0.13690521], [0.15181276, 0.15181276],
             [0.13690521, 0.13690521]],
            [[0.1506486, 0.15064861], [0.16705267, 0.16705267],
             [0.1506486, 0.15064861]],
            [[0.1506486, 0.15064861], [0.16705267, 0.16705267],
             [0.1506486, 0.15064861]],
            [[0.13690521, 0.13690521], [0.15181276, 0.15181276],
             [0.13690521, 0.13690521]],
        ]]])
        np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-5)
        if torch.cuda.is_available():
            g = GaussianFilter(3, [3, 2, 1], 3).to(torch.device("cuda:0"))
            np.testing.assert_allclose(g(a.cuda()).cpu().numpy(),
                                       expected,
                                       rtol=1e-2)
 def test_1d(self):
     a = torch.ones(1, 8, 10)
     g = GaussianFilter(1, 3, 3).to(torch.device("cpu:0"))
     expected = np.array([[[
         0.5654129,
         0.68915915,
         0.79146194,
         0.8631974,
         0.8998163,
         0.8998163,
         0.8631973,
         0.79146194,
         0.6891592,
         0.5654129,
     ]]])
     expected = np.tile(expected, (1, 8, 1))
     np.testing.assert_allclose(g(a).cpu().numpy(), expected, rtol=1e-5)
예제 #16
0
파일: utils.py 프로젝트: walehn/MONAI
def extreme_points_to_image(
    points: List[Tuple[int, ...]],
    label: np.ndarray,
    sigma: Union[Sequence[float], float, Sequence[torch.Tensor],
                 torch.Tensor] = 0.0,
    rescale_min: float = -1.0,
    rescale_max: float = 1.0,
):
    """
    Please refer to :py:class:`monai.transforms.AddExtremePointsChannel` for the usage.

    Applies a gaussian filter to the extreme points image. Then the pixel values in points image are rescaled
    to range [rescale_min, rescale_max].

    Args:
        points: Extreme points of the object/organ.
        label: label image to get extreme points from. Shape must be
            (1, spatial_dim1, [, spatial_dim2, ...]). Doesn't support one-hot labels.
        sigma: if a list of values, must match the count of spatial dimensions of input data,
            and apply every value in the list to 1 spatial dimension. if only 1 value provided,
            use it for all spatial dimensions.
        rescale_min: minimum value of output data.
        rescale_max: maximum value of output data.
    """
    # points to image
    points_image = torch.zeros(label.shape[1:], dtype=torch.float)
    for p in points:
        points_image[p] = 1.0

    # add channel and add batch
    points_image = points_image.unsqueeze(0).unsqueeze(0)
    gaussian_filter = GaussianFilter(label.ndim - 1, sigma=sigma)
    points_image = gaussian_filter(points_image).squeeze(0).detach().numpy()

    # rescale the points image to [rescale_min, rescale_max]
    min_intensity = np.min(points_image)
    max_intensity = np.max(points_image)
    points_image = (points_image - min_intensity) / (max_intensity -
                                                     min_intensity)
    points_image = points_image * (rescale_max - rescale_min) + rescale_min
    return points_image
예제 #17
0
파일: array.py 프로젝트: Nic-Ma/MONAI
class ProbNMS(Transform):
    """
    Performs probability based non-maximum suppression (NMS) on the probabilities map via
    iteratively selecting the coordinate with highest probability and then move it as well
    as its surrounding values. The remove range is determined by the parameter `box_size`.
    If multiple coordinates have the same highest probability, only one of them will be
    selected.

    Args:
        spatial_dims: number of spatial dimensions of the input probabilities map.
            Defaults to 2.
        sigma: the standard deviation for gaussian filter.
            It could be a single value, or `spatial_dims` number of values. Defaults to 0.0.
        prob_threshold: the probability threshold, the function will stop searching if
            the highest probability is no larger than the threshold. The value should be
            no less than 0.0. Defaults to 0.5.
        box_size: the box size (in pixel) to be removed around the the pixel with the maximum probability.
            It can be an integer that defines the size of a square or cube,
            or a list containing different values for each dimensions. Defaults to 48.

    Return:
        a list of selected lists, where inner lists contain probability and coordinates.
        For example, for 3D input, the inner lists are in the form of [probability, x, y, z].

    Raises:
        ValueError: When ``prob_threshold`` is less than 0.0.
        ValueError: When ``box_size`` is a list or tuple, and its length is not equal to `spatial_dims`.
        ValueError: When ``box_size`` has a less than 1 value.

    """

    backend = [TransformBackends.TORCH, TransformBackends.NUMPY]

    def __init__(
        self,
        spatial_dims: int = 2,
        sigma: Union[Sequence[float], float, Sequence[torch.Tensor],
                     torch.Tensor] = 0.0,
        prob_threshold: float = 0.5,
        box_size: Union[int, Sequence[int]] = 48,
    ) -> None:
        self.sigma = sigma
        self.spatial_dims = spatial_dims
        if self.sigma != 0:
            self.filter = GaussianFilter(spatial_dims=spatial_dims,
                                         sigma=sigma)
        if prob_threshold < 0:
            raise ValueError("prob_threshold should be no less than 0.0.")
        self.prob_threshold = prob_threshold
        if isinstance(box_size, int):
            self.box_size = np.asarray([box_size] * spatial_dims)
        elif len(box_size) != spatial_dims:
            raise ValueError(
                "the sequence length of box_size should be the same as spatial_dims."
            )
        else:
            self.box_size = np.asarray(box_size)
        if self.box_size.min() <= 0:
            raise ValueError("box_size should be larger than 0.")

        self.box_lower_bd = self.box_size // 2
        self.box_upper_bd = self.box_size - self.box_lower_bd

    def __call__(self, prob_map: NdarrayOrTensor):
        """
        prob_map: the input probabilities map, it must have shape (H[, W, ...]).
        """
        if self.sigma != 0:
            if not isinstance(prob_map, torch.Tensor):
                prob_map = torch.as_tensor(prob_map, dtype=torch.float)
            self.filter.to(prob_map.device)
            prob_map = self.filter(prob_map)

        prob_map_shape = prob_map.shape

        outputs = []
        while prob_map.max() > self.prob_threshold:
            max_idx = unravel_index(prob_map.argmax(), prob_map_shape)
            prob_max = prob_map[tuple(max_idx)]
            max_idx = max_idx.cpu().numpy() if isinstance(
                max_idx, torch.Tensor) else max_idx
            prob_max = prob_max.item() if isinstance(
                prob_max, torch.Tensor) else prob_max
            outputs.append([prob_max] + list(max_idx))

            idx_min_range = (max_idx - self.box_lower_bd).clip(0, None)
            idx_max_range = (max_idx + self.box_upper_bd).clip(
                None, prob_map_shape)
            # for each dimension, set values during index ranges to 0
            slices = tuple(
                slice(idx_min_range[i], idx_max_range[i])
                for i in range(self.spatial_dims))
            prob_map[slices] = 0

        return outputs
 def test_wrong_args(self):
     with self.assertRaisesRegex(ValueError, ""):
         GaussianFilter(3, [3, 2], 3).to(torch.device("cpu:0"))
     GaussianFilter(3, [3, 2, 1], 3).to(torch.device("cpu:0"))  # test init