xttmp 2.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. xttmp/__init__.py +1 -0
  2. xttmp/api/__init__.py +5 -0
  3. xttmp/api/evaluate.py +163 -0
  4. xttmp/api/get_visualize_handle.py +29 -0
  5. xttmp/api/instancing_model.py +35 -0
  6. xttmp/core/__init__.py +0 -0
  7. xttmp/core/apgstmd_core.py +188 -0
  8. xttmp/core/apgstmdv2_core.py +79 -0
  9. xttmp/core/base_core.py +36 -0
  10. xttmp/core/dstmd_core.py +213 -0
  11. xttmp/core/estmd_backbone.py +110 -0
  12. xttmp/core/estmd_core.py +356 -0
  13. xttmp/core/feedbackstmd_core.py +61 -0
  14. xttmp/core/fracstmd_core.py +98 -0
  15. xttmp/core/fstmd_core.py +15 -0
  16. xttmp/core/fstmdv2_core.py +42 -0
  17. xttmp/core/haarstmd_core.py +140 -0
  18. xttmp/core/math_operator.py +307 -0
  19. xttmp/core/stfeedbackstmd_core.py +233 -0
  20. xttmp/core/stmdplus_core.py +187 -0
  21. xttmp/core/stmdplusv2_core.py +82 -0
  22. xttmp/core/vstmd_core.py +420 -0
  23. xttmp/demo/evaluate_model.py +92 -0
  24. xttmp/demo/inference_gui.py +148 -0
  25. xttmp/demo/inference_gui_single_process.py +134 -0
  26. xttmp/demo/inference_image_stream.py +67 -0
  27. xttmp/demo/inference_video.py +66 -0
  28. xttmp/main.py +14 -0
  29. xttmp/model/__init__.py +13 -0
  30. xttmp/model/backbone.py +514 -0
  31. xttmp/model/facilitated_model.py +230 -0
  32. xttmp/model/feedback_model.py +271 -0
  33. xttmp/model/haarstmd.py +61 -0
  34. xttmp/model/vstmd.py +457 -0
  35. xttmp/util/__init__.py +0 -0
  36. xttmp/util/compute_module.py +402 -0
  37. xttmp/util/create_kernel.py +363 -0
  38. xttmp/util/evaluate_module.py +697 -0
  39. xttmp/util/iostream.py +660 -0
  40. xttmp-2.3.0.dist-info/METADATA +85 -0
  41. xttmp-2.3.0.dist-info/RECORD +45 -0
  42. xttmp-2.3.0.dist-info/WHEEL +5 -0
  43. xttmp-2.3.0.dist-info/entry_points.txt +2 -0
  44. xttmp-2.3.0.dist-info/licenses/LICENSE +201 -0
  45. xttmp-2.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,363 @@
