From b200ec4b1f8469b27e480b00175518722308a212 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Wed, 2 Jul 2025 21:54:02 -0700 Subject: [PATCH] scripts/examples: Add examples for RAW event camera output. --- .../02-Genx320/genx320_event_mode.py | 55 +++++++++++++++ .../genx320_event_mode_filtering.py | 63 +++++++++++++++++ .../genx320_event_mode_high_speed.py | 51 ++++++++++++++ ...genx320_event_mode_high_speed_filtering.py | 59 ++++++++++++++++ .../genx320_event_mode_long_exposure.py | 61 ++++++++++++++++ ...x320_event_mode_long_exposure_filtering.py | 69 +++++++++++++++++++ 6 files changed, 358 insertions(+) create mode 100644 scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode.py create mode 100644 scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_filtering.py create mode 100644 scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed.py create mode 100644 scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed_filtering.py create mode 100644 scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure.py create mode 100644 scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure_filtering.py diff --git a/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode.py b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode.py new file mode 100644 index 000000000..1bf0d0119 --- /dev/null +++ b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode.py @@ -0,0 +1,55 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# This example shows off using the genx320 event camera from Prophesee +# using event streaming mode. + +import csi +import image +import time +# https://micropython-ulab.readthedocs.io/en/latest/index.html +from ulab import numpy as np + +# Surface to draw the histogram image on. +img = image.Image(320, 320, image.GRAYSCALE) + +# Stores camera events +# Shape: (EVT_res, 6) where EVT_res is the event resolution +# Columns: +# [0] Event type +# [1] Seconds timestamp +# [2] Milliseconds timestamp +# [3] Microseconds timestamp +# [4] X coordinate 0 to 319 for GENX320 +# [5] Y coordinate 0 to 319 for GENX320 +events = np.zeros((2048, 6), dtype=np.uint16) + +# Initialize the sensor. +csi0 = csi.CSI(cid=csi.GENX320) +csi0.reset() +csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT) + +clock = time.clock() + +while True: + clock.tick() + + # Reads up to 2048 events from the camera. + # Returns the number of valid events (0-2048) or a negative error code. + # Note that old events in the buffer are not cleared to save CPU time. + event_count = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events) + + # Render events into a histogram image. + # If clear=True, the image is reset to "brightness" before drawing. + # For each PIX_ON_EVENT, add "contrast" to the bin value; + # for each PIX_OFF_EVENT, subtract it and clamp to [0, 255]. + # If clear=False, histogram accumulates over multiple calls. + img.draw_event_histogram(events[:event_count], clear=True, brightness=128, contrast=64) + + # Push the image to the jpeg buffer for the IDE to pull and display. + # The IDE pulls frames off the camera at a much lower rate than the + # onboard camera frame rate printed below. + img.flush() + + print(event_count, clock.fps()) diff --git a/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_filtering.py b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_filtering.py new file mode 100644 index 000000000..3d11baf81 --- /dev/null +++ b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_filtering.py @@ -0,0 +1,63 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# This example shows off using the genx320 event camera from Prophesee +# using event streaming mode. +# +# Adds filtering of events based on the event type (PIX_ON_EVENT or PIX_OFF_EVENT). + +import csi +import image +import time +# https://micropython-ulab.readthedocs.io/en/latest/index.html +from ulab import numpy as np + +TARGET_EVENT_TYPE = csi.PIX_ON_EVENT # Change to PIX_OFF_EVENT to filter low events. + +# Surface to draw the histogram image on. +img = image.Image(320, 320, image.GRAYSCALE) + +# Stores camera events +# Shape: (EVT_res, 6) where EVT_res is the event resolution +# Columns: +# [0] Event type +# [1] Seconds timestamp +# [2] Milliseconds timestamp +# [3] Microseconds timestamp +# [4] X coordinate 0 to 319 for GENX320 +# [5] Y coordinate 0 to 319 for GENX320 +events = np.zeros((2048, 6), dtype=np.uint16) + +# Initialize the sensor. +csi0 = csi.CSI(cid=csi.GENX320) +csi0.reset() +csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT) + +clock = time.clock() + +while True: + clock.tick() + + # Reads up to 2048 events from the camera. + # Returns the number of valid events (0-2048) or a negative error code. + # Note that old events in the buffer are not cleared to save CPU time. + event_count = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events) + events_slice = events[:event_count] + indices = np.nonzero(events_slice[:, 0] == TARGET_EVENT_TYPE)[0] + if len(indices): + target_events = np.take(events_slice, indices, axis=0) + + # Render events into a histogram image. + # If clear=True, the image is reset to "brightness" before drawing. + # For each PIX_ON_EVENT, add "contrast" to the bin value; + # for each PIX_OFF_EVENT, subtract it and clamp to [0, 255]. + # If clear=False, histogram accumulates over multiple calls. + img.draw_event_histogram(target_events, clear=True, brightness=128, contrast=64) + + # Push the image to the jpeg buffer for the IDE to pull and display. + # The IDE pulls frames off the camera at a much lower rate than the + # onboard camera frame rate printed below. + img.flush() + + print(len(target_events), clock.fps()) diff --git a/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed.py b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed.py new file mode 100644 index 000000000..bbf7534dc --- /dev/null +++ b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed.py @@ -0,0 +1,51 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# This example shows off using the genx320 event camera from Prophesee +# using event streaming mode. +# +# This example has no frame buffer visualization to run extremely fast. + +import csi +import time +# https://micropython-ulab.readthedocs.io/en/latest/index.html +from ulab import numpy as np + +# Stores camera events +# Shape: (EVT_res, 6) where EVT_res is the event resolution +# Columns: +# [0] Event type +# [1] Seconds timestamp +# [2] Milliseconds timestamp +# [3] Microseconds timestamp +# [4] X coordinate 0 to 319 for GENX320 +# [5] Y coordinate 0 to 319 for GENX320 +events = np.zeros((2048, 6), dtype=np.uint16) + +# Initialize the sensor. +csi0 = csi.CSI(cid=csi.GENX320) +csi0.reset() +csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT) + +clock = time.clock() +t = time.ticks_us() + +i = 0 +while True: + clock.tick() + t1 = time.ticks_us() + diff = time.ticks_diff(t1, t) + t = t1 + i += 1 + + # Reads up to 2048 events from the camera. + # Returns the number of valid events (0-2048) or a negative error code. + # Note that old events in the buffer are not cleared to save CPU time. + event_count = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events) + + # Sub-sample the event rate output to not impact performance of event + # data processing. The overhead of sending stats outputs to the IDE can + # become significant at high event rates. + if not i % 10: + print(f'{event_count} events\t{clock.fps()} fps\t{diff} us') diff --git a/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed_filtering.py b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed_filtering.py new file mode 100644 index 000000000..818e314f0 --- /dev/null +++ b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_high_speed_filtering.py @@ -0,0 +1,59 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# This example shows off using the genx320 event camera from Prophesee +# using event streaming mode. +# +# This example has no frame buffer visualization to run extremely fast. +# +# Adds filtering of events based on the event type (PIX_ON_EVENT or PIX_OFF_EVENT). + +import csi +import time +# https://micropython-ulab.readthedocs.io/en/latest/index.html +from ulab import numpy as np + +TARGET_EVENT_TYPE = csi.PIX_ON_EVENT # Change to PIX_OFF_EVENT to filter low events. + +# Stores camera events +# Shape: (EVT_res, 6) where EVT_res is the event resolution +# Columns: +# [0] Event type +# [1] Seconds timestamp +# [2] Milliseconds timestamp +# [3] Microseconds timestamp +# [4] X coordinate 0 to 319 for GENX320 +# [5] Y coordinate 0 to 319 for GENX320 +events = np.zeros((2048, 6), dtype=np.uint16) + +# Initialize the sensor. +csi0 = csi.CSI(cid=csi.GENX320) +csi0.reset() +csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT) + +clock = time.clock() +t = time.ticks_us() + +i = 0 +while True: + clock.tick() + t1 = time.ticks_us() + diff = time.ticks_diff(t1, t) + t = t1 + i += 1 + + # Reads up to 2048 events from the camera. + # Returns the number of valid events (0-2048) or a negative error code. + # Note that old events in the buffer are not cleared to save CPU time. + event_count = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events) + events_slice = events[:event_count] + indices = np.nonzero(events_slice[:, 0] == TARGET_EVENT_TYPE)[0] + if len(indices): + valid_events = np.take(events_slice, indices, axis=0) + + # Sub-sample the event rate output to not impact performance of event + # data processing. The overhead of sending stats outputs to the IDE can + # become significant at high event rates. + if not i % 10: + print(f'{len(valid_events)} events\t{clock.fps()} fps\t{diff} us') diff --git a/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure.py b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure.py new file mode 100644 index 000000000..48f6b0a70 --- /dev/null +++ b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure.py @@ -0,0 +1,61 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# This example shows off using the genx320 event camera from Prophesee +# using event streaming mode drawing multiple frames on the same image. + +import csi +import image +import time +# https://micropython-ulab.readthedocs.io/en/latest/index.html +from ulab import numpy as np + +EXPOSURE_FRAMES = 10 + +# Surface to draw the histogram image on. +img = image.Image(320, 320, image.GRAYSCALE) + +# Stores camera events +# Shape: (EVT_res, 6) where EVT_res is the event resolution +# Columns: +# [0] Event type +# [1] Seconds timestamp +# [2] Milliseconds timestamp +# [3] Microseconds timestamp +# [4] X coordinate 0 to 319 for GENX320 +# [5] Y coordinate 0 to 319 for GENX320 +events = np.zeros((2048, 6), dtype=np.uint16) + +# Initialize the sensor. +csi0 = csi.CSI(cid=csi.GENX320) +csi0.reset() +csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT) + +clock = time.clock() +i = 0 +while True: + clock.tick() + + # Reads up to 2048 events from the camera. + # Returns the number of valid events (0-2048) or a negative error code. + # Note that old events in the buffer are not cleared to save CPU time. + event_count = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events) + + # Clear the image every EXPOSURE_FRAMES frames. + c = (i % EXPOSURE_FRAMES) == 0 + i += 1 + + # Render events into a histogram image. + # If clear=True, the image is reset to "brightness" before drawing. + # For each PIX_ON_EVENT, add "contrast" to the bin value; + # for each PIX_OFF_EVENT, subtract it and clamp to [0, 255]. + # If clear=False, histogram accumulates over multiple calls. + img.draw_event_histogram(events[:event_count], clear=c, brightness=128, contrast=64) + + # Push the image to the jpeg buffer for the IDE to pull and display. + # The IDE pulls frames off the camera at a much lower rate than the + # onboard camera frame rate printed below. + img.flush() + + print(event_count, clock.fps()) diff --git a/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure_filtering.py b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure_filtering.py new file mode 100644 index 000000000..211295fdf --- /dev/null +++ b/scripts/examples/01-Camera/03-Event-Cameras/02-Genx320/genx320_event_mode_long_exposure_filtering.py @@ -0,0 +1,69 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# This example shows off using the genx320 event camera from Prophesee +# using event streaming mode drawing multiple frames on the same image. +# +# Adds filtering of events based on the event type (PIX_ON_EVENT or PIX_OFF_EVENT). + +import csi +import image +import time +# https://micropython-ulab.readthedocs.io/en/latest/index.html +from ulab import numpy as np + +TARGET_EVENT_TYPE = csi.PIX_ON_EVENT # Change to PIX_OFF_EVENT to filter low events. + +EXPOSURE_FRAMES = 10 + +# Surface to draw the histogram image on. +img = image.Image(320, 320, image.GRAYSCALE) + +# Stores camera events +# Shape: (EVT_res, 6) where EVT_res is the event resolution +# Columns: +# [0] Event type +# [1] Seconds timestamp +# [2] Milliseconds timestamp +# [3] Microseconds timestamp +# [4] X coordinate 0 to 319 for GENX320 +# [5] Y coordinate 0 to 319 for GENX320 +events = np.zeros((32768, 6), dtype=np.uint16) + +# Initialize the sensor. +csi0 = csi.CSI(cid=csi.GENX320) +csi0.reset() +csi0.ioctl(csi.IOCTL_GENX320_SET_MODE, csi.GENX320_MODE_EVENT) + +clock = time.clock() +i = 0 +while True: + clock.tick() + + # Reads up to 2048 events from the camera. + # Returns the number of valid events (0-2048) or a negative error code. + # Note that old events in the buffer are not cleared to save CPU time. + event_count = csi0.ioctl(csi.IOCTL_GENX320_READ_EVENTS, events) + events_slice = events[:event_count] + indices = np.nonzero(events_slice[:, 0] == TARGET_EVENT_TYPE)[0] + if len(indices): + target_events = np.take(events_slice, indices, axis=0) + + # Clear the image every EXPOSURE_FRAMES frames. + c = (i % EXPOSURE_FRAMES) == 0 + i += 1 + + # Render events into a histogram image. + # If clear=True, the image is reset to "brightness" before drawing. + # For each PIX_ON_EVENT, add "contrast" to the bin value; + # for each PIX_OFF_EVENT, subtract it and clamp to [0, 255]. + # If clear=False, histogram accumulates over multiple calls. + img.draw_event_histogram(target_events, clear=c, brightness=128, contrast=64) + + # Push the image to the jpeg buffer for the IDE to pull and display. + # The IDE pulls frames off the camera at a much lower rate than the + # onboard camera frame rate printed below. + img.flush() + + print(len(target_events), clock.fps())