Coverage for tests/test_repr.py: 100%

120 statements  

« prev     ^ index     » next       coverage.py v7.15.1, created at 2026-07-15 09:33 +0000

1import numpy as np 

2import pytest 

3 

4from evutils.types import Event_dtype 

5from evutils.repr import ( 

6 timesurface, 

7 voxel_histogram, 

8 histogram, 

9 wedge_histogram, 

10 frame_diff, 

11 frame_rgb, 

12 frame_gray, 

13 tore 

14) 

15 

16def create_events(data): 

17 events = np.zeros(len(data), dtype=Event_dtype) 

18 for i, (t, x, y, p) in enumerate(data): 

19 events[i]['t'] = t 

20 events[i]['x'] = x 

21 events[i]['y'] = y 

22 events[i]['p'] = p 

23 return events 

24 

25def test_timesurface(): 

26 events = create_events([(100, 10, 20, 1), (200, 15, 25, 0)]) 

27 ts = timesurface(events, width=100, height=50, tau=100) 

28 assert ts.shape == (50, 100) 

29 assert ts[20, 10] == pytest.approx(np.exp(-(200 - 100) / 100.0)) 

30 assert ts[25, 15] == pytest.approx(-1.0) 

31 

32def test_timesurface_empty(): 

33 events = create_events([]) 

34 ts = timesurface(events, width=100, height=50) 

35 assert ts.shape == (50, 100) 

36 assert np.all(ts == 0) 

37 

38def test_voxel_histogram(): 

39 events = create_events([(100, 10, 20, 1), (150, 15, 25, 0), (200, 10, 20, 1)]) 

40 vh = voxel_histogram(events, width=100, height=50, n_bins=2, dt=100) 

41 assert vh.shape == (2, 50, 100, 3) 

42 

43def test_voxel_histogram_empty(): 

44 events = create_events([]) 

45 vh = voxel_histogram(events, width=100, height=50, n_bins=10, dt=1000) 

46 assert vh.shape == (10, 50, 100, 3) 

47 assert np.all(vh == 0) 

48 

49def test_voxel_histogram_less_than_3_events(): 

50 events = create_events([(100, 10, 20, 1), (150, 15, 25, 0)]) 

51 vh = voxel_histogram(events, width=100, height=50, n_bins=2, dt=100) 

52 assert vh.shape == (2, 50, 100, 3) 

53 assert np.all(vh == 0) 

54 

55def test_voxel_histogram_exceeds_dt(): 

56 events = create_events([(100, 10, 20, 1), (150, 15, 25, 0), (250, 10, 20, 1)]) 

57 with pytest.raises(AssertionError): 

58 voxel_histogram(events, width=100, height=50, n_bins=2, dt=100) 

59 

60def test_histogram(): 

61 events = create_events([(100, 10, 20, 1), (200, 15, 25, 0), (250, 10, 20, 1)]) 

62 h = histogram(events, width=100, height=50, fill=False) 

63 assert h.shape == (50, 100, 3) 

64 assert h[20, 10, 0] == 2 # Red channel for p=1 

65 assert h[25, 15, 2] == 1 # Blue channel for p=0 

66 

67def test_histogram_empty(): 

68 events = create_events([]) 

69 h = histogram(events, width=100, height=50) 

70 assert h.shape == (50, 100, 3) 

71 assert np.all(h == 0) 

72 

73def test_histogram_fill(): 

74 events = create_events([(100, 10, 20, 1)]) 

75 h = histogram(events, width=100, height=50, fill=True) 

76 assert h.shape == (50, 100, 3) 

77 assert h[20, 10, 0] == 255 

78 

79def test_wedge_histogram(): 

80 events = create_events([(100, 10, 20, 1), (200, 15, 25, 0)]) 

81 wh = wedge_histogram(events, width=100, height=50, tl=300) 

82 assert wh.shape == (50, 100, 3) 

83 

84def test_frame_diff(): 

85 events = create_events([(100, 10, 20, 1), (150, 15, 25, 0), (200, 10, 20, 1)]) 

86 fd = frame_diff(events, width=100, height=50) 

87 assert fd.shape == (50, 100) 

88 assert fd[20, 10] == 2 

89 assert fd[25, 15] == -1 

90 

91def test_frame_diff_empty(): 

92 events = create_events([]) 

93 fd = frame_diff(events, width=100, height=50) 