1
+ import math
2
+
3
+ import numpy as np
4
+ import torch
5
+
6
+
7
+ def create_2d_gaussian_kernel(size, sigma):
8
+ # 处理参数 (简化防御性编程,假设输入已经是合法的 int 或 tuple)
9
+ sy, sx = (size, size) if isinstance(size, int) else size
10
+ sig_y, sig_x = (sigma, sigma) if isinstance(sigma, (int, float)) else sigma
11
+
12
+ # 生成 1D 坐标
13
+ y = torch.arange(sy, dtype=torch.float32) - sy // 2
14
+ x = torch.arange(sx, dtype=torch.float32) - sx // 2
15
+
16
+ # 生成 2D 网格坐标 (yy 和 xx 都是 size 形状的矩阵)
17
+ yy, xx = torch.meshgrid(y, x, indexing='ij')
18
+
19
+ # 直接将 2D 坐标代入二维高斯公式(一眼就能看懂的数学表达)
20
+ kernel = torch.exp(-(xx**2 / (2 * sig_x**2) + yy**2 / (2 * sig_y**2)))
21
+
22
+ # 归一化并调整形状
23
+ kernel /= kernel.sum()
24
+ return kernel.view(1, 1, sy, sx)
25
+
26
+
27
+ def create_gamma_kernel(order, tau, length):
28
+ t = torch.arange(length, dtype=torch.float32)
29
+
30
+ # 避免 t=0 时 log(0) 报错,加一个极小的值 eps
31
+ t_safe = torch.clamp(t, min=1e-7)
32
+
33
+ fact = math.factorial(order - 1)
34
+
35
+ # 计算对数域下的结果 (Log Domain)
36
+ # ln(kernel) = order * ln(order * t / tau) - (order * t / tau) - ln(tau * fact)
37
+ log_kernel = (order * torch.log(order * t_safe / tau)
38
+ - (order * t_safe / tau)
39
+ - math.log(tau * float(fact)))
40
+
41
+ # 还原回线性域
42
+ kernel = torch.exp(log_kernel)
43
+
44
+ # 修正 t=0 时的真实值
45
+ kernel[0] = 0.0
46
+
47
+ return kernel.view(-1, 1, 1, 1)
48
+
49
+
50
+ def create_spatial_inhibition_kernel(kernel_size=15,
51
+ sigma1=1.5,
52
+ sigma2=3,
53
+ e=1.,
54
+ rho=0,
55
+ A=1,
56
+ B=3):
57
+
58
+
59
+ coords = torch.arange(kernel_size, dtype=torch.float32) - kernel_size // 2
60
+ y, x = torch.meshgrid(coords, coords, indexing='ij')
61
+
62
+ # 计算欧式距离矩阵
63
+ r = torch.sqrt(x**2 + y**2)
64
+
65
+ # 计算双高斯分布 (Difference of Gaussians 的变体)
66
+ # g1 为中心兴奋 (Center),g2 为周边抑制 (Surround)
67
+ g1 = torch.exp(-(r**2) / (2 * sigma1**2)) / (2 * torch.pi * sigma1**2)
68
+ g2 = torch.exp(-(r**2) / (2 * sigma2**2)) / (2 * torch.pi * sigma2**2)
69
+
70
+ g = g1 - e * g2 - rho
71
+
72
+ kernel = A * g.clamp(min=0) + B * g.clamp(max=0)
73
+
74
+ return kernel / kernel.max()
75
+
76
+
77
+ def create_direction_inhi_kernel(KernelSize=8, Sigma1=1.5, Sigma2=3.0):
78
+ """
79
+ Function Description:
80
+ This function generates lateral inhibition kernels along the Theta direction using PyTorch.
81
+ We adopt a one-dimensional DoG as the lateral inhibition kernel function here.
82
+ """
83
+ # 确保输入参数为浮点数张量,以便进行数学运算
84
+ s1 = torch.tensor(Sigma1, dtype=torch.float32)
85
+ s2 = torch.tensor(Sigma2, dtype=torch.float32)
86
+
87
+ # Sampling for DoG
88
+ zero_point_factor = (torch.log(s2 / s1) * 2 * (s1**2) * (s2**2)) / (s2**2 - s1**2)
89
+ Zero_Point_DoG_X1 = -torch.sqrt(zero_point_factor)
90
+ Zero_Point_DoG_X2 = -Zero_Point_DoG_X1
91
+
92
+ Min_Point_DoG_X1 = -torch.sqrt(3 * zero_point_factor)
93
+ Min_Point_DoG_X2 = -Min_Point_DoG_X1
94
+
95
+ if KernelSize % 2 == 0:
96
+ KernelSize += 1
97
+
98
+ Half_Kernel_Size = (KernelSize - 1) // 2
99
+ Quarter_Kernel_Size = (KernelSize - 1) // 4
100
+
101
+ Center_Range_DoG = Zero_Point_DoG_X2 - Zero_Point_DoG_X1
102
+ Center_Step = Center_Range_DoG / Half_Kernel_Size
103
+
104
+ Surround_Range_DoG = Min_Point_DoG_X2 - Zero_Point_DoG_X2
105
+ Surround_Step = 2 * Surround_Range_DoG / Quarter_Kernel_Size
106
+
107
+ # 使用 torch.arange 替换 np.arange
108
+ # 注意:为了让步长乘法正确应用,arange 生成的序列需要显式指定为 float 类型
109
+ X_Smaller = Zero_Point_DoG_X1 - torch.arange(Quarter_Kernel_Size, 0, -1, dtype=torch.float32) * Surround_Step
110
+ X_Larger = Zero_Point_DoG_X2 + torch.arange(1, Quarter_Kernel_Size + 1, 1, dtype=torch.float32) * Surround_Step
111
+ X_Center = Zero_Point_DoG_X1 + torch.arange(0, Half_Kernel_Size + 1, dtype=torch.float32) * Center_Step
112
+
113
+ # 使用 torch.cat 替换 np.concatenate
114
+ X = torch.cat((X_Smaller, X_Center, X_Larger))
115
+
116
+ # 计算高斯分布
117
+ pi_tensor = torch.tensor(torch.pi)
118
+ Gauss1 = torch.exp(-(X**2) / (2 * s1**2)) / (2 * pi_tensor * s1**2)
119
+ Gauss2 = torch.exp(-(X**2) / (2 * s2**2)) / (2 * pi_tensor * s2**2)
120
+ Inhibition_Kernel = Gauss1 - Gauss2
121
+
122
+ # 阈值置零
123
+ Inhibition_Kernel[torch.abs(Inhibition_Kernel) < 1e-4] = 0
124
+
125
+ # 使用 torch.reshape 改变形状
126
+ directionalInhiKernel = torch.reshape(Inhibition_Kernel, (1, 1, KernelSize))
127
+
128
+ return directionalInhiKernel
129
+
130
+
131
+ def create_T1_kernels(filterNum=4,
132
+ alpha=3.0,
133
+ eta=1.5,
134
+ filterSize=11,
135
+ device='cpu'):
136
+ """
137
+ Generate T1 kernels (Difference of Gaussians) using pure PyTorch.
138
+
139
+ Returns:
140
+ torch.Tensor: A tensor of shape (filterNum, filterSize, filterSize)
141
+ """
142
+ # If the filter size is even, force it to be odd
143
+ if filterSize % 2 == 0:
144
+ filterSize += 1
145
+
146
+ # 1. Compute angles for each filter
147
+ # 形状: (filterNum,) -> 例如 [0, pi/4, pi/2, 3pi/4]
148
+ Theta = torch.arange(filterNum, dtype=torch.float32, device=device) * torch.pi / filterNum
149
+
150
+ # 2. Generate coordinates
151
+ r = filterSize // 2
152
+ x_coords = torch.arange(-r, r + 1, dtype=torch.float32, device=device)
153
+ y_coords = torch.arange(r, -r - 1, -1, dtype=torch.float32, device=device)
154
+
155
+ # indexing='xy' 保证了与 numpy.meshgrid 默认行为完全一致
156
+ X, Y = torch.meshgrid(x_coords, y_coords, indexing='xy')
157
+
158
+ # 3. 维度扩展以支持批量(向量化)计算
159
+ # 将 X, Y 扩展为 (1, filterSize, filterSize)
160
+ X = X.unsqueeze(0)
161
+ Y = Y.unsqueeze(0)
162
+
163
+ # 将 Theta 扩展为 (filterNum, 1, 1)
164
+ Theta = Theta.view(-1, 1, 1)
165
+
166
+ # 4. 向量化计算偏移量 (X1, Y1, X2, Y2)
167
+ # 利用广播机制,这里会生成形状为 (filterNum, filterSize, filterSize) 的张量
168
+ cos_theta = torch.cos(Theta)
169
+ sin_theta = torch.sin(Theta)
170
+
171
+ X1 = X - alpha * cos_theta
172
+ Y1 = Y - alpha * sin_theta
173
+
174
+ X2 = X + alpha * cos_theta
175
+ Y2 = Y + alpha * sin_theta
176
+
177
+ # 5. 生成高斯分布
178
+ coeff = 1 / (2 * torch.pi * eta**2)
179
+ gauss1 = coeff * torch.exp(-(X1**2 + Y1**2) / (2 * eta**2))
180
+ gauss2 = coeff * torch.exp(-(X2**2 + Y2**2) / (2 * eta**2))
181
+
182
+ # 6. 计算差值 (最终的滤波器)
183
+ # 形状: (filterNum, filterSize, filterSize)
184
+ dictKernel = gauss1 - gauss2
185
+
186
+ # 如果你坚持需要返回 list,可以取消下面这行的注释:
187
+ # return list(dictKernel)
188
+
189
+ return dictKernel.unsqueeze(1) # 返回形状为 (filterNum, 1, filterSize, filterSize) 的张量
190
+
191
+
192
+ def create_fracdiff_kernel(alpha=0.8, wide=3):
193
+ """
194
+ Generates a fractional difference kernel.
195
+
196
+ Parameters:
197
+ - alpha: The fractional difference parameter.
198
+ - wide: The width of the kernel.
199
+
200
+ Returns:
201
+ - frackernel: The fractional difference kernel.
202
+ """
203
+ # Ensure the width is at least 2
204
+ if wide < 2:
205
+ wide = 2
206
+
207
+ # Initialize the kernel
208
+ frackernel = torch.zeros(wide, dtype=torch.float32)
209
+
210
+ # Generate the kernel based on alpha
211
+ if alpha == 1:
212
+ frackernel[0] = 1
213
+ elif 0 < alpha < 1:
214
+ t_list = torch.arange(wide)
215
+ frackernel = torch.exp(-alpha * t_list / (1 - alpha)) / (1 - alpha)
216
+
217
+ # Normalize the kernel
218
+ sum_kernel = torch.sum(frackernel) # 1/M(\alpha)
219
+ frackernel = frackernel / sum_kernel
220
+ frackernel[frackernel < 1e-16] = 0
221
+ else:
222
+ raise ValueError("Alpha must be in the interval (0,1].")
223
+
224
+ return frackernel
225
+
226
+
227
+ def create_attention_kernel(kernel_size=17,
228
+ zeta=[2, 2.5, 3, 3.5],
229
+ theta=[0, math.pi/4, math.pi/2, math.pi*3/4],
230
+ device='cpu',
231
+ dtype=torch.float32):
232
+ """
233
+ Creates attention kernels using PyTorch.
234
+
235
+ Parameters:
236
+ - kernel_size: Size of the kernel.
237
+ - zeta: List of zeta values.
238
+ - theta: List of theta values.
239
+ - device: Target device for the tensors (e.g., 'cpu', 'cuda').
240
+ - dtype: Data type for the tensors.
241
+
242
+ Returns:
243
+ - attention_kernel: 2D list containing attention kernels as PyTorch tensors.
244
+ """
245
+
246
+ # 调整 kernel size(如果是偶数则加 1)
247
+ if kernel_size % 2 == 0:
248
+ kernel_size += 1
249
+
250
+ # 初始化存储 attention kernels 的二维列表
251
+ r = len(zeta)
252
+ s = len(theta)
253
+ attention_kernel = [[None] * s for _ in range(r)]
254
+
255
+ # 计算 kernel 中心点
256
+ center = (kernel_size - 1) / 2
257
+
258
+ # 生成网格坐标 (注意 dtype 和 device 的传递)
259
+ x = torch.arange(kernel_size, dtype=dtype, device=device) - center
260
+ y = torch.arange(kernel_size, 0, -1, dtype=dtype, device=device) - center
261
+
262
+ # PyTorch 的 meshgrid 需要明确指定 indexing='xy' 以对齐 NumPy 的默认行为
263
+ shift_x, shift_y = torch.meshgrid(x, y, indexing='xy')
264
+
265
+ # 为每种 Zeta 和 Theta 的组合生成 attention kernels
266
+ for i in range(r):
267
+ for j in range(s):
268
+ # 将标量转换为 float 进行计算
269
+ z_val = float(zeta[i])
270
+ t_val = float(theta[j])
271
+
272
+ # 预计算三角函数以提升效率
273
+ cos_val = math.cos(t_val + math.pi / 2)
274
+ sin_val = math.sin(t_val + math.pi / 2)
275
+
276
+ # 生成核公式
277
+ term1 = 2 / math.pi / (z_val ** 4)
278
+ term2 = z_val ** 2 - (shift_x * cos_val + shift_y * sin_val) ** 2
279
+ term3 = torch.exp(-(shift_x ** 2 + shift_y ** 2) / (2 * z_val ** 2))
280
+
281
+ attention_kernel_with_ij = term1 * term2 * term3
282
+
283
+ # 阈值过滤 (使用 torch.abs)
284
+ attention_kernel_with_ij[torch.abs(attention_kernel_with_ij) < 1e-4] = 0
285
+
286
+ # 翻转卷积核 (对应 NumPy 中的 axis=0 和 axis=1)
287
+ attention_kernel_with_ij = torch.flip(attention_kernel_with_ij, dims=[0, 1])
288
+
289
+ attention_kernel[i][j] = attention_kernel_with_ij
290
+
291
+ return attention_kernel
292
+
293
+
294
+ def create_prediction_kernel(Vel=0.25,
295
+ Delta_t=25,
296
+ filter_size=25,
297
+ FilterNum=8,
298
+ zeta=2,
299
+ eta=2.5,
300
+ device='cpu',
301
+ dtype=torch.float32):
302
+ """
303
+ Creates prediction kernels for motion detection using PyTorch.
304
+
305
+ Parameters:
306
+ - Vel: Velocity of the moving object.
307
+ - Delta_t: Time interval.
308
+ - filter_size: Size of the filter.
309
+ - FilterNum: Number of filters.
310
+ - zeta: Zeta parameter.
311
+ - eta: Eta parameter.
312
+ - device: Target device for the tensors (e.g., 'cpu', 'cuda').
313
+ - dtype: Data type for the tensors.
314
+
315
+ Returns:
316
+ - PredictionKernal: List containing prediction kernels as PyTorch tensors.
317
+ """
318
+
319
+ # 初始化存储 prediction kernels 的列表
320
+ PredictionKernal = []
321
+
322
+ # 计算中心点
323
+ Center = (filter_size - 1) / 2
324
+
325
+ # 生成网格坐标 (与 NumPy 的 meshgrid 对齐)
326
+ x = torch.arange(filter_size, dtype=dtype, device=device) - Center
327
+ y = torch.arange(filter_size, 0, -1, dtype=dtype, device=device) - Center
328
+ ShiftX, ShiftY = torch.meshgrid(x, y, indexing='xy')
329
+
330
+ # 计算角度 (注意 torch.atan2 的参数顺序与 np.arctan2 一致,都是 y, x)
331
+ fai = torch.atan2(ShiftY, ShiftX)
332
+
333
+ # 计算 Delta X 和 Delta Y
334
+ Delta_X = Vel * Delta_t * torch.cos(fai)
335
+ Delta_Y = Vel * Delta_t * torch.sin(fai)
336
+
337
+ # 生成每个方向的 prediction kernels
338
+ for idx in range(FilterNum):
339
+ # 严格遵循原代码逻辑:(idx - 1)
340
+ theta = (idx - 1) * 2 * torch.pi / FilterNum
341
+
342
+ # 计算指数项
343
+ PredictionKernalWithIdx = torch.exp(
344
+ -((ShiftX - Delta_X) ** 2 + (ShiftY - Delta_Y) ** 2) / (2 * zeta ** 2)
345
+ + eta * torch.cos(fai - theta)
346
+ )
347
+
348
+ # 第一次归一化
349
+ PredictionKernalWithIdx = PredictionKernalWithIdx / torch.sum(PredictionKernalWithIdx)
350
+
351
+ # 阈值过滤以加速计算
352
+ PredictionKernalWithIdx[PredictionKernalWithIdx < 5e-4] = 0
353
+
354
+ # 第二次归一化
355
+ PredictionKernalWithIdx /= torch.sum(PredictionKernalWithIdx)
356
+
357
+ # 翻转卷积核 (对应 np.flip axis=0 和 axis=1)
358
+ PredictionKernalWithIdx = torch.flip(PredictionKernalWithIdx, dims=[0, 1])
359
+
360
+ PredictionKernal.append(PredictionKernalWithIdx)
361
+
362
+ return PredictionKernal
363
+