dvs事件相机

Document translation from dv-processing Release rel_1.7 iniVation AG

安装

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

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值