94 assert fd.shape == (50, 100) 

95 assert np.all(fd == 0) 

96 

97def test_frame_rgb(): 

98 events = create_events([(100, 10, 20, 1), (150, 15, 25, 0)]) 

99 frgb = frame_rgb(events, width=100, height=50) 

100 assert frgb.shape == (50, 100, 3) 

101 assert np.array_equal(frgb[20, 10], [255, 0, 0]) 

102 assert np.array_equal(frgb[25, 15], [0, 0, 255]) 

103 assert np.array_equal(frgb[0, 0], [0, 0, 0]) 

104 

105def test_frame_gray(): 

106 events = create_events([(100, 10, 20, 1), (150, 15, 25, 0)]) 

107 fg = frame_gray(events, width=100, height=50) 

108 assert fg.shape == (50, 100) 

109 assert fg[20, 10] == 255 

110 assert fg[25, 15] == 0 

111 assert fg[0, 0] == 128 

112 

113def test_tore(): 

114 events = create_events([(100, 10, 20, 1), (150, 15, 25, 0), (200, 10, 20, 1)]) 

115 t = tore(events, width=100, height=50, n_events=2, tau=100) 

116 assert t.shape == (50, 100, 2, 2) 

117 assert t[20, 10, 1, 1] == pytest.approx(1.0) 

118 assert t[20, 10, 0, 1] == pytest.approx(np.exp(-1.0)) 

119 

120def test_tore_empty(): 

121 events = create_events([]) 

122 t = tore(events, width=100, height=50, n_events=4) 

123 assert t.shape == (50, 100, 4, 2) 

124 assert np.all(t == 0) 

125 

126 

127# --- saturation / overflow edge cases (branch coverage) -------------------- 

128 

129def test_histogram_saturation(): 

130 """A uint8 histogram bin clips at 255 instead of overflowing.""" 

131 events = create_events([(i, 10, 20, 1) for i in range(300)]) # 300 hits, one pixel 

132 h = histogram(events, width=100, height=50, fill=False) 

133 assert h[20, 10, 0] == 255 # capped, not wrapped to 300 % 256 

134 

135 

136def test_wedge_histogram_saturation(): 

137 """A wedge bin saturates: a second selected hit on the same pixel is not 

138 added once the bin is already at 255.""" 

139 events = create_events([(100, 10, 20, 1), (200, 10, 20, 1)]) 

140 wh = wedge_histogram(events, width=100, height=50, tl=300) 

141 assert wh[20, 10, 0] == 255 # single 255, second hit skipped 

142 

143 

144def test_tore_fifo_overflow(): 

145 """With more events than n_events on one pixel/polarity, the oldest fall out 

146 of the FIFO; only the most recent n_events survive.""" 

147 events = create_events([(100, 10, 20, 1), (150, 10, 20, 1), (200, 10, 20, 1)]) 

148 t = tore(events, width=100, height=50, n_events=2, tau=100) 

149 assert t.shape == (50, 100, 2, 2) 

150 # newest (t=200) at slot 1, second-newest (t=150) at slot 0; t=100 dropped. 

151 assert t[20, 10, 1, 1] == pytest.approx(1.0) 

152 assert t[20, 10, 0, 1] == pytest.approx(np.exp(-0.5)) 

153 

154 

155def test_voxel_histogram_more_windows_than_bins(): 

156 """Extra time windows beyond n_bins are dropped (the loop breaks). Span 

157 0..100 at bin_dt=50 yields 3 windows, one more than n_bins=2.""" 

158 events = create_events([(0, 10, 20, 1), (50, 11, 21, 0), (100, 12, 22, 1)]) 

159 vh = voxel_histogram(events, width=100, height=50, n_bins=2, dt=100) 

160 assert vh.shape == (2, 50, 100, 3) 

161 

162 

163def test_voxel_histogram_fewer_windows_than_bins(): 

164 """Fewer time windows than n_bins: the loop exhausts normally (no break), 

165 leaving the trailing bins zero. Span 20 at bin_dt=1000 is a single window.""" 

166 events = create_events([(0, 10, 20, 1), (10, 11, 21, 0), (20, 12, 22, 1)]) 

167 vh = voxel_histogram(events, width=100, height=50, n_bins=10, dt=10000) 

168 assert vh.shape == (10, 50, 100, 3) 

169 assert np.all(vh[1:] == 0) # only the first window populated