使用例子

在本节教程中,我们将示范如何使用提供的接口结合数据集实现各种任务。所有测试例子都可在examples目录下找到对应脚本。

注意:在进行测试前,请先确保本地项目目录SpikeCV.spkData.datasets下有已经解压的对应数据集,并且指定数据时需具体指定到场景名称。

超高速运动场景纹理重构算法

TFI重构算法

使用recVidarReal2019数据集中的汽车高速行驶的场景序列car-100kmh进行重构,对应的测试脚本为test_tfi.py,其数据读取的过程与上述TFP重构算法的数据读取相同

使用spkProc.reconstruction.tfp.TFP进行重构并将结果输出保存至视频文件

device = torch.device('cpu')
reconstructor = TFP(paraDict.get('spike_h'), paraDict.get('spike_w'), device)

st = time.time()
recImg = reconstructor.spikes2images(spikes, half_win_length=20)
ed = time.time()
print('shape: ', recImg.shape, 'time: {:.6f}'.format(ed - st))


filename = path.split_path_into_pieces(data_filename)
if not os.path.exists('results'):
    os.makedirs('results')

result_filename = os.path.join('results', filename[-1] + '_tfp.avi')
obtain_reconstruction_video(recImg, result_filename, **paraDict)

重构结果:

car-100kmh_tfi

TFP重构算法

使用recVidarReal2019数据集中的汽车高速行驶的场景序列car-100kmh进行重构,对应的测试脚本为test_tfp.py,其具体实现过程为:

import os
import torch
import sys
sys.path.append("..")

import time

from spkData.load_dat import data_parameter_dict
from spkData.load_dat import SpikeStream
from spkProc.reconstruction.tfp import TFP
from visualization.get_video import obtain_reconstruction_video
from utils import path

# 指定数据序列及任务类型
data_filename = "recVidarReal2019/classA/car-100kmh"
label_type = 'raw'

# 加载数据集属性字典
paraDict = data_parameter_dict(data_filename, label_type)

#加载脉冲数据
vidarSpikes = SpikeStream(**paraDict)

block_len = 500
spikes = vidarSpikes.get_block_spikes(begin_idx=0, block_len=block_len)

使用spkProc.reconstruction.tfp.TFP进行重构并将结果输出保存至视频文件

device = torch.device('cpu')
reconstructor = TFP(paraDict.get('spike_h'), paraDict.get('spike_w'), device)

st = time.time()
recImg = reconstructor.spikes2images(spikes, half_win_length=20)
ed = time.time()
print('shape: ', recImg.shape, 'time: {:.6f}'.format(ed - st))


filename = path.split_path_into_pieces(data_filename)
if not os.path.exists('results'):
    os.makedirs('results')

result_filename = os.path.join('results', filename[-1] + '_tfp.avi')
obtain_reconstruction_video(recImg, result_filename, **paraDict)

重构结果:

car-100kmh_tfp

TFSTP重构算法

使用recVidarReal2019数据集中的汽车高速行驶的场景序列car-100kmh进行重构,对应的测试脚本为test_tfstp.py,其具体实现过程为:

import os, sys
import torch
sys.path.append('..')

from spkData.load_dat import data_parameter_dict
from spkData.load_dat import SpikeStream
from spkProc.reconstruction.tfstp import TFSTP
from visualization.get_video import obtain_reconstruction_video
from utils import path
from pprint import pprint

# 指定数据序列及任务类型
data_filename = 'recVidarReal2019/classA/car-100kmh'
label_type = 'raw' # 没有标签数据的数据集,任务类型只能指定为raw

# 加载数据集属性字典
paraDict = data_parameter_dict(data_filename, label_type)
pprint(paraDict)

#加载脉冲数据
vidarSpikes = SpikeStream(**paraDict)
block_len = 1500
spikes = vidarSpikes.get_block_spikes(begin_idx=500, block_len=block_len)

数据集记载成功后终端会输出:

