From 7f84ce50102f90c12bb6e5104c46fd906fc3c290 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sat, 16 Oct 2021 12:10:00 -0700 Subject: [PATCH 1/3] Add frogeye sensor driver --- src/omv/Makefile | 1 + src/omv/boards/NANO33/omv_boardconfig.h | 1 + src/omv/boards/OPENMV2/omv_boardconfig.h | 1 + src/omv/boards/OPENMV3/omv_boardconfig.h | 1 + src/omv/boards/OPENMV4/omv_boardconfig.h | 1 + src/omv/boards/OPENMV4P/omv_boardconfig.h | 1 + src/omv/boards/OPENMVPT/omv_boardconfig.h | 1 + src/omv/common/sensor.h | 52 ++++++++++++----------- src/omv/common/sensor_utils.c | 26 +++++++++--- src/omv/ports/stm32/omv_portconfig.mk | 2 + src/omv/sensors/frogeye2020.c | 35 +++++++++++++++ src/omv/sensors/frogeye2020.h | 15 +++++++ 12 files changed, 106 insertions(+), 31 deletions(-) create mode 100644 src/omv/sensors/frogeye2020.c create mode 100644 src/omv/sensors/frogeye2020.h diff --git a/src/omv/Makefile b/src/omv/Makefile index 301b00b5c..159d07a5e 100644 --- a/src/omv/Makefile +++ b/src/omv/Makefile @@ -39,6 +39,7 @@ SRCS += $(addprefix sensors/, \ hm01b0.c \ gc2145.c \ paj6100.c \ + frogeye2020.c \ ) SRCS += $(addprefix imlib/, \ diff --git a/src/omv/boards/NANO33/omv_boardconfig.h b/src/omv/boards/NANO33/omv_boardconfig.h index 0e0dd1b99..7d25cf26a 100644 --- a/src/omv/boards/NANO33/omv_boardconfig.h +++ b/src/omv/boards/NANO33/omv_boardconfig.h @@ -44,6 +44,7 @@ #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) #define OMV_ENABLE_PAJ6100 (0) +#define OMV_ENABLE_FROGEYE2020 (0) // Set which OV767x sensor is used #define OMV_OV7670_VERSION (75) diff --git a/src/omv/boards/OPENMV2/omv_boardconfig.h b/src/omv/boards/OPENMV2/omv_boardconfig.h index b401597a3..56a708533 100644 --- a/src/omv/boards/OPENMV2/omv_boardconfig.h +++ b/src/omv/boards/OPENMV2/omv_boardconfig.h @@ -57,6 +57,7 @@ #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) #define OMV_ENABLE_PAJ6100 (0) +#define OMV_ENABLE_FROGEYE2020 (0) // Enable sensor features #define OMV_ENABLE_OV5640_AF (0) diff --git a/src/omv/boards/OPENMV3/omv_boardconfig.h b/src/omv/boards/OPENMV3/omv_boardconfig.h index 46eaeb987..466690226 100644 --- a/src/omv/boards/OPENMV3/omv_boardconfig.h +++ b/src/omv/boards/OPENMV3/omv_boardconfig.h @@ -57,6 +57,7 @@ #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) #define OMV_ENABLE_PAJ6100 (0) +#define OMV_ENABLE_FROGEYE2020 (0) // Enable sensor features #define OMV_ENABLE_OV5640_AF (0) diff --git a/src/omv/boards/OPENMV4/omv_boardconfig.h b/src/omv/boards/OPENMV4/omv_boardconfig.h index 649da41b5..6605a87b5 100644 --- a/src/omv/boards/OPENMV4/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4/omv_boardconfig.h @@ -64,6 +64,7 @@ #define OMV_ENABLE_LEPTON (1) #define OMV_ENABLE_HM01B0 (0) #define OMV_ENABLE_PAJ6100 (1) +#define OMV_ENABLE_FROGEYE2020 (1) // Set which OV767x sensor is used #define OMV_OV7670_VERSION (70) diff --git a/src/omv/boards/OPENMV4P/omv_boardconfig.h b/src/omv/boards/OPENMV4P/omv_boardconfig.h index 608bb3cc4..178c8ea67 100644 --- a/src/omv/boards/OPENMV4P/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4P/omv_boardconfig.h @@ -67,6 +67,7 @@ #define OMV_ENABLE_LEPTON (1) #define OMV_ENABLE_HM01B0 (0) #define OMV_ENABLE_PAJ6100 (1) +#define OMV_ENABLE_FROGEYE2020 (1) // Enable sensor features #define OMV_ENABLE_OV5640_AF (0) diff --git a/src/omv/boards/OPENMVPT/omv_boardconfig.h b/src/omv/boards/OPENMVPT/omv_boardconfig.h index 96ef3899f..e816ca524 100644 --- a/src/omv/boards/OPENMVPT/omv_boardconfig.h +++ b/src/omv/boards/OPENMVPT/omv_boardconfig.h @@ -64,6 +64,7 @@ #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) #define OMV_ENABLE_PAJ6100 (0) +#define OMV_ENABLE_FROGEYE2020 (0) // Enable sensor features #define OMV_ENABLE_OV5640_AF (1) diff --git a/src/omv/common/sensor.h b/src/omv/common/sensor.h index 57f676190..5b6f21a61 100644 --- a/src/omv/common/sensor.h +++ b/src/omv/common/sensor.h @@ -14,36 +14,38 @@ #include "cambus.h" #include "imlib.h" -#define OV2640_SLV_ADDR (0x60) -#define OV5640_SLV_ADDR (0x78) -#define OV7725_SLV_ADDR (0x42) -#define MT9V034_SLV_ADDR (0xB8) -#define MT9M114_SLV_ADDR (0x90) -#define LEPTON_SLV_ADDR (0x54) -#define HM01B0_SLV_ADDR (0x48) -#define GC2145_SLV_ADDR (0x78) +#define OV2640_SLV_ADDR (0x60) +#define OV5640_SLV_ADDR (0x78) +#define OV7725_SLV_ADDR (0x42) +#define MT9V034_SLV_ADDR (0xB8) +#define MT9M114_SLV_ADDR (0x90) +#define LEPTON_SLV_ADDR (0x54) +#define HM01B0_SLV_ADDR (0x48) +#define GC2145_SLV_ADDR (0x78) +#define FROGEYE2020_SLV_ADDR (0x6E) // Chip ID Registers -#define OV5640_CHIP_ID (0x300A) -#define OV_CHIP_ID (0x0A) -#define ON_CHIP_ID (0x00) -#define HIMAX_CHIP_ID (0x0001) -#define GC_CHIP_ID (0xF0) +#define OV5640_CHIP_ID (0x300A) +#define OV_CHIP_ID (0x0A) +#define ON_CHIP_ID (0x00) +#define HIMAX_CHIP_ID (0x0001) +#define GC_CHIP_ID (0xF0) // Chip ID Values -#define OV2640_ID (0x26) -#define OV5640_ID (0x56) -#define OV7670_ID (0x76) -#define OV7690_ID (0x76) -#define OV7725_ID (0x77) -#define OV9650_ID (0x96) -#define MT9V034_ID (0x13) -#define MT9M114_ID (0x2481) -#define LEPTON_ID (0x54) -#define HM01B0_ID (0xB0) -#define GC2145_ID (0x21) +#define OV2640_ID (0x26) +#define OV5640_ID (0x56) +#define OV7670_ID (0x76) +#define OV7690_ID (0x76) +#define OV7725_ID (0x77) +#define OV9650_ID (0x96) +#define MT9V034_ID (0x13) +#define MT9M114_ID (0x2481) +#define LEPTON_ID (0x54) +#define HM01B0_ID (0xB0) +#define GC2145_ID (0x21) // Wide ID -#define PAJ6100_ID (0x6100) +#define PAJ6100_ID (0x6100) +#define FROGEYE2020_ID (0x2020) typedef enum { FRAMESIZE_INVALID = 0, diff --git a/src/omv/common/sensor_utils.c b/src/omv/common/sensor_utils.c index 622b4ac0d..1e8ab56eb 100644 --- a/src/omv/common/sensor_utils.c +++ b/src/omv/common/sensor_utils.c @@ -27,6 +27,7 @@ #include "lepton.h" #include "hm01b0.h" #include "paj6100.h" +#include "frogeye2020.h" #include "gc2145.h" #include "framebuffer.h" #include "omv_boardconfig.h" @@ -156,13 +157,9 @@ __weak int sensor_reset() // Re-enable the bus. cambus_enable(&sensor.bus, true); - // Check if the control is supported. - if (sensor.reset == NULL) { - return SENSOR_ERROR_CTL_UNSUPPORTED; - } - // Call sensor-specific reset function - if (sensor.reset(&sensor) != 0) { + if (sensor.reset != NULL + && sensor.reset(&sensor) != 0) { return SENSOR_ERROR_CTL_FAILED; } @@ -286,6 +283,14 @@ int sensor_probe_init(uint32_t bus_id, uint32_t bus_speed) break; #endif //(OMV_ENABLE_GC2145 == 1) + #if (OMV_ENABLE_FROGEYE2020 == 1) + case FROGEYE2020_SLV_ADDR: + sensor.chip_id_w = FROGEYE2020_ID; + sensor.pwdn_pol = ACTIVE_HIGH; + sensor.reset_pol = ACTIVE_HIGH; + break; + #endif // (OMV_ENABLE_FROGEYE2020 == 1) + #if (OMV_ENABLE_PAJ6100 == 1) case 0: if (paj6100_detect(&sensor)) { @@ -403,6 +408,15 @@ int sensor_probe_init(uint32_t bus_id, uint32_t bus_speed) break; #endif // (OMV_ENABLE_PAJ6100 == 1) + #if (OMV_ENABLE_FROGEYE2020 == 1) + case FROGEYE2020_ID: + if (sensor_set_xclk_frequency(FROGEYE2020_XCLK_FREQ) != 0) { + return SENSOR_ERROR_TIM_INIT_FAILED; + } + init_ret = frogeye2020_init(&sensor); + break; + #endif // (OMV_ENABLE_FROGEYE2020 == 1) + default: return SENSOR_ERROR_ISC_UNSUPPORTED; break; diff --git a/src/omv/ports/stm32/omv_portconfig.mk b/src/omv/ports/stm32/omv_portconfig.mk index 0ed201114..aa3019447 100644 --- a/src/omv/ports/stm32/omv_portconfig.mk +++ b/src/omv/ports/stm32/omv_portconfig.mk @@ -154,6 +154,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/sensors/, \ hm01b0.o \ gc2145.o \ paj6100.o \ + frogeye2020.o \ ) FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/, \ @@ -511,6 +512,7 @@ UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/sensors/, \ hm01b0.o \ gc2145.o \ paj6100.o \ + frogeye2020.o \ ) UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/,\ diff --git a/src/omv/sensors/frogeye2020.c b/src/omv/sensors/frogeye2020.c new file mode 100644 index 000000000..c35cee876 --- /dev/null +++ b/src/omv/sensors/frogeye2020.c @@ -0,0 +1,35 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * FrogEye2020 driver. + */ +#include "omv_boardconfig.h" +#if (OMV_ENABLE_FROGEYE2020 == 1) + +#include "sensor.h" + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + return (pixformat == PIXFORMAT_GRAYSCALE) ? 0 : -1; +} + +static int set_framesize(sensor_t *sensor, framesize_t framesize) +{ + return (framesize == FRAMESIZE_QVGA) ? 0 : -1; +} + +int frogeye2020_init(sensor_t *sensor) +{ + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->hw_flags.pixck = 1; + sensor->hw_flags.gs_bpp = 1; + return 0; +} + +#endif // (OMV_ENABLE_FROGEYE2020 == 1) diff --git a/src/omv/sensors/frogeye2020.h b/src/omv/sensors/frogeye2020.h new file mode 100644 index 000000000..f2b858aca --- /dev/null +++ b/src/omv/sensors/frogeye2020.h @@ -0,0 +1,15 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * FrogEye2020 driver. + */ +#ifndef __FROGEYE2020_H__ +#define __FROGEYE2020_H__ +#define FROGEYE2020_XCLK_FREQ (5000000) +int frogeye2020_init(sensor_t *sensor); +#endif // __FROGEYE2020_H__ From 899f80759f63a9262bbd59ec6accd3b81463e9f4 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sat, 16 Oct 2021 12:10:24 -0700 Subject: [PATCH 2/3] Fix errode/dilate to work on non-white pixels --- src/omv/imlib/binary.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/omv/imlib/binary.c b/src/omv/imlib/binary.c index 680e9765f..eb8dacf37 100644 --- a/src/omv/imlib/binary.c +++ b/src/omv/imlib/binary.c @@ -757,8 +757,8 @@ static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_ for (int j = -ksize; j <= ksize; j++) { uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img,y+j); // subtract old left edge and add new right edge to sum - acc -= (IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,x-ksize-1) & 1); // values have already been thresholded to 0x00 or 0xFF - acc += (IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,x+ksize) & 1); + acc -= (IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,x-ksize-1) > 0); + acc += (IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,x+ksize) > 0); } // for j } else { // slower way which checks boundaries per pixel acc = e_or_d ? 0 : -1; // Don't count center pixel... @@ -767,8 +767,8 @@ static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_ IM_MIN(IM_MAX(y + j, 0), (img->h - 1))); for (int k = -ksize; k <= ksize; k++) { - acc += ((IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, - IM_MIN(IM_MAX(x + k, 0), (img->w - 1)))) >> 7); + acc += (IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (img->w - 1)))) > 0; } // for k } // for j } @@ -821,8 +821,8 @@ static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_ for (int j = -ksize; j <= ksize; j++) { uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img,y+j); // subtract old left column and add new right column - acc -= IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,x-ksize-1) & 1; // already 0 or FFFF - acc += IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,x+ksize) & 1; // (pre-thresholded) + acc -= IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,x-ksize-1) > 0; + acc += IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,x+ksize) > 0; } } else { // need to check boundary conditions for each pixel acc = e_or_d ? 0 : -1; // Don't count center pixel... @@ -832,7 +832,7 @@ static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_ for (int k = -ksize; k <= ksize; k++) { acc += (IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, - IM_MIN(IM_MAX(x + k, 0), (img->w - 1)))) & 1; // already 0 or FFFF + IM_MIN(IM_MAX(x + k, 0), (img->w - 1)))) > 0; } } } From 7f3b14ec0eff6cbaedd921b8fd8a6a7b790656c3 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sat, 16 Oct 2021 12:29:13 -0700 Subject: [PATCH 3/3] Add event camera examples --- .../OpenMV/37-Event-Cameras/frogeye2020.py | 39 ++++++++++++++++ .../frogeye2020_with_tracking.py | 45 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 scripts/examples/OpenMV/37-Event-Cameras/frogeye2020.py create mode 100644 scripts/examples/OpenMV/37-Event-Cameras/frogeye2020_with_tracking.py diff --git a/scripts/examples/OpenMV/37-Event-Cameras/frogeye2020.py b/scripts/examples/OpenMV/37-Event-Cameras/frogeye2020.py new file mode 100644 index 000000000..445c0849a --- /dev/null +++ b/scripts/examples/OpenMV/37-Event-Cameras/frogeye2020.py @@ -0,0 +1,39 @@ +# This example shows off using the frogeye2020 event camera. +# +# The frogeye2020 is a 320x240 event camera. There are two bits per pixel which show no motion, +# motion in one direction, or motion in another direction. The sensor runs at 50 FPS. + +import sensor, image, time + +sensor.reset() +sensor.set_pixformat(sensor.GRAYSCALE) +sensor.set_framesize(sensor.QVGA) + +palette = image.Image(1, 256, sensor.RGB565) + +for i in range(64): + palette.set_pixel(0, i, (0, 0, 0)) + +for i in range(64, 128): + palette.set_pixel(0, i, (255, 0, 0)) + +for i in range(128, 192): + palette.set_pixel(0, i, (0, 0, 255)) + +for i in range(192, 256): + palette.set_pixel(0, i, (0, 255, 0)) + +clock = time.clock() + +while(True): + clock.tick() + + img = sensor.snapshot() + # Handle sensor rotation. + img.assign(hmirror=True, vflip=True) + # Make pretty. + img.to_rainbow(color_palette=palette) + # Cleanup noise. + img.erode(1) + + print(clock.fps()) diff --git a/scripts/examples/OpenMV/37-Event-Cameras/frogeye2020_with_tracking.py b/scripts/examples/OpenMV/37-Event-Cameras/frogeye2020_with_tracking.py new file mode 100644 index 000000000..c373715dc --- /dev/null +++ b/scripts/examples/OpenMV/37-Event-Cameras/frogeye2020_with_tracking.py @@ -0,0 +1,45 @@ +# This example shows off using the frogeye2020 event camera with tracking. +# +# The frogeye2020 is a 320x240 event camera. There are two bits per pixel which show no motion, +# motion in one direction, or motion in another direction. The sensor runs at 50 FPS. + +import sensor, image, time + +sensor.reset() +sensor.set_pixformat(sensor.GRAYSCALE) +sensor.set_framesize(sensor.QVGA) + +palette = image.Image(1, 256, sensor.RGB565) + +for i in range(64): + palette.set_pixel(0, i, (0, 0, 0)) + +for i in range(64, 128): + palette.set_pixel(0, i, (255, 0, 0)) + +for i in range(128, 192): + palette.set_pixel(0, i, (0, 0, 255)) + +for i in range(192, 256): + palette.set_pixel(0, i, (0, 255, 0)) + +clock = time.clock() + +while(True): + clock.tick() + + img = sensor.snapshot() + # Handle sensor rotation. + img.assign(hmirror=True, vflip=True) + # Make pretty. + img.to_rainbow(color_palette=palette) + # Cleanup noise. + img.erode(1) + + blobs = img.find_blobs([(0, 0)], invert=True, + pixels_threshold=10, area_threshold=10, merge=False) + + for blob in blobs: + img.draw_rectangle(blob.rect(), color=(0, 255, 0)) + + print(clock.fps())