Coverage for nilearn/_utils/tests/test_segmentation.py: 0%

66 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-20 10:58 +0200

1""" 

2Testing functions for random walker segmentation from scikit-image 0.11.3. 

3 

4Thanks to scikit image. 

5""" 

6 

7import numpy as np 

8import pytest 

9 

10from nilearn._utils.segmentation import random_walker 

11 

12 

13def test_modes_in_random_walker_spacing(rng): 

14 """Smoke test for spacing in random_walker.""" 

15 img = rng.standard_normal(size=(30, 30, 30)) 

16 labels = np.zeros_like(img) 

17 random_walker(img, labels, beta=90, spacing=(3, 3, 3)) 

18 

19 

20def test_modes_in_random_walker(rng): 

21 img = np.zeros((30, 30, 30)) + 0.1 * rng.standard_normal(size=(30, 30, 30)) 

22 img[9:21, 9:21, 9:21] = 1 

23 img[10:20, 10:20, 10:20] = 0 

24 labels = np.zeros_like(img) 

25 labels[6, 6, 6] = 1 

26 labels[14, 15, 16] = 2 

27 # default mode = cg 

28 random_walker_cg = random_walker(img, labels, beta=90) 

29 assert (random_walker_cg.reshape(img.shape)[6, 6, 6] == 1).all() 

30 assert img.shape == random_walker_cg.shape 

31 # test `mask` strategy of sub function _mask_edges_weights in laplacian 

32 labels[5:25, 26:29, 26:29] = -1 

33 random_walker(img, labels, beta=30) 

34 

35 

36def test_isolated_pixel(rng): 

37 data = rng.random((3, 3)) 

38 

39 # Build the following labels with an isolated seed 

40 # in the bottom-right corner: 

41 # array([[ 0., -1., -1.], 

42 # [-1., -1., -1.], 

43 # [-1., -1., 1.]]) 

44 labels = -np.ones((3, 3)) 

45 # Point 

46 labels[0, 0] = 0 

47 # Make a seed 

48 labels[2, 2] = 1 

49 # The expected result is: 

50 # array([[ 0., -1., -1.], 

51 # [-1., -1., -1.], 

52 # [-1., -1., 1.]]) 

53 expected = np.array( 

54 [[0.0, -1.0, -1.0], [-1.0, -1.0, -1.0], [-1.0, -1.0, 1.0]] 

55 ) 

56 np.testing.assert_array_equal(expected, random_walker(data, labels)) 

57 

58 

59def test_isolated_seed(rng): 

60 data = rng.random((3, 3)) 

61 

62 # Build the following labels with an isolated seed 

63 # in the bottom-right corner: 

64 # array([[ 0., 1., -1.], 

65 # [-1., -1., -1.], 

66 # [-1., -1., 2.]]) 

67 labels = -np.ones((3, 3)) 

68 # Make a seed 

69 labels[0, 1] = 1 

70 # Point next to the seed 

71 labels[0, 0] = 0 

72 # Set a seed in the middle, it is surrounded by masked pixels 

73 labels[2, 2] = 2 

74 # The expected result is: 

75 # array([[ 1., 1., -1.], 

76 # [-1., -1., -1.], 

77 # [-1., -1., -1.]]) 

78 expected = np.array( 

79 [[1.0, 1.0, -1.0], [-1.0, -1.0, -1.0], [-1.0, -1.0, -1.0]] 

80 ) 

81 np.testing.assert_array_equal(expected, random_walker(data, labels)) 

82 

83 

84def test_trivial_cases(): 

85 # When all voxels are labeled 

86 img = np.ones((10, 10, 10)) 

87 labels = np.ones((10, 10, 10)) 

88 

89 # It returns same labels which are provided 

90 pass_through = random_walker(img, labels) 

91 np.testing.assert_array_equal(pass_through, labels) 

92 

93 # When there is no seed 

94 # Case 1: only masked pixels 

95 labels = -np.ones((10, 10, 10)) 

96 # It returns the labels 

97 np.testing.assert_array_equal(random_walker(img, labels), labels) 

98 

99 # Case 2: only unlabeled pixels 

100 labels = np.zeros((10, 10, 10)) 

101 # It return the labels 

102 np.testing.assert_array_equal(random_walker(img, labels), labels) 

103 

104 

105def test_bad_inputs(rng): 

106 # Too few dimensions 

107 img = np.ones(10) 

108 labels = np.arange(10) 

109 with pytest.raises(ValueError): 

110 random_walker(img, labels) 

111 

112 # Too many dimensions 

113 img = rng.normal(size=(3, 3, 3, 3, 3)) 

114 labels = np.arange(3**5).reshape(img.shape) 

115 with pytest.raises(ValueError): 

116 random_walker(img, labels) 

117 

118 # Spacing incorrect length 

119 img = rng.normal(size=(10, 10)) 

120 labels = np.zeros((10, 10)) 

121 labels[2, 4] = 2 

122 labels[6, 8] = 5 

123 with pytest.raises(ValueError): 

124 random_walker(img, labels, spacing=(1,)) 

125 

126 

127def test_reorder_labels(rng): 

128 """When labels have non-consecutive integers, make them consecutive by \ 

129 reordering them to make no gaps/differences between integers. 

130 

131 We expect labels to be of same shape even if they are reordered. 

132 

133 Issue #938, comment #14. 

134 """ 

135 data = np.zeros((5, 5)) + 0.1 * rng.standard_normal(size=(5, 5)) 

136 data[1:5, 1:5] = 1 

137 

138 labels = np.zeros_like(data) 

139 labels[3, 3] = 1 

140 labels[1, 4] = 4 # giving integer which is non-consecutive 

141 

142 labels = random_walker(data, labels) 

143 assert data.shape == labels.shape