{'filepath': '..\\spkData\\datasets\\recVidarReal2019\\classA\\car-100kmh',
 'spike_h': 250,
 'spike_w': 400}
loading total spikes from dat file -- spatial resolution: 400 x 250, begin index: 500 total timestamp: 1500

使用spkProc.reconstruction.tfstp.TFSTP进行重构并将结果输出保存至视频文件

device = torch.device('cuda')
reconstructor = TFSTP(paraDict.get('spike_h'), paraDict.get('spike_w'), device)
recImg = reconstructor.spikes2images_offline(spikes)

filename = path.split_path_info_pieces(data_filename)
if not os.path.exists('results'):
    os.makedirs('results')

result_filename = os.path.join('results', filename[-1] + '_tfstp.avi')
obtain_reconstruction_videos(recImg, result_filename, **paraDict)

重构结果:

car-100kmh_tfstp

SSML重构算法

example中的train_ssml_recon.pytest_ssml_recon.py分别提供了SSML_ReconNet网络训练与测试的样例。

其中,测试时,直接读取.dat文件,截取41个时间步送入预训练网络,即可生成对其中心帧的重构图。

训练时,需要准备数据集文件夹。文件夹结构按照dataset_name\input\*.dat的形式组织。调整训练文件的参数,或者直接运行训练文件以默认参数进行训练。由于SSML重构算法用于没有GroundTruth的真实场景重构,所以没有PSNR指标。用户可以在若干小时后使用保存的中间模型权重来进行测试,查看是否达到了预期的重构结果。

SRR超分重构算法

example中的test_SRR.py提供了SRR_moedl网络测试的样例。

本算法需要安装 Pyflow(https://github.com/pathak22/pyflow)依赖库,用于计算光流。

克隆仓库后,执行以下命令:(对于Windows系统,还需要将pyflow/src/project.h中的 #define _LINUX_MAC 语句注释掉。)

cd pyflow/
python setup.py build_ext -i

随后将生成的.pyd文件(Windows系统)或.so文件(Linux系统)复制到工作目录下。

测试时,直接读取.dat文件,截取240个时间步送入预训练网络,即可生成超分图。

BSF重构算法

使用recVidarReal2019数据集中的汽车高速行驶场景序列car-100kmh进行重构,对应的测试脚本为examples/test_bsf.py(直接运行方式)及spikecv proc reconst bsf(CLI方式)。以下分别介绍两种使用方式。

直接脚本调用

首先确保BSF预训练权重已放置在正确位置(spkProc/reconstruction/BSF_Recon/pretrained/bsf.pth)。然后在examples/目录下运行:

import os
import sys
sys.path.append("..")

import torch
from pprint import pprint
from spkData.load_dat import SpikeStream, data_parameter_dict
from spkProc.reconstruction.BSF_Recon.bsf_recon import BSFRecon, default_weight_path
from visualization.get_video import obtain_reconstruction_video

data_filename = "recVidarReal2019/classA/car-100kmh"
label_type = "raw"
begin_idx = 500
block_len = 300
step = 3

paraDict = data_parameter_dict(data_filename, label_type)
pprint(paraDict)

vidarSpikes = SpikeStream(**paraDict)
spikes = vidarSpikes.get_block_spikes(begin_idx=begin_idx, block_len=block_len)

device_name = "cuda" if torch.cuda.is_available() else "cpu"
device = torch.device(device_name)
print(f"Using device: {device_name}")
print(f"Expected weight path: {default_weight_path()}")

reconstructor = BSFRecon(
    spike_h=paraDict["spike_h"],
    spike_w=paraDict["spike_w"],
    device=device,
    step=step,
)

print("Running BSF reconstruction...")
rec_img = reconstructor.spikes2images(spikes)
print(f"Reconstructed frames shape: {rec_img.shape}")

if not os.path.exists("results"):
    os.makedirs("results")

result_video = os.path.join("results", "car-100kmh_bsf.avi")
obtain_reconstruction_video(rec_img, result_video, **paraDict)
print(f"Reconstruction video saved to: {result_video}")

CLI调用

使用CLI方式调用BSF重构更为简洁,无需编写脚本。首先下载数据集:

spikecv data download --dataset recVidarReal2019

然后运行BSF重构:

spikecv proc reconst bsf \
    --yaml-file-path recVidarReal2019/config.yaml \
    --dat-file-path recVidarReal2019/classA/car-100kmh.dat \
    --begin-idx 500 \
    --block-len 300 \
    --step 3

CLI参数说明:

  • --yaml-file-path / -yaml:数据集配置文件路径,默认recVidarReal2019/config.yaml

  • --dat-file-path / -dat:脉冲数据文件路径,默认recVidarReal2019/classA/car-100kmh.dat

  • --begin-idx / -begin:起始帧索引,默认500

  • --block-len / -b:处理的帧数,默认300(注意:至少需要101帧才能输出有效结果)

  • --weight-path / -w:预训练权重路径,默认使用spkProc/reconstruction/BSF_Recon/pretrained/bsf.pth

  • --step:输出帧时间步长,默认3

  • --window-size:滑动窗口大小,默认61

  • --gamma:Gamma校正因子,默认2.2

重构结果保存在results/目录下(由CLI自动创建),文件名为{数据文件名}_bsf.avi

BSF 重构效果展示

光流估计

example中的train_scflow.pytest_scflow.py分别提供了SCFlow网络训练与测试的样例。

# train_scflow.py 中的代码介绍

# main函数结构介绍

######################## Train Loader ########################
## 定义训练集合的代码

######################## Test Loader ########################
## 定义验证集合

######################## Create Saving Root ########################
## 定义保存训练结果的文件夹与writer

######################## Create Model ########################
## 初始化模型

######################## Create Optimizer ########################
## 创建优化器

######################## Training Loop ########################
## 逐个epoch训练调用train()函数的循环

# train函数结构介绍

######################## Define params and model.train() ########################
## 定义参数并将model设置为train模式

######################## Get inputs ########################
## 获取minibatch的输入

######################## Compute output ########################
## 计算网络的输出

######################## Compute loss ########################
## 计算损失函数

######################## Compute gradient and optimize ########################
## 计算梯度并反向传播

######################## Record loss and output logs ########################
## 记录损失并输出训练日志

# validate函数的结构的前半部分与train类似(不同的是model为eval模式),在计算网络输出后对所输出的光流进行评价记录、打印日志


# test_scflow.py 的函数结构与上述validate函数类似,可通过设置scene变量选择PHM数据集的场景

多目标高速运动物体跟踪

使用motVidarReal2020数据集实现多目标跟踪的任务,并且使用标签数据及模型结果进行可视化和指标度量。

Spike-SORT多目标跟踪算法示例

对应的测试脚本为test_ssort.py,具体实现过程为:

插入模块及数据加载

import os, sys
import torch
sys.path.append("..")  #若是在example目录下,需添加父级目录路径

from spkData.load_dat import data_parameter_dict
from spkData.load_dat import SpikeStream
from spkProc.tracking.spike_sort import SpikeSORT
from utils import path

from metrics.tracking_mot import TrackingMetrics
from visualization.get_video import obtain_mot_video
from pprint import pprint

# 指定数据集名称及任务类型
data_filename = "motVidarReal2020/spike59"
label_type = "tracking"

# 记载数据集属性字典
paraDict = data_parameter_dict(data_filename, label_type)
pprint(paraDict)

# 使用数据属性字典加载数据
vidarSpikes = SpikeStream(**paraDict)
block_len = 1000
spikes = vidarSpikes.get_block_spikes(begin_idx=0, block_len=block_len)

若数据集加载成功,则终端会输出:

{'filepath': '..\\spkData\\datasets\\motVidarReal2020\\spike59\\spikes.dat',
 'labeled_data_dir': '..\\spkData\\datasets\\motVidarReal2020\\spike59\\spikes_gt.txt',
 'labeled_data_suffix': 'txt',
 'labeled_data_type': [4, 5],
 'spike_h': 250,
 'spike_w': 400}
loading total spikes from dat file -- spatial resolution: 400 x 250, begin index: 0 total timestamp: 1000

进行多目标跟踪并保存结果到文本文件

使用spkProc.tracking.spike_sort中的多目标跟踪器SpikeSORT,并且输出结果到txt文本文件中

device = torch.device('cuda')

calibration_time = 150
filename = path.split_path_info_pieces(data_filename)
result_filename = filename[-1] + '_spikeSort.txt'
# 确保文件保存路径存在
if not os.path.exists('results'):
    os.makedirs('results')
tracking_file = os.path.join('results', result_filename)
# 实例化 SpikeSORT用于多目标跟踪
spike_tracker = SpikeSORT(spikes, paraDict.get('spike_h'), paraDict.get('spike_w'), device)

spike_tracker.calibrate_motion(calibration_time)
spike_tracker.get_results(tracking_file)

若成功运行,终端中会出现跟踪所消耗的总时长:

begin calibrate..
Total tracking took: 4.090 seconds for 850 timestamps spikes

结果度量及可视化

# 多目标跟踪结果度量
metrics = TrackingMetrics(tracking_file, **paraDict)
metrics.get_results()

# 可视化多目标跟踪结果
video_filename = os.path.join('results', filename[-1] + 'mot.avi')
# 在滤波后的脉冲阵列上可视化跟踪结果
obtain_mot_video(spike_tracker.filterd_spikes, video_filename, tracking_file, **paraDict)
# 若是在原始脉冲阵列上可视化跟踪结果,可采取
# obtain_mot_video(spikes, video_filename, tracking_file, **paraDict)

度量结果:

      IDF1   IDP   IDR  Rcll  Prcn GT MT PT ML  FP  FN IDs  FM  MOTA  MOTP IDt IDa IDm
full 93.6% 91.0% 96.5% 96.5% 91.0%  5  5  0  0 383 141   0  36 86.9% 0.465   0   0   0
part  nan%  nan%  nan%  nan%  nan%  0  0  0  0   0   0   0   0  nan%   nan   0   0   0

可视化结果:

  • 在原始脉冲阵列上可视化跟踪结果,白色边框为标签数据,彩色边框为算法结果,不同颜色表示不同的跟踪器。

spike59_mot
  • 在STP滤波后的脉冲阵列上的可视化跟踪结果

spike59_filtered_mot

SNNTracker多目标跟踪算法示例

我们提供了test_snntracker.py脚本以展示更完整的功能。

此处只说明核心代码功能:

插入模块及数据加载

import argparse
import cv2
import os
from utils import path
import sys
import torch
import numpy as np
from pprint import pprint
from spkProc.tracking.SNN_Tracker.snn_tracker import SNNTracker
from spkData.load_dat import data_parameter_dict, SpikeStream
from utils.utils import vis_trajectory, downscale_input
from visualization.get_video import obtain_mot_video
from metrics.tracking_mot_v2 import TrackingMetrics  # for SNNTracker
import pathlib
from pathlib import Path

# 指定数据集名称及任务类型
data_filename = "motVidarReal2020/spike59"
label_type = "tracking"

# 记载数据集属性字典
para_dict = data_parameter_dict(data_filename, label_type)
pprint(para_dict)

# 使用数据属性字典加载数据
vidarSpikes = SpikeStream(**para_dict)
block_len = 1000
spikes = vidarSpikes.get_block_spikes(begin_idx=0, block_len=block_len)

若数据集加载成功,则终端会输出:

{'filepath': '..\\spkData\\datasets\\motVidarReal2020\\spike59\\spikes.dat',
 'labeled_data_dir': '..\\spkData\\datasets\\motVidarReal2020\\spike59\\spikes_gt.txt',
 'labeled_data_suffix': 'txt',
 'labeled_data_type': [4, 5],
 'spike_h': 250,
 'spike_w': 400}
loading total spikes from dat file -- spatial resolution: 400 x 250, begin index: 0 total timestamp: 1000

数据预处理

可以对加载的脉冲数据进行降采样处理,以减少计算量并提高处理速度:

# 降采样比例(默认 1,不缩放)
scale_w = 1 # 2
scale_h = 1 # 2
spikes = downscale_input(spikes, scale_w, scale_h)
para_dict['spike_w'] = para_dict.get('spike_w') // scale_w
para_dict['spike_h'] = para_dict.get('spike_h') // scale_h
pprint(spikes.shape)

初始化SNNTracker

使用spkProc.tracking.SNN_Tracker.snn_tracker.SNNTracker初始化跟踪器,并设置相关参数:

# 设置设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"Using device: {device}")

# 初始化SNNTracker
attention_size = 15
tracker = SNNTracker(
   spike_h=para_dict.get('spike_h'),
   spike_w=para_dict.get('spike_w'),
   device=device,
   attention_size=attention_size
)

运动标定

使用STP滤波器进行运动标定,以估计背景运动并提取前景目标:

# 标定时间
calibration_time = 150

print("Starting motion calibration...")
tracker.calibrate_motion(spikes, calibration_time)
print("Motion calibration completed.")

执行跟踪

对整个数据序列进行多目标跟踪,并实时显示进度:

# 创建结果目录(如果不存在)
RESULT_DIR = Path("results")
RESULT_DIR.mkdir(parents=True, exist_ok=True)

track_videoName = str(RESULT_DIR / "motVidarReal2020_spike59_snn.avi")
tracking_file = str(RESULT_DIR / "motVidarReal2020_spike59_snn.txt")


print("Starting tracking...")
mov = cv2.VideoWriter(track_videoName, cv2.VideoWriter_fourcc(*'MJPG'), 30, (para_dict.get('spike_w'), para_dict.get('spike_h')))
tracker.get_results(spikes[calibration_time:], tracking_file, mov, save_video=True)
print(f"Tracking completed")

mov.release()
cv2.destroyAllWindows()
  • 实时跟踪视频输出

spike59_snn

轨迹可视化

trajectories_filename = str(RESULT_DIR / "motVidarReal2020_spike59_py.json")
visTraj_filename = str(RESULT_DIR / "motVidarReal2020_spike59.png")

# 可视化轨迹
tracker.save_trajectory(str(RESULT_DIR), "spike59")
vis_trajectory(trajectories_filename, visTraj_filename, **para_dict)

print(f"Trajectory visualization saved to: {trajectory_filename}")
  • 轨迹可视化结果

spike59_trajectory

结果度量

使用metrics.tracking_mot_v2.TrackingMetrics对跟踪结果进行评估:

# 计算跟踪指标
metrics = TrackingMetrics(tracking_file, **para_dict)
metrics.get_results()

度量结果示例:

      IDF1   IDP   IDR  Rcll  Prcn GT MT PT ML  FP FN IDs  FM  MOTA  MOTP IDt IDa IDm
full 95.8% 92.9% 98.8% 98.8% 92.9%  5  5  0  0 301 47   0  28 91.3% 0.418   0   0   0
part   NaN   NaN   NaN   NaN   NaN  0  0  0  0   0  0   0   0   NaN   NaN   0   0   0

视频可视化

使用visualization.get_video.obtain_mot_video生成跟踪结果视频:

# 生成可视化视频
video_filename = str(RESULT_DIR / "motVidarReal2020_spike59_mot.avi")
obtain_mot_video(
    spikes,
    video_filename,
    tracking_file,
    **para_dict
)
print(f"Tracking video saved to: {video_filename}")

# 如果要在STP滤波后的脉冲阵列上可视化跟踪结果,可使用:
# obtain_mot_video(tracker.filtered_spikes, video_filename, tracking_file, **para_dict)
  • 视频可视化结果

spike59_snn_mot