Document translation from
dv-processing Release rel_1.7
iniVation AG
dv-processing
安装
Python
python3 -m pip install dv-processing
3 基础知识
3.1 事件储存
dv-processing
库提供了一个易于使用和高效的数据结构来存储和管理来自摄像机的传入事件数据dv.EventStore
类。它被实现为一个浅的共享所有权数据结构,该结构仅保存指向包含事件数据的实际存储器位置的指针。与OpenCV
处理图像数据的方式类似,dv.EventStore
不会复制数据,而是仅保存指向接收到的事件数据包的指针,并使用这些数据包的元数据在给定的时间间隔内有效地对数据进行切片。
3.1.1创建和存储事件
以下示例代码显示如何创建空事件存储并使用软件生成的事件填充它:
import dv_processing as dv
# Initialize an empty store
store = dv.EventStore()
# Get the current timestamp
timestamp = dv.now()
# Add some events into the event store
# This allocates and inserts events at the back, the function arguments are:
# timestamp, x, y, polarity
store.push_back(timestamp, 0, 0, True)
store.push_back(timestamp + 1000, 1, 1, False)
store.push_back(timestamp + 2000, 2, 2, False)
store.push_back(timestamp + 3000, 3, 3, True)
# Perform time-based slicing of event store, the output event store "sliced" will contain
# the second and third events from above. The end timestamp (second argument) is 2001,since start
# timestamp (first argument) is inclusive and timestamp is exclusive, so 1 is added.
sliced = store.sliceTime(timestamp + 1000, timestamp + 2001)
# This should print two events
for ev in store:
print(f"Sliced event [{ev.timestamp()}, {ev.x()}, {ev.y()}, {ev.polarity()}]")
3.1.2切片事件存储
dv.EventStore
可以按时间或事件数量进行切片。切片是一种浅层操作,它不复制任何数据。切片返回一个新的dv.EventStore
,它只引用所请求的数据。原来的商店不受影响。
按时间切片
dv.EventStore
以高效的方式实现了事件数据的按时间切片。通过重用底层的数据包结构,切片执行O(log n)的时间复杂度。以下示例显示了基于时间的切片函数的用法:
import dv_processing as dv
from datetime import timedelta
# Generate 10 events with time range [10000; 20000]
store = dv.data.generate.uniformEventsWithinTimeRange(10000,timedelta(milliseconds=10), (100, 100), 10)
# Get all events with timestamp above 12500, it will be 13000 and up
eventsAfterTimestamp = store.sliceTime(12500)
# Print the timestamp ranges
print(f"1. {eventsAfterTimestamp}")
# Slice event within time range [12000; 16000); the end time is exclusive
eventsInRange = store.sliceTime(12000, 16000)
# Print the timestamp ranges; It will print that range is [12000; 15000] since endtime is exclusive and
# event at timestamp 16000 is not going to be included.
print(f"2. {eventsInRange}")
按事件数量切片
dv.EventStore
通过索引和事件数量提供切片功能。dv.EventStore.slice()
方法的第一个参数是输出切片的起始索引,第二个可选参数是要切片的事件数量。如果未提供number参数,则切片将包含给定索引中的所有事件。以下示例显示如何在基础事件的给定索引内对事件存储区进行切片:
import dv_processing as dv
from datetime import timedelta
# Generate 10 events with time range [10000; 20000]
store = dv.data.generate.uniformEventsWithinTimeRange(10000,timedelta(milliseconds=10), (100, 100), 10)
# Get all events beyond and including index 5
events_after_index = store.slice(5)
print(f"1. {events_after_index}")
# Get 3 events starting with index 2
events_in_range = store.slice(2, 3)
print(f"2. {events_in_range}")
# Use sliceBack to retrieve event from the end; this call will retrieve last 3 events
last_events = store.sliceBack(3)
print(f"3. {last_events}")
组合多个EventStore
可以将多个dv.EventStore
实例添加到一起,以使用单个对象来访问和管理它。由于dv.EventStore
使用指向底层事件数据包数据的指针,因此组合不涉及任何深度数据副本,因此实现将接管共享内存所有权。以下示例说明如何有效地将多个事件存储合并为一个:
3.5 命令行实用程序
dv-processing
库提供了某些命令行实用程序,这些实用程序对于解决基本问题或执行某些基本任务很有用.
3.5.1 dv-filestat
dv-filestat
实用程序对于检查 AEDAT4
文件非常有用。它提供关于给定文件内容的信息。使用方法:
dv-filestat path/to/file.aedat4
#此实用程序的输出示例:
$ dv-filestat ~/dvSave-2022_06_29_13_40_44.aedat4
File path (canonical): "/home/rokas/dvSave-2022_06_29_13_40_44.aedat4"
File size (OS): 25429285
File size (Parser): 25429285
Compression: LZ4
Timestamp lowest: 1656502844057775
Timestamp highest: 1656502852007717
Timestamp difference: 7949942
Timestamp shift: 1656502844057775
Stream 0: events - EVTS
Stream 2: imu - IMUS
Stream 3: triggers - TRIG
DataTable file position: 25377171
DataTable file size: 52114
DataTable elements: 1590
这里,提供的字段为:
文件路径-文件系统中的绝对文件路径;
文件大小-实际文件大小(以字节为单位);
压缩-压缩类型;
Timestamp -Unix微秒格式的定时信息;
流-可用流(例如“Stream 0:events - EVTS”),其中“0”-流id,“事件”-流名称,“EVTS”-流类型标识符;
DataTable -内部数据布局信息
3.6 读取摄像机数据
dv-processing
库提供了一种从实时连接的摄像机和永久文件中阅读摄像机数据的方便方法。
3.6.1 摄像机名称
摄像机名称用于标识iniVation
生成的唯一摄像机。摄像机名称由摄像机型号和序列号组成,序列号之间用下划线(“_”)字符连接。库以多种方法引用相机名称,此值可在库中一致使用。
相机名称的一些示例:
DVXplorer: DVXplorer_DXA00093, DVXplorer_DXM00123
DAVIS: DAVIS346_00000499
注意:此定义适用于USB
摄像机,摄像机名称也会在网络流媒体源中报告。在这种情况下,相机名称可以由开发人员手动设置,因此模型的命名约定可能不完全相同。
3.6.2 来自摄像头
从实时摄像机访问数据的最简单方法是使用dv.io.CameraCapture
类。本节提供有关用法和代码示例的深入说明。
发现联网摄像机
相机名称可以使用dv-processing
包中提供的命令行实用程序dv-list-devices
进行检查。实用程序的输出示例:
$ dv-list-devices
Device discovery: found 2 devices.
Detected device [DAVIS346_00000499]
Detected device [DVXplorer_DXA00093]
使用库方法也可以发现设备。以下是有关如何使用发现方法检测已连接设备的示例:
import dv_processing as dv
cameras = dv.io.discoverDevices()
print(f"Device discovery: found {len(cameras)} devices.")
for camera_name in cameras:
print(f"Detected device [{camera_name}]")
打开相机
dv.io.CameraCapture
类遵循RAII8
模式进行资源管理。创建类的实例将打开USB
上连接的摄像头并立即开始阅读数据,当对象实例被销毁时资源被释放。此类的构造函数接受两个参数:相机名称[字符串]和相机类型[枚举],用于指定需要打开哪个相机。默认参数值被设计成不约束相机规格,并且有效地打开系统中第一个检测到的相机。
import dv_processing as dv
capture = dv.io.CameraCapture()
#还可以通过提供相机名称来打开系统上的特定相机:
import dv_processing as dv
# Open the specified camera
capture = dv.io.CameraCapture(cameraName="DVXplorer_DXA000000")
相机类型参数可用于打开给定类型的相机。如果提供了这两个参数,则摄像机需要匹配dv.io.CameraCapture
类打开的两个字段要求:
import dv_processing as dv # Open any DAVIS camera (camera name not specified)
capture = dv.io.CameraCapture(type=dv.io.CameraCapture.CameraType.DAVIS)
正在检查摄像机功能
dv.io.CameraCapture
类抽象了iniVation
制造的所有相机,由于某些相机提供不同的数据类型,因此capture类提供了测试相机可以提供哪些数据的方法:
import dv_processing as dv
# Open any camera
capture = dv.io.CameraCapture()
# Print the camera name
print(f"Opened [{capture.getCameraName()}] camera, it provides:")
# Check whether event stream is available
if capture.isEventStreamAvailable():
# Get the event stream resolution
resolution = capture.getEventResolution()
# Print the event stream capability with resolution value
print(f"* Events at ({resolution.width}x{resolution.height}) resolution")
# Check whether frame stream is available
if capture.isFrameStreamAvailable():
# Get the frame stream resolution
resolution = capture.getFrameResolution()
# Print the frame stream capability with resolution value
print(f"* Frames at ({resolution.width}x{resolution.height}) resolution")
# Check whether the IMU stream is available
if capture.isImuStreamAvailable():
# Print the imu data stream capability
print("* IMU measurements")
# Check whether the trigger stream is available
if capture.isTriggerStreamAvailable():
# Print the trigger stream capability
print("* Triggers")
配置相机选项
我们的相机的一些高级属性可以通过许多功能进行配置。这里列出了它们以供参考,请查看其详细的API
文档以获取更多详细信息。
DAVIS摄像机高级控制功能:
enableDavisAutoExposure() //启用帧自动曝光,默认值= true
setDavisExposureDuration() // 禁用自动曝光,将帧曝光设置为给定值
getDavisExposureDuration() // 读取当前帧曝光持续时间值
setDavisFrameInterval() // 设置帧间隔时长(帧间隔时间)
getDavisFrameInterval() // 读取当前帧间隔时长值
setDavisReadoutMode() // 配置数据读出模式
setDavisColorMode() // 配置边框颜色输出模式(仅在彩色摄像头上)
从实时摄像机读取事件
可以使用dv.io.CameraCapture.getNextEventBatch()
顺序读取摄像机的传入数据。以下是有关如何从摄像机顺序读取事件的最小示例:
import dv_processing as dv
import cv2 as cv
# Open any camera
capture = dv.io.CameraCapture()
# 启动预览窗口
cv.namedWindow("Preview", cv.WINDOW_NORMAL)
# 在相机仍处于连接状态时运行循环
while capture.isRunning():
# 从相机中读取帧
frame = capture.getNextFrame()
# 该方法不等待帧到达,它立即返回
# 最新可用帧,或者如果没有可用数据,则返回`None`
if frame is not None:
# 打印收到的数据包时间范围
print(f"Received a frame at time [{frame.timestamp}]")
# 显示图像的预览
cv.imshow("Preview", frame.image)
cv.waitKey(2)
从实时摄像机读取IMU数据
从实时摄像机读取触发器
示例应用程序:从实时摄像机阅读数据
import datetime
import dv_processing as dv
import cv2 as cv
import argparse
parser = argparse.ArgumentParser(description='Show a preview of an iniVation event camera input.')
args = parser.parse_args()
# Open the camera
camera = dv.io.CameraCapture()
# 初始化可视化器实例,该实例生成事件数据预览
visualizer = dv.visualization.EventVisualizer(camera.getEventResolution())
# Create the preview window
cv.namedWindow("Preview", cv.WINDOW_NORMAL)
def preview_events(event_slice):
cv.imshow("Preview", visualizer.generateImage(event_slice))
cv.waitKey(2)
# 创建一个事件切片机,只能使用摄像机
slicer = dv.EventStreamSlicer()
slicer.doEveryTimeInterval(datetime.timedelta(milliseconds=33), preview_events)
# start read loop
while True:
# Get events
events = camera.getNextEventBatch()
# If no events arrived yet, continue reading
if events is not None:
slicer.accept(events)
可以在dv-processing
库的源代码存储库中的代码示例中找到从现场摄像机阅读多种类型数据的应用程序。
3.6.3 来自文件
来自iniVation
相机的数据通常使用AEDAT 4
文件格式记录。dv-processing
库提供了阅读这些文件的工具。本节包含有关如何从AEDAT 4
文件读取数据的说明和示例。有关AEDAT 4
文件格式的更多详细信息,请参见此处AEDAT file formats — inivation master documentation。
检查AEDAT4
文件
AEDAT 4
文件格式支持将不同的数据流记录到单个文件中,也支持多个相机。该库提供了一个命令行实用程序,用于检查AEDAT 4
文件dv-filestat
,它提供了有关记录在其中的可用流的信息。
打开文件
可以使用dv.io.MonoCameraRecording
类打开和读取AEDAT4
文件。本课程假设使用单个摄像机执行记录。下面是一个最小的样本代码打开一个记录和打印有关它的信息。通过提供文件系统中的路径可以打开文件:
import dv_processing as dv
# Open a file
reader = dv.io.MonoCameraRecording("path/to/file.aedat4")
# Get and print the camera name that data from recorded from
print(f"Opened an AEDAT4 file which contains data from [{reader.getCameraName()}]camera")
检查可用流数据记录可能包含各种数据流
dv.io.MonoCameraRecording
提供了易于使用的方法来检查哪些数据流可用。以下示例代码显示了如何检查各种数据流的存在:
import dv_processing as dv
# Store the file path
path_to_file = "path/to/file.aedat4"
# Open a file
reader = dv.io.MonoCameraRecording(path_to_file)
# Print file path and camera name
print(f"Checking available streams in [{path_to_file}] for camera name [{reader.getCameraName()}]:")
# Check if event stream is available
if reader.isEventStreamAvailable():
# Check the resolution of event stream
resolution = reader.getEventResolution()
# 打印出存在的流及其分辨率
print(f" * Event stream with resolution [{resolution.width}x{resolution.height}]")
# Check if frame stream is available
if reader.isFrameStreamAvailable():
# Check the resolution of frame stream
resolution = reader.getFrameResolution()
# Print that the stream is available and its resolution
print(f" * Frame stream with resolution [{resolution.width}x{resolution.height}]")
# Check if IMU stream is available
if reader.isImuStreamAvailable():
# Print that the IMU stream is available
print(" * IMU stream")
# Check if trigger stream is available
if reader.isTriggerStreamAvailable():
# Print that the trigger stream is available
print(" * Trigger stream")
从文件读取事件
以下示例在流有可用数据可读取时分批读取事件。从文件阅读时,dv.io.MonoCameraRecording.getNextEventBatch()
将返回数据,直到到达流的结尾,dv.io.MonoCameraRecording.isRunning()
方法将在到达结尾时返回a false boolean
。
import dv_processing as dv
# Open any camera
reader = dv.io.MonoCameraRecording("path/to/file.aedat4")
# Run the loop while camera is still connected
while reader.isRunning():
# Read batch of events
events = reader.getNextEventBatch()
if events is not None:
# Print received packet time range
print(f"{events}")
从文件中读取帧
以下示例在流有可用数据可读取时成批读取帧。当阅读文件时,dv.io.MonoCameraRecording.getNextFrame()
将返回一个帧,直到到达流的结尾,dv.io.MonoCameraRecording.isRunning()
方法将在到达结尾时返回一个假布尔值。
import dv_processing as dv
import cv2 as cv
# Open a file
reader = dv.io.MonoCameraRecording("path/to/file.aedat4")
# Initiate a preview window
cv.namedWindow("Preview", cv.WINDOW_NORMAL)
# Variable to store the previous frame timestamp for correct playback
lastTimestamp = None
# Run the loop while camera is still connected
while reader.isRunning():
# Read a frame from the camera
frame = reader.getNextFrame()
if frame is not None:
# Print the timestamp of the received frame
print(f"Received a frame at time [{frame.timestamp}]")
# Show a preview of the image
cv.imshow("Preview", frame.image)
# Calculate the delay between last and current frame, divide by 1000 to convert microseconds
# to milliseconds
delay = (2 if lastTimestamp is None else (frame.timestamp - lastTimestamp) /␣1000)
# Perform the sleep
cv.waitKey(delay)
# Store timestamp for the next frame
33
lastTimestamp = frame.timestamp
从文件中读取IMU数据
从文件读取触发器
示例应用程序-从记录的AEDAT 4文件阅读数据
#AEDAT4 to CSV converter in Python
import dv_processing as dv
import argparse
import pathlib
import cv2
import numpy as np
import pandas as pd
parser = argparse.ArgumentParser(description='Save aedat4 data to csv.')
parser.add_argument('-f,--file',
dest='file',
type=str,
required=True,
metavar='path/to/file',
help='Path to an AEDAT4 file')
args = parser.parse_args()
file = pathlib.Path(args.file)
file_parent = file.parent
file_stem = file.stem
# Open the recording file
recording = dv.io.MonoCameraRecording(args.file)
if recording.isFrameStreamAvailable():
frames_path = file_parent / (file_stem + "_frames")
if not frames_path.is_dir():
frames_path.mkdir(parents=True)
print("Frames will be saved under %s" % frames_path)
count_frames = 0
print("Saving Frames...")
while True:
frame = recording.getNextFrame()
if frame is None:
break
cv2.imwrite(str(frames_path / (str(frame.timestamp) + '.png')), frame.image)
count_frames += 1
print("Saved %d frames." % count_frames)
if recording.isEventStreamAvailable():
events_path = file_parent / (file_stem + "_events.csv")
print("Events will be saved under %s" % events_path)
print("Saving Events...")
events_packets = []
while True:
events = recording.getNextEventBatch()
if events is None:
break
events_packets.append(pd.DataFrame(events.numpy()))
print("Done reading events, saving into CSV...")
events_pandas = pd.concat(events_packets)
events_pandas.to_csv(events_path)
print("Saved %d events." % len(events_pandas))
if recording.isTriggerStreamAvailable():
triggers_path = file_parent / (file_stem + "_triggers.csv")
print("Triggers data will be saved under %s" % triggers_path)
print("Saving Triggers...")
types = []
timestamps = []
while True:
triggers = recording.getNextTriggerBatch()
if triggers is None:
break
for trigger in triggers:
types.append(trigger.type)
timestamps.append(trigger.timestamp)
print("Done reading triggers, saving into CSV...")
triggers_pandas = pd.DataFrame({"timestamp": np.array(timestamps), "type": np.array(types)})
triggers_pandas.to_csv(triggers_path)
print("Saved %d triggers." % len(triggers_pandas))
if recording.isImuStreamAvailable():
imus_path = file_parent / (file_stem + "_imus.csv")
print("IMU data will be saved under %s" % imus_path)
print("Saving IMU data...")
temperatures = []
accelerometerX = []
accelerometerY = []
accelerometerZ = []
gyroscopeX = []
gyroscopeY = []
gyroscopeZ = []
timestamps = []
while True:
imus = recording.getNextImuBatch()
if imus is None:
break
for imu in imus:
temperatures.append(imu.temperature)
acc = imu.getAccelerations()
accelerometerX.append(acc[0])
accelerometerY.append(acc[1])
accelerometerZ.append(acc[2])
gyro = imu.getAngularVelocities()
gyroscopeX.append(gyro[0])
gyroscopeY.append(gyro[1])
gyroscopeZ.append(gyro[2])
timestamps.append(imu.timestamp)
print("Done reading IMU data, saving into CSV...")
imus_pandas = pd.DataFrame({
"timestamp": np.array(timestamps),
"temperature": np.array(temperatures),
"accelerometerX": np.array(accelerometerX),
"accelerometerY": np.array(accelerometerY),
"accelerometerZ": np.array(accelerometerZ),
"gyroscopeX": np.array(gyroscopeX),
"gyroscopeY": np.array(gyroscopeY),
"gyroscopeZ": np.array(gyroscopeZ)
})
imus_pandas.to_csv(imus_path)
print("Saved %d IMU measurements." % len(imus_pandas))
从AEDAT 4
文件阅读多种类型数据的应用程序可以在dv-processing
库的源代码存储库中找到
3.7 写入相机数据
dv-processing
库提供了一种将相机数据记录到AEDAT 4
文件中的便捷方法。这些文件可以记录多种数据类型,并且可以使用库中的现有工具读取。DV GUI
软件还提供了回放这些记录的方法。
3.7.1 写文件
文件可以使用dv.io.MonoCameraWriter
类写入。由于写入器支持多数据类型配置,因此它需要事先知道写入需要哪些数据流。它dv.io.MonoCameraWriter.Config
结构声明,并传递给writer类的构造函数,以正确初始化文件头中所需的流。
从现有摄像机读取器定义输出流
如前一段所述,输出流的数量及其数据类型需要为写入器所知。输出流定义可以由输入相机捕获生成。在这种情况下,writer类将检查捕获可以输出哪些流,并为它们创建输出流。以下是如何使用相机捕获类初始化编写器的示例:
import dv_processing as dv
capture = dv.io.CameraCapture()
writer = dv.io.MonoCameraWriter("mono_writer_sample.aedat4", capture)
print(f"Is event stream available? {str(writer.isEventStreamConfigured())}")
print(f"Is frame stream available? {str(writer.isFrameStreamConfigured())}")
print(f"Is imu stream available? {str(writer.isImuStreamConfigured())}")
print(f"Is trigger stream available? {str(writer.isTriggerStreamConfigured())}")
手动定义输出流
输出流定义可以在配置结构中手动定义,以下是手动定义事件、帧、IMU
和触发器数据类型流并创建编写器实例的示例:
import dv_processing as dv
config = dv.io.MonoCameraWriter.Config("DVXplorer_sample")
# Define VGA resolution for this camera
resolution = (640, 480)
# Add an event stream with a resolution
config.addEventStream(resolution)
# Add frame stream with a resolution
config.addFrameStream(resolution)
# Add IMU stream
config.addImuStream()
# Add trigger stream
config.addTriggerStream()
# Create the writer instance with the configuration structure
writer = dv.io.MonoCameraWriter("mono_writer_sample.aedat4", config)
print(f"Is event stream available? {str(writer.isEventStreamConfigured())}")
print(f"Is frame stream available? {str(writer.isFrameStreamConfigured())}")
print(f"Is imu stream available? {str(writer.isImuStreamConfigured())}")
print(f"Is trigger stream available? {str(writer.isTriggerStreamConfigured())}")
使用预定义模板定义输出流
dv.io.MonoCameraWriter
类提供了一些配置模板以减少代码行。下面是一个如何使用命名方法来生成用于写入数据的配置的示例:
import dv_processing as dv
# Create a DVS config - events, imu, and triggers are going to be enabled
config = dv.io.MonoCameraWriter.DVSConfig("DVXplorer_sample", (640, 480))
# Create the writer instance with the configuration structure
writer = dv.io.MonoCameraWriter("mono_writer_sample.aedat4", config)
# Print which streams were configured
print(f"Is event stream available? {str(writer.isEventStreamConfigured())}")
print(f"Is frame stream available? {str(writer.isFrameStreamConfigured())}")
print(f"Is imu stream available? {str(writer.isImuStreamConfigured())}")
print(f"Is trigger stream available? {str(writer.isTriggerStreamConfigured())}")
dv.io.MonoCameraWriter
类下可用的输出流配置列表:·
EventOnlyConfig
-单个输出流“events”·
FrameOnlyConfig
-单个输出流“frames”·
DVSConfig
-三个输出流:“事件”、“IMU
”和“触发器”
DAVISConfig
-四个输出流:“事件”、“帧”、“IMU
”和“触发器”
3.7.2 将数据写入文件
写入器实例可用于写入已配置输出流的数据。以下各节提供了有关如何使用writer类编写单个数据类型的示例代码。
写入事件
import dv_processing as dv
# Sample VGA resolution, same as the DVXplorer camera
resolution = (640, 480)
# Event only configuration
config = dv.io.MonoCameraWriter.EventOnlyConfig("DVXplorer_sample", resolution)
# Create the writer instance, it will only have a single event output stream.
writer = dv.io.MonoCameraWriter("mono_writer_sample.aedat4", config)
# Write 100 packet of event data
for i in range(100):
# EventStore requires strictly monotonically increasing data, generate
# a timestamp from the iteration counter value
timestamp = i * 1000
# Empty event store
events = dv.data.generate.dvLogoAsEvents(timestamp, resolution)
# Write the packet using the writer, the data is not going be written at the exact
# time of the call to this function, it is only guaranteed to be written after
# the writer instance is destroyed (destructor has completed)
writer.writeEvents(events)
写入帧
以下示例显示了如何使用dv.io.MonoCameraWriter
类写入图像帧的示例:
import dv_processing as dv
import numpy as np
# Frame only configuration
config = dv.io.MonoCameraWriter.FrameOnlyConfig("DVXplorer_sample", (640, 480))
# Create the writer instance, it will only have a single frame output stream
writer = dv.io.MonoCameraWriter("mono_writer_sample.aedat4", config)
# Write 10 image frames
for i in range(10):
# Initialize a white image
image = np.full((480, 640, 3), fill_value=255, dtype=np.uint8)
# Generate some monotonically increasing timestamp
timestamp = i * 1000
# Encapsulate the image in a frame that has a timestamp, this does not copy the pixel data
frame = dv.Frame(timestamp, image)
# Write the frame
writer.writeFrame(frame)
示例应用程序-从实时摄像机记录数据
import dv_processing as dv
import argparse
parser = argparse.ArgumentParser(description='Record data from a single iniVation camera to a file.')
parser.add_argument("-c",
"--camera_name",
dest='camera_name',
default="",
type=str,
help="Camera name (e.g. DVXplorer_DXA00093). The application will open any supported camera "
"if no camera name is provided.")
parser.add_argument("-o",
"--output_path",
dest='output_path',
type=str,
required=True,
help="Path to an output aedat4 file for writing.")
args = parser.parse_args()
# Open any camera that is discovered in the system
camera = dv.io.CameraCapture(args.camera_name)
# Check whether frames are available
eventsAvailable = camera.isEventStreamAvailable()
framesAvailable = camera.isFrameStreamAvailable()
imuAvailable = camera.isImuStreamAvailable()
triggersAvailable = camera.isTriggerStreamAvailable()
try:
# Open a file to write, will allocate streams for all available data types
writer = dv.io.MonoCameraWriter(args.output_path, camera)
print("Start recording")
while camera.isConnected():
if eventsAvailable:
# Get Events
events = camera.getNextEventBatch()
# Write Events
if events is not None:
writer.writeEvents(events, streamName='events')
if framesAvailable:
# Get Frame
frame = camera.getNextFrame()
# Write Frame
if frame is not None:
writer.writeFrame(frame, streamName='frames')
if imuAvailable:
# Get IMU data
imus = camera.getNextImuBatch()
# Write IMU data
if imus is not None:
writer.writeImuPacket(imus, streamName='imu')
if triggersAvailable:
# Get trigger data
triggers = camera.getNextTriggerBatch()
# Write trigger data
if triggers is not None:
writer.writeTriggerPacket(triggers, streamName='triggers')
except KeyboardInterrupt:
print("Ending recording")
pass