Merge pull request #2565 from openmv/romfs_support
Some checks are pending
🔎 Check Code Formatting / formatting-check (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions

misc: romfs support.
This commit is contained in:
Ibrahim Abdelkader 2025-03-29 18:58:05 +02:00 committed by GitHub
commit ff4fd1bf6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
60 changed files with 917 additions and 361 deletions

View File

@ -16,7 +16,7 @@ sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
model = ml.Model("person_detect", load_to_fb=True)
model = ml.Model("/rom/person_detect.tflite")
print(model)
clock = time.clock()

View File

@ -23,7 +23,7 @@ min_confidence = 0.4
threshold_list = [(math.ceil(min_confidence * 255), 255)]
# Load built-in FOMO face detection model
model = ml.Model("fomo_face_detection")
model = ml.Model("/rom/fomo_face_detection.tflite")
print(model)
# Alternatively, models can be loaded from the filesystem storage.

View File

@ -18,7 +18,7 @@ from ulab import numpy as np
# The model is built-in on the RT1062. On other OpenMV Cam's with limited flash space please grab
# the model from here: https://github.com/openmv/openmv/tree/master/src/lib/tflm/models and
# copy it to the OpenMV Cam's file system. E.g. model = ml.Model("force_int_quant.tflite")
model = ml.Model("force_int_quant")
model = ml.Model("/rom/force_int_quant.tflite")
print(model)
i = np.array([-3, -1, -2, 5, -2, 10, -1, 9, 0, # noqa

View File

@ -49,10 +49,10 @@ class MicroSpeech:
def __init__(self, preprocessor=None, micro_speech=None, labels=None, **kwargs):
self.preprocessor = preprocessor
if preprocessor is None:
self.preprocessor = Model("audio_preprocessor")
self.preprocessor = Model("/rom/audio_preprocessor.tflite")
self.labels, self.micro_speech = (labels, micro_speech)
if micro_speech is None:
self.micro_speech = Model("micro_speech")
self.micro_speech = Model("/rom/micro_speech.tflite")
self.labels = self.micro_speech.labels
# 16 samples/1ms
self.audio_buffer = np.zeros((1, _SAMPLES_PER_STEP * 3), dtype=np.int16)

View File

@ -34,6 +34,11 @@ from ml.preprocessing import Normalization
class Model(uml.Model):
def __init__(self, *args, **kwargs):
super().__init__(*args, kwargs.get("load_to_fb", False))
try:
path = args[0].split(".")[0] + ".txt"
self.labels = [line.rstrip('\n') for line in open(path, "r")]
except Exception:
self.labels = None
def predict(self, args, **kwargs):
args = [Normalization()(x) if isinstance(x, image.Image) else x for x in args]

View File

@ -39,9 +39,9 @@ ECHO = $(Q)@echo
MAKE = $(Q)make
CAT = $(Q)cat
TFLITE2C = tflite2c.py
MKROMFS = mkromfs.py
# Targets
TARGET ?= OPENMV4
OPENMV = openmv
FIRMWARE = firmware
@ -51,6 +51,13 @@ JLINK_SPEED ?= 100000
JLINK_DEVICE ?= unspecified
JLINK_GDB_SERVER ?= /opt/JLink/JLinkGDBServer
ifeq ($(TARGET),)
ifneq ($(MAKECMDGOALS),clean)
$(error Invalid or no TARGET specified)
endif
TARGET=OPENMV4
endif
# Directories
TOP_DIR=$(shell pwd)
BUILD=$(TOP_DIR)/build

@ -1 +1 @@
Subproject commit 61fbdadd42d379141d081fa4c89a095e74929a9d
Subproject commit e6ad965cd3d4138b57329aecb752aec582a0033a

View File

@ -6,16 +6,10 @@
# This work is licensed under the MIT license, see the file LICENSE for details.
#
# TFLM Makefile
override CFLAGS := $(CFLAGS) -Wno-unused-variable
GENERATED_H := $(BUILD)/tflm_builtin_models.h
GENERATED_C := $(BUILD)/tflm_builtin_models.c
HDR_OBJS = $(BUILD)/tflm_builtin_models.o
LIB_OBJS = $(BUILD)/tflm_backend.o
OBJ_DIRS = $(sort $(dir $(HDR_OBJS)))
ifeq ($(strip $(VELA_ARGS)),)
override VELA_ARGS := ""
endif
OBJ_DIRS = $(sort $(dir $(LIB_OBJS)))
override CFLAGS := $(CFLAGS) -Wno-unused-variable
# Extra module flags.
CXXFLAGS += $(filter-out -std=gnu99 -std=gnu11,$(CFLAGS)) \
@ -45,24 +39,11 @@ ifeq ($(MICROPY_PY_CUBEAI), 1)
SRC_USERMOD += $(OMV_MOD_DIR)/../../stm32cubeai/py_st_nn.c
endif
all: | headers $(LIB_OBJS)
headers: | $(OBJ_DIRS) $(HDR_OBJS)
all: $(LIB_OBJS) | $(OBJ_DIRS)
$(OBJ_DIRS):
$(MKDIR) -p $@
$(GENERATED_H): $(wildcard models/*)
$(ECHO) "GEN $(shell realpath --relative-to=pwd $@)"
$(PYTHON) $(TOOLS)/$(TFLITE2C) --input models --build-dir ${BUILD} \
--header > $(BUILD)/tflm_builtin_models.h
$(GENERATED_C): $(wildcard models/*)
$(ECHO) "GEN $(shell realpath --relative-to=pwd $@)"
$(PYTHON) $(TOOLS)/$(TFLITE2C) --input models --build-dir ${BUILD} \
--vela-args ${VELA_ARGS} > $(BUILD)/tflm_builtin_models.c
$(HDR_OBJS): $(GENERATED_H) $(GENERATED_C)
$(BUILD)/%.o : %.c
$(ECHO) "CC $<"
$(CC) $(CFLAGS) -c -o $@ $<
@ -75,5 +56,4 @@ $(BUILD)/%.o : %.s
$(ECHO) "AS $<"
$(AS) $(AFLAGS) $< -o $@
-include $(HDR_OBJS:%.o=%.d)
-include $(LIB_OBJS:%.o=%.d)

View File

@ -110,17 +110,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#if !defined(CUBEAI)
#define IMLIB_ENABLE_TFLM_BUILTIN_MICRO_SPEECH
#define IMLIB_ENABLE_TFLM_BUILTIN_AUDIO_PREPROCESSOR
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#endif
// Enable FAST (20+ KBs).
#define IMLIB_ENABLE_AGAST

View File

@ -178,6 +178,10 @@
#define OMV_FLASH_EXT_ORIGIN 0x90000000
#define OMV_FLASH_EXT_LENGTH 16M
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x90B00000
#define OMV_ROMFS_PART0_LENGTH 4M
// MDMA configuration
#define OMV_MDMA_CHANNEL_DCMI_0 (0)
#define OMV_MDMA_CHANNEL_DCMI_1 (1)

View File

@ -0,0 +1,58 @@
{
"0": {
"size": "0x400000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/audio_preprocessor.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/yolo_v5_224_nano.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/force_int_quant.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/micro_speech.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/person_detect.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -110,10 +110,8 @@
// Enable find_barcodes() (42 KB)
//#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
//#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable AGAST.
// #define IMLIB_ENABLE_AGAST

View File

@ -109,10 +109,8 @@
// Enable find_barcodes() (42 KB)
//#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
//#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable AGAST.
// #define IMLIB_ENABLE_AGAST

View File

@ -110,17 +110,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features()
#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#if !defined(CUBEAI)
#define IMLIB_ENABLE_TFLM_BUILTIN_MICRO_SPEECH
#define IMLIB_ENABLE_TFLM_BUILTIN_AUDIO_PREPROCESSOR
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#endif
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -164,6 +164,10 @@
#define OMV_FLASH_EXT_ORIGIN 0x90000000
#define OMV_FLASH_EXT_LENGTH 16M
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x90B00000
#define OMV_ROMFS_PART0_LENGTH 4M
// MDMA configuration
#define OMV_MDMA_CHANNEL_DCMI_0 (0)
#define OMV_MDMA_CHANNEL_DCMI_1 (1)

View File

@ -0,0 +1,52 @@
{
"0": {
"size": "0x400000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/micro_speech.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/audio_preprocessor.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/person_detect.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/force_int_quant.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -110,17 +110,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#if !defined(CUBEAI)
#define IMLIB_ENABLE_TFLM_BUILTIN_MICRO_SPEECH
#define IMLIB_ENABLE_TFLM_BUILTIN_AUDIO_PREPROCESSOR
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#endif
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -181,6 +181,10 @@
#define OMV_FLASH_EXT_ORIGIN 0x90000000
#define OMV_FLASH_EXT_LENGTH 16M
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x90B00000
#define OMV_ROMFS_PART0_LENGTH 4M
// MDMA configuration
#define OMV_MDMA_CHANNEL_DCMI_0 (0)
#define OMV_MDMA_CHANNEL_DCMI_1 (1)

View File

@ -0,0 +1,58 @@
{
"0": {
"size": "0x400000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/audio_preprocessor.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/yolo_v5_224_nano.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/force_int_quant.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/micro_speech.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/person_detect.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -67,10 +67,8 @@
// Enable find_barcodes() (42 KB)
//#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
//#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Stereo Imaging
// #define IMLIB_ENABLE_STEREO_DISPARITY

View File

@ -106,10 +106,8 @@
// Enable find_barcodes() (42 KB)
//#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
//#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -112,6 +112,10 @@
#define OMV_FLASH_TXT_ORIGIN 0x08010000
#define OMV_FLASH_TXT_LENGTH 960K
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x080E0000
#define OMV_ROMFS_PART0_LENGTH 128K
// CSI I2C bus
#define OMV_CSI_I2C_ID (1)
#define OMV_CSI_I2C_SPEED (OMV_I2C_SPEED_STANDARD)

View File

@ -52,8 +52,9 @@ static const pin_t omv_boot_pins[] = {
static const partition_t OMV_BOOT_DFU_PARTITIONS[] = {
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 1, .start = 0x08000000, .limit = 0x08008000, .attr = 0 }, // Boot
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08008000, .limit = 0x08010000, .attr = 0 }, // FFS
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08010000, .limit = 0x08100000, .attr = 0 }, // Firmware
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08010000, .limit = 0x080E0000, .attr = 0 }, // Firmware
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x080E0000, .limit = 0x08100000, .attr = 0 }, // ROMFS
};
#define OMV_BOOT_DFU_PARTITIONS_COUNT 3 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE"
#define OMV_BOOT_DFU_PARTITIONS_COUNT 4 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE", "ROMFS0"
#endif //__OMV_BOOTCONFIG_H__

View File

@ -0,0 +1,22 @@
{
"0": {
"size": "0x20000",
"entries": [
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -110,15 +110,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
#define IMLIB_ENABLE_FEATURES
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#if !defined(CUBEAI)
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#endif
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -1,14 +1,33 @@
include("$(MPY_DIR)/extmod/asyncio")
# Filesystem
freeze ("$(OMV_LIB_DIR)/", "_boot.py")
freeze ("$(OMV_LIB_DIR)/", "bno055.py")
# Drivers
require("onewire")
require("ds18x20")
require("dht")
require("neopixel")
freeze ("$(OMV_LIB_DIR)/", "modbus.py")
freeze ("$(OMV_LIB_DIR)/", "mqtt.py")
freeze ("$(OMV_LIB_DIR)/", "mutex.py")
freeze ("$(OMV_LIB_DIR)/", "pid.py")
freeze ("$(OMV_LIB_DIR)/", "rpc.py")
freeze ("$(OMV_LIB_DIR)/", "rtsp.py")
freeze ("$(OMV_LIB_DIR)/", "bno055.py")
freeze ("$(OMV_LIB_DIR)/", "ssd1306.py")
freeze ("$(OMV_LIB_DIR)/", "tb6612.py")
freeze ("$(OMV_LIB_DIR)/", "vl53l1x.py")
freeze ("$(OMV_LIB_DIR)/", "machine.py")
freeze ("$(OMV_LIB_DIR)/", "display.py")
freeze ("$(OMV_LIB_DIR)/ml")
# Networking
require("ssl")
require("ntptime")
require("webrepl")
freeze ("$(OMV_LIB_DIR)/", "rpc.py")
freeze ("$(OMV_LIB_DIR)/", "rtsp.py")
freeze ("$(OMV_LIB_DIR)/", "mqtt.py")
freeze ("$(OMV_LIB_DIR)/", "requests.py")
# Utils
require("time")
require("logging")
freeze ("$(OMV_LIB_DIR)/", "mutex.py")

View File

@ -109,7 +109,11 @@
#define OMV_FLASH_FFS_ORIGIN 0x08008000
#define OMV_FLASH_FFS_LENGTH 96K
#define OMV_FLASH_TXT_ORIGIN 0x08020000
#define OMV_FLASH_TXT_LENGTH 1920K
#define OMV_FLASH_TXT_LENGTH 1664K
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x081C0000
#define OMV_ROMFS_PART0_LENGTH 256K
// CSI I2C bus
#define OMV_CSI_I2C_ID (1)

View File

@ -52,8 +52,9 @@ static const pin_t omv_boot_pins[] = {
static const partition_t OMV_BOOT_DFU_PARTITIONS[] = {
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 1, .start = 0x08000000, .limit = 0x08008000, .attr = 0 }, // Boot
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08008000, .limit = 0x08020000, .attr = 0 }, // FFS
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08020000, .limit = 0x08200000, .attr = 0 }, // FIRMWARE
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08020000, .limit = 0x081C0000, .attr = 0 }, // FIRMWARE
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x081C0000, .limit = 0x08200000, .attr = 0 }, // ROMFS
};
#define OMV_BOOT_DFU_PARTITIONS_COUNT 3 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE"
#define OMV_BOOT_DFU_PARTITIONS_COUNT 4 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE", "ROMFS0"
#endif //__OMV_BOOTCONFIG_H__

View File

@ -0,0 +1,28 @@
{
"0": {
"size": "0x40000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -110,15 +110,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features()
#define IMLIB_ENABLE_FEATURES
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#if !defined(CUBEAI)
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#endif
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -170,7 +170,11 @@
#define OMV_FLASH_FFS_ORIGIN 0x08020000
#define OMV_FLASH_FFS_LENGTH 128K
#define OMV_FLASH_TXT_ORIGIN 0x08040000
#define OMV_FLASH_TXT_LENGTH 1792K
#define OMV_FLASH_TXT_LENGTH 1664K
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x081E0000
#define OMV_ROMFS_PART0_LENGTH 128K
// MDMA configuration
#define OMV_MDMA_CHANNEL_DCMI_0 (0)

View File

@ -52,8 +52,9 @@ static const pin_t omv_boot_pins[] = {
static const partition_t OMV_BOOT_DFU_PARTITIONS[] = {
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 1, .start = 0x08000000, .limit = 0x08020000, .attr = 0 }, // Boot
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08020000, .limit = 0x08040000, .attr = 0 }, // FFS
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08040000, .limit = 0x08200000, .attr = 0 }, // FIRMWARE
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08040000, .limit = 0x081E0000, .attr = 0 }, // FIRMWARE
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x081E0000, .limit = 0x08200000, .attr = 0 }, // ROMFS
};
#define OMV_BOOT_DFU_PARTITIONS_COUNT 3 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE"
#define OMV_BOOT_DFU_PARTITIONS_COUNT 4 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE", "ROMFS0"
#endif //__OMV_BOOTCONFIG_H__

View File

@ -0,0 +1,23 @@
{
"0": {
"size": "0x20000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -110,15 +110,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features() and Haar cascades.
#define IMLIB_ENABLE_FEATURES
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#if !defined(CUBEAI)
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#endif
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -167,6 +167,10 @@
#define OMV_FLASH_TXT_ORIGIN 0x08040000
#define OMV_FLASH_TXT_LENGTH 1792K
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x91800000
#define OMV_ROMFS_PART0_LENGTH 8M
// MDMA configuration
#define OMV_MDMA_CHANNEL_DCMI_0 (0)
#define OMV_MDMA_CHANNEL_DCMI_1 (1)

View File

@ -62,7 +62,8 @@ static const partition_t OMV_BOOT_DFU_PARTITIONS[] = {
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08020000, .limit = 0x08040000, .attr = 0 }, // FFS
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08040000, .limit = 0x08200000, .attr = 0 }, // FIRMWARE
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 0, .start = 0x00000000, .limit = 0x02000000, .attr = 0 }, // QSPI
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 0, .start = 0x01800000, .limit = 0x02000000, .attr = 0 }, // ROMFS
};
#define OMV_BOOT_DFU_PARTITIONS_COUNT 4 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE", "SPI_FLASH"
#define OMV_BOOT_DFU_PARTITIONS_COUNT 5 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE", "SPI_FLASH", "ROMFS0"
#endif //__OMV_BOOTCONFIG_H__

View File

@ -0,0 +1,58 @@
{
"0": {
"size": "0x800000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/audio_preprocessor.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/yolo_v5_224_nano.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/force_int_quant.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/micro_speech.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/person_detect.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -110,15 +110,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
#define IMLIB_ENABLE_FEATURES
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#if !defined(CUBEAI)
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#endif
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -157,6 +157,10 @@
#define OMV_FLASH_TXT_ORIGIN 0x08040000
#define OMV_FLASH_TXT_LENGTH 1792K
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x91800000
#define OMV_ROMFS_PART0_LENGTH 8M
// MDMA configuration
#define OMV_MDMA_CHANNEL_DCMI_0 (0)
#define OMV_MDMA_CHANNEL_DCMI_1 (1)

View File

@ -62,7 +62,8 @@ static const partition_t OMV_BOOT_DFU_PARTITIONS[] = {
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08020000, .limit = 0x08040000, .attr = 0 }, // FFS
{ .type = PTYPE_AXI_FLASH, .region = -1, .rdonly = 0, .start = 0x08040000, .limit = 0x08200000, .attr = 0 }, // FIRMWARE
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 0, .start = 0x00000000, .limit = 0x02000000, .attr = 0 }, // QSPI
{ .type = PTYPE_SPI_FLASH, .region = -1, .rdonly = 0, .start = 0x01800000, .limit = 0x02000000, .attr = 0 }, // ROMFS
};
#define OMV_BOOT_DFU_PARTITIONS_COUNT 4 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE", "SPI_FLASH"
#define OMV_BOOT_DFU_PARTITIONS_COUNT 5 // Must be a literal
#define OMV_BOOT_DFU_PARTITIONS_STR "BOOTLOADER", "FILESYSTEM", "FIRMWARE", "SPI_FLASH", "ROMFS0"
#endif //__OMV_BOOTCONFIG_H__

View File

@ -0,0 +1,58 @@
{
"0": {
"size": "0x800000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/audio_preprocessor.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/yolo_v5_224_nano.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/force_int_quant.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/micro_speech.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/person_detect.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -114,15 +114,8 @@
// Enable find_barcodes() (42 KB)
#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
#define IMLIB_ENABLE_FEATURES
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable Tensor Flow
#define IMLIB_ENABLE_TFLM_BUILTIN_FOMO_FACE_DETECTION
#define IMLIB_ENABLE_TFLM_BUILTIN_PERSON_DETECT
#define IMLIB_ENABLE_TFLM_BUILTIN_FORCE_INT_QUANT
// Enable AGAST.
#define IMLIB_ENABLE_AGAST

View File

@ -92,7 +92,7 @@
#define OMV_GC_BLOCK0_MEMORY OCRM2 // Extra GC block 0.
#define OMV_GC_BLOCK0_SIZE (26K)
#define OMV_GC_BLOCK1_MEMORY DTCM // Main GC block
#define OMV_GC_BLOCK1_SIZE (290K)
#define OMV_GC_BLOCK1_SIZE (288K)
#define OMV_GC_BLOCK2_MEMORY DRAM // Extra GC block 1.
#define OMV_GC_BLOCK2_SIZE (8M)
#define OMV_RAMFUNC_MEMORY ITCM2 // RAM code memory.
@ -123,6 +123,10 @@
#define OMV_FLASH_FFS_ORIGIN 0x60400000
#define OMV_FLASH_FFS_LENGTH 0x00400000
// ROMFS configuration.
#define OMV_ROMFS_PART0_ORIGIN 0x60800000
#define OMV_ROMFS_PART0_LENGTH 8M
// CSI I2C bus
#define OMV_CSI_I2C_ID (1)
#define OMV_CSI_I2C_SPEED (OMV_I2C_SPEED_STANDARD)

View File

@ -4,7 +4,7 @@ FPU=fpv5-sp-d16
FABI=hard
PORT=mimxrt
JLINK_DEVICE=MIMXRT1062xxx6A
OMV_BOARD_CFLAGS=-DBOARD_FLASH_SIZE=0x800000
OMV_BOARD_CFLAGS=-DBOARD_FLASH_SIZE=0x1000000
OMV_FIRM_BASE=0x60000000
OMV_FIRM_ADDR=0x60000000
OMV_HSE_VALUE=12000000

View File

@ -0,0 +1,58 @@
{
"0": {
"size": "0x800000",
"entries": [
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/audio_preprocessor.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/fomo_face_detection.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/yolo_v5_224_nano.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/force_int_quant.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/micro_speech.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "tflite",
"path": "{TOP}/lib/tflm/models/person_detect.tflite",
"alignment": 16,
"optimize": "Performance"
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_eye.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_smile.xml",
"stages": 0
},
{
"type": "haar",
"path": "{TOP}/lib/haar/haarcascade_frontalface.xml",
"stages": 0
}
]
}
}

View File

@ -110,10 +110,8 @@
// Enable find_barcodes() (42 KB)
//#define IMLIB_ENABLE_BARCODES
// Enable find_features() and built-in Haar cascades. (75KBs)
// Enable find_features().
//#define IMLIB_ENABLE_FEATURES
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
// Enable FAST (20+ KBs).
// #define IMLIB_ENABLE_FAST

View File

@ -280,4 +280,9 @@ OMV_DMA_MEMORY_NEW(3)
. = ALIGN(4);
} > FLASH_TEXT
// Only one partition is currently supported.
#if defined(OMV_ROMFS_PART0_ORIGIN)
_micropy_hw_romfs_part0_start = OMV_ROMFS_PART0_ORIGIN;
_micropy_hw_romfs_part0_size = OMV_ROMFS_PART0_LENGTH;
#endif
.ARM.attributes 0 : { *(.ARM.attributes) }

View File

@ -43,6 +43,7 @@ export ECHO
export MAKE
export CAT
export TFLITE2C
export MKROMFS
# Export Flags
export CFLAGS

File diff suppressed because one or more lines are too long

View File

@ -26,13 +26,15 @@
*/
#include <stdio.h>
#include "py/obj.h"
#include "py/nlr.h"
#include "py/runtime.h"
#if MICROPY_VFS
#include "py/stream.h"
#include "extmod/vfs.h"
#endif
#include "xalloc.h"
#include "imlib.h"
// built-in cascades
#include "cascade.h"
#include "file_utils.h"
#ifdef IMLIB_ENABLE_FEATURES
static int eval_weak_classifier(cascade_t *cascade, point_t pt, int t_idx, int w_idx, int r_idx) {
@ -178,141 +180,123 @@ array_t *imlib_detect_objects(image_t *image, cascade_t *cascade, rectangle_t *r
return objects;
}
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
#if MICROPY_VFS
static void *cascade_buffer_read(uint8_t **buf, size_t size) {
uint8_t *buf8 = *buf;
*buf += size;
return buf8;
}
int imlib_load_cascade_from_file(cascade_t *cascade, const char *path) {
int i;
FIL fp;
FRESULT res = FR_OK;
int error = 0;
mp_obj_t args[2] = {
mp_obj_new_str_from_cstr(path),
MP_OBJ_NEW_QSTR(MP_QSTR_rb),
};
file_open(&fp, path, true, FA_READ | FA_OPEN_EXISTING);
memset(cascade, 0, sizeof(cascade_t));
// Read detection window size
file_read(&fp, &cascade->window, sizeof(cascade->window));
mp_buffer_info_t bufinfo;
mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(args), args, (mp_map_t *) &mp_const_empty_map);
// Read num stages
file_read(&fp, &cascade->n_stages, sizeof(cascade->n_stages));
if (mp_get_buffer(file, &bufinfo, MP_BUFFER_READ)) {
uint8_t *buf = (uint8_t *) bufinfo.buf + 12;
// Set detection window size and the number of stages.
cascade->window.w = ((uint32_t *) bufinfo.buf)[0];
cascade->window.h = ((uint32_t *) bufinfo.buf)[1];
cascade->n_stages = ((uint32_t *) bufinfo.buf)[2];
cascade->stages_array = xalloc(sizeof(*cascade->stages_array) * cascade->n_stages);
cascade->stages_thresh_array = xalloc(sizeof(*cascade->stages_thresh_array) * cascade->n_stages);
if (cascade->stages_array == NULL ||
cascade->stages_thresh_array == NULL) {
res = 20;
goto error;
// Set the number features in each stages
cascade->stages_array = cascade_buffer_read(&buf, cascade->n_stages);
// Skip alignment
if ((uint32_t) buf % 4) {
buf += 4 - ((uint32_t) buf % 4);
}
// Sum the number of features in each stages
for (size_t i = 0; i < cascade->n_stages; i++) {
cascade->n_features += cascade->stages_array[i];
}
// Set features thresh array, alpha1, alpha 2,rects weights and rects
cascade->stages_thresh_array = cascade_buffer_read(&buf, sizeof(int16_t) * cascade->n_stages);
cascade->tree_thresh_array = cascade_buffer_read(&buf, sizeof(int16_t) * cascade->n_features);
cascade->alpha1_array = cascade_buffer_read(&buf, sizeof(int16_t) * cascade->n_features);
cascade->alpha2_array = cascade_buffer_read(&buf, sizeof(int16_t) * cascade->n_features);
cascade->num_rectangles_array = cascade_buffer_read(&buf, sizeof(int8_t) * cascade->n_features);
// Sum the number of rectangles in all features
for (size_t i = 0; i < cascade->n_features; i++) {
cascade->n_rectangles += cascade->num_rectangles_array[i];
}
// Set rectangles weights and rectangles (number of rectangles * 4 points)
cascade->weights_array = cascade_buffer_read(&buf, cascade->n_rectangles);
cascade->rectangles_array = cascade_buffer_read(&buf, cascade->n_rectangles * 4);
} else {
// Read detection window size.
mp_stream_read_exactly(file, &cascade->window, sizeof(cascade->window), &error);
// Read the number of stages.
mp_stream_read_exactly(file, &cascade->n_stages, sizeof(cascade->n_stages), &error);
// Allocate stages array.
cascade->stages_array = xalloc(sizeof(int8_t) * cascade->n_stages);
// Read number of features in each stages
mp_stream_read_exactly(file, cascade->stages_array, cascade->n_stages, &error);
// Skip alignment
uint8_t padding[4];
if (cascade->n_stages % 4) {
mp_stream_read_exactly(file, padding, 4 - (cascade->n_stages % 4), &error);
}
// Sum the number of features in each stages
for (size_t i = 0; i < cascade->n_stages; i++) {
cascade->n_features += cascade->stages_array[i];
}
// Alloc features thresh array, alpha1, alpha 2,rects weights and rects
cascade->stages_thresh_array = xalloc(sizeof(int16_t) * cascade->n_stages);
cascade->tree_thresh_array = xalloc(sizeof(int16_t) * cascade->n_features);
cascade->alpha1_array = xalloc(sizeof(int16_t) * cascade->n_features);
cascade->alpha2_array = xalloc(sizeof(int16_t) * cascade->n_features);
cascade->num_rectangles_array = xalloc(sizeof(int8_t) * cascade->n_features);
// Read features thresh array, alpha1, alpha 2,rects weights and rects
mp_stream_read_exactly(file, cascade->stages_thresh_array, sizeof(int16_t) * cascade->n_stages, &error);
mp_stream_read_exactly(file, cascade->tree_thresh_array, sizeof(int16_t) * cascade->n_features, &error);
mp_stream_read_exactly(file, cascade->alpha1_array, sizeof(int16_t) * cascade->n_features, &error);
mp_stream_read_exactly(file, cascade->alpha2_array, sizeof(int16_t) * cascade->n_features, &error);
mp_stream_read_exactly(file, cascade->num_rectangles_array, cascade->n_features, &error);
// Sum the number of rectangles per feature
for (size_t i = 0; i < cascade->n_features; i++) {
cascade->n_rectangles += cascade->num_rectangles_array[i];
}
// Allocate weights and rectangles arrays.
cascade->weights_array = xalloc(cascade->n_rectangles);
cascade->rectangles_array = xalloc(cascade->n_rectangles * 4);
// Read rectangles weights and rectangles (number of rectangles * 4 points)
mp_stream_read_exactly(file, cascade->weights_array, sizeof(int8_t) * cascade->n_rectangles, &error);
mp_stream_read_exactly(file, cascade->rectangles_array, sizeof(int8_t) * cascade->n_rectangles * 4, &error);
}
/* read num features in each stages */
file_read(&fp, cascade->stages_array, sizeof(uint8_t) * cascade->n_stages);
/* sum num of features in each stages*/
for (i = 0, cascade->n_features = 0; i < cascade->n_stages; i++) {
cascade->n_features += cascade->stages_array[i];
if (error != 0) {
mp_raise_OSError(error);
}
/* alloc features thresh array, alpha1, alpha 2,rects weights and rects*/
cascade->tree_thresh_array = xalloc(sizeof(*cascade->tree_thresh_array) * cascade->n_features);
cascade->alpha1_array = xalloc(sizeof(*cascade->alpha1_array) * cascade->n_features);
cascade->alpha2_array = xalloc(sizeof(*cascade->alpha2_array) * cascade->n_features);
cascade->num_rectangles_array = xalloc(sizeof(*cascade->num_rectangles_array) * cascade->n_features);
if (cascade->tree_thresh_array == NULL ||
cascade->alpha1_array == NULL ||
cascade->alpha2_array == NULL ||
cascade->num_rectangles_array == NULL) {
res = 20;
goto error;
}
/* read stages thresholds */
file_read(&fp, cascade->stages_thresh_array, sizeof(int16_t) * cascade->n_stages);
/* read features thresholds */
file_read(&fp, cascade->tree_thresh_array, sizeof(*cascade->tree_thresh_array) * cascade->n_features);
/* read alpha 1 */
file_read(&fp, cascade->alpha1_array, sizeof(*cascade->alpha1_array) * cascade->n_features);
/* read alpha 2 */
file_read(&fp, cascade->alpha2_array, sizeof(*cascade->alpha2_array) * cascade->n_features);
/* read num rectangles per feature*/
file_read(&fp, cascade->num_rectangles_array, sizeof(*cascade->num_rectangles_array) * cascade->n_features);
/* sum num of recatngles per feature*/
for (i = 0, cascade->n_rectangles = 0; i < cascade->n_features; i++) {
cascade->n_rectangles += cascade->num_rectangles_array[i];
}
cascade->weights_array = xalloc(sizeof(*cascade->weights_array) * cascade->n_rectangles);
cascade->rectangles_array = xalloc(sizeof(*cascade->rectangles_array) * cascade->n_rectangles * 4);
if (cascade->weights_array == NULL ||
cascade->rectangles_array == NULL) {
res = 20;
goto error;
}
/* read rectangles weights */
file_read(&fp, cascade->weights_array, sizeof(*cascade->weights_array) * cascade->n_rectangles);
/* read rectangles num rectangles * 4 points */
file_read(&fp, cascade->rectangles_array, sizeof(*cascade->rectangles_array) * cascade->n_rectangles * 4);
error:
file_close(&fp);
return res;
mp_stream_close(file);
return 0;
}
#endif //(IMLIB_ENABLE_IMAGE_FILE_IO)
int imlib_load_cascade(cascade_t *cascade, const char *path) {
// built-in cascade
if (0) {
#ifdef IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
} else if (strcmp(path, "frontalface") == 0) {
cascade->window.w = frontalface_window_w;
cascade->window.h = frontalface_window_h;
cascade->n_stages = frontalface_n_stages;
cascade->stages_array = (uint8_t *) frontalface_stages_array;
cascade->stages_thresh_array = (int16_t *) frontalface_stages_thresh_array;
cascade->tree_thresh_array = (int16_t *) frontalface_tree_thresh_array;
cascade->alpha1_array = (int16_t *) frontalface_alpha1_array;
cascade->alpha2_array = (int16_t *) frontalface_alpha2_array;
cascade->num_rectangles_array = (int8_t *) frontalface_num_rectangles_array;
cascade->weights_array = (int8_t *) frontalface_weights_array;
cascade->rectangles_array = (int8_t *) frontalface_rectangles_array;
#if MICROPY_VFS
// xml cascade
return imlib_load_cascade_from_file(cascade, path);
#else
return -1;
#endif
#ifdef IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
} else if (strcmp(path, "eye") == 0) {
cascade->window.w = eye_window_w;
cascade->window.h = eye_window_h;
cascade->n_stages = eye_n_stages;
cascade->stages_array = (uint8_t *) eye_stages_array;
cascade->stages_thresh_array = (int16_t *) eye_stages_thresh_array;
cascade->tree_thresh_array = (int16_t *) eye_tree_thresh_array;
cascade->alpha1_array = (int16_t *) eye_alpha1_array;
cascade->alpha2_array = (int16_t *) eye_alpha2_array;
cascade->num_rectangles_array = (int8_t *) eye_num_rectangles_array;
cascade->weights_array = (int8_t *) eye_weights_array;
cascade->rectangles_array = (int8_t *) eye_rectangles_array;
#endif
} else {
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
// xml cascade
return imlib_load_cascade_from_file(cascade, path);
#else
return -1;
#endif
}
int i;
// sum the number of features in all stages
for (i = 0, cascade->n_features = 0; i < cascade->n_stages; i++) {
cascade->n_features += cascade->stages_array[i];
}
// sum the number of recatngles in all features
for (i = 0, cascade->n_rectangles = 0; i < cascade->n_features; i++) {
cascade->n_rectangles += cascade->num_rectangles_array[i];
}
return FR_OK;
}
#endif // IMLIB_ENABLE_FEATURES

View File

@ -6807,14 +6807,11 @@ mp_obj_t py_image_load_cascade(size_t n_args, const mp_obj_t *args, mp_map_t *kw
const char *path = mp_obj_str_get_str(args[0]);
// Load cascade from file or flash
int res = imlib_load_cascade(&cascade, path);
if (res != FR_OK) {
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
// cascade is not built-in and failed to load it from file.
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) file_strerror(res));
if (imlib_load_cascade(&cascade, path) != 0) {
#if MICROPY_VFS
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Failed to load Haar cascade"));
#else
// cascade is not built-in.
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Image I/O is not supported"));
#endif
}

View File

@ -37,6 +37,11 @@
#include "py/objtuple.h"
#include "py/binary.h"
#if MICROPY_VFS
#include "py/stream.h"
#include "extmod/vfs.h"
#endif
#include "py_helper.h"
#include "imlib_config.h"
@ -45,9 +50,6 @@
#include "file_utils.h"
#include "py_ml.h"
#include "ulab/code/ndarray.h"
#if MICROPY_PY_ML_TFLM
#include "tflm_builtin_models.h"
#endif
#ifndef IMLIB_ML_MODEL_ALIGN
#ifndef __DCACHE_PRESENT
@ -313,9 +315,6 @@ static void py_ml_model_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
case MP_QSTR_output_zero_point:
dest[0] = MP_OBJ_FROM_PTR(self->output_zero_point);
break;
case MP_QSTR_labels:
dest[0] = self->labels;
break;
default:
// Continue lookup in locals_dict.
dest[1] = MP_OBJ_SENTINEL;
@ -335,48 +334,41 @@ mp_obj_t py_ml_model_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const char *path = mp_obj_str_get_str(args[ARG_path].u_obj);
(void) path;
//const char *path = mp_obj_str_get_str(args[ARG_path].u_obj);
py_ml_model_obj_t *model = mp_obj_malloc_with_finaliser(py_ml_model_obj_t, &py_ml_model_type);
model->data = NULL;
model->fb_alloc = false;
model->labels = mp_const_none;
#if MICROPY_PY_ML_TFLM
// Model loading will use ROMFS eventually, so need to move to the backend.
for (const tflm_builtin_model_t *_model = &tflm_builtin_models[0]; _model->name != NULL; _model++) {
if (!strcmp(path, _model->name)) {
// Load model data.
model->size = _model->size;
model->data = (unsigned char *) _model->data;
#if MICROPY_VFS
mp_obj_t file_args[2] = {
args[ARG_path].u_obj,
MP_OBJ_NEW_QSTR(MP_QSTR_rb),
};
if (_model->n_labels == 0) {
break;
}
mp_buffer_info_t bufinfo;
mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(file_args), file_args, (mp_map_t *) &mp_const_empty_map);
// Load model labels
model->labels = mp_obj_new_list(_model->n_labels, NULL);
mp_obj_list_t *labels = MP_OBJ_TO_PTR(model->labels);
for (int l = 0; l < _model->n_labels; l++) {
const char *label = _model->labels[l];
labels->items[l] = mp_obj_new_str(label, strlen(label));
}
break;
if (mp_get_buffer(file, &bufinfo, MP_BUFFER_READ)) {
model->size = bufinfo.len;
model->data = bufinfo.buf;
model->fb_alloc = false;
} else {
int error;
// Get file size
mp_off_t res = mp_stream_seek(file, 0, MP_SEEK_END, &error);
if (res == (mp_off_t) -1) {
mp_raise_OSError(error);
}
if (mp_stream_seek(file, 0, MP_SEEK_SET, &error) == (mp_off_t) -1) {
mp_raise_OSError(error);
}
}
#endif
if (model->data == NULL) {
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
FIL fp;
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
model->size = f_size(&fp);
model->size = res;
model->fb_alloc = args[ARG_load_to_fb].u_bool;
// Allocate model data buffer.
if (model->fb_alloc) {
// The model's data will Not be free'd on exceptions.
fb_alloc_mark();
model->data = fb_alloc(model->size, FB_ALLOC_PREFER_SPEED | FB_ALLOC_CACHE_ALIGN);
// The model's data will Not be free'd on exceptions.
fb_alloc_mark_permanent();
} else {
// Align size and memory and keep a reference to the GC block.
@ -384,12 +376,18 @@ mp_obj_t py_ml_model_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
model->_raw = xalloc(size + IMLIB_ML_MODEL_ALIGN);
model->data = (void *) (((uintptr_t) model->_raw + IMLIB_ML_MODEL_ALIGN) & ~IMLIB_ML_MODEL_ALIGN);
}
file_read(&fp, model->data, model->size);
file_close(&fp);
#else
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
#endif
// Read file data.
mp_stream_read_exactly(file, model->data, model->size, &error);
if (error != 0) {
mp_raise_OSError(error);
}
}
mp_stream_close(file);
#else
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("File I/O is not supported"));
#endif
ml_backend_init_model(model);
return MP_OBJ_FROM_PTR(model);

View File

@ -51,7 +51,6 @@ typedef struct py_ml_model_obj {
mp_obj_tuple_t *output_scale;
mp_obj_tuple_t *output_zero_point;
mp_obj_tuple_t *output_dtype;
mp_obj_t labels;
void *state; // Private context for the backend.
} py_ml_model_obj_t;

View File

@ -23,8 +23,6 @@
*
* MicroPython port config.
*/
#include <mpconfigport.h>
#define MICROPY_NLR_RAISE_HOOK \
do { \
extern void fb_alloc_free_till_mark(); \
@ -32,7 +30,11 @@
} while (0);
#define MICROPY_ENABLE_VM_ABORT (1)
#define MICROPY_PY_NETWORK_PPP_LWIP (0)
#define MICROPY_PY_MACHINE_UART_IRQ (0)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_GC_SPLIT_HEAP (1)
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "lib/cyw43-driver/firmware/w4343WA1_7_45_98_102_combined.h"
#define MICROPY_BANNER_NAME_AND_VERSION "OpenMV " OPENMV_GIT_TAG "; MicroPython " MICROPY_GIT_TAG
#include <mpconfigport.h>

View File

@ -27,6 +27,9 @@ SYSTEM ?= mimxrt/system_$(MCU_SERIES)
STARTUP ?= mimxrt/startup_$(MCU_SERIES)
HAL_DIR ?= hal/mimxrt/$(MCU_SERIES)
ROMFS_IMAGE := $(FW_DIR)/romfs.stamp
ROMFS_CONFIG := $(OMV_BOARD_CONFIG_DIR)/romfs.json
# Compiler Flags
# TODO: -Wdouble-promotion
CFLAGS += -std=gnu99 \
@ -55,6 +58,8 @@ CFLAGS += -DCPU_$(MCU) \
-DXIP_BOOT_HEADER_ENABLE=1 \
-DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \
-DCFG_TUSB_MCU=OPT_MCU_MIMXRT1XXX \
-DCFG_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED \
-DCFG_TUD_TASK_QUEUE_SZ=128 \
-DCPU_HEADER_H='<$(MCU_SERIES).h>' \
-DCMSIS_MCU_H='<$(MCU_SERIES).h>' \
-DCLOCK_CONFIG_H='<boards/$(MCU_SERIES)_clock_config.h>' \
@ -413,6 +418,8 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/extmod/,\
vfs_fat_diskio.o \
vfs_fat_file.o \
vfs_lfs.o \
vfs_rom.o \
vfs_rom_file.o \
vfs_posix.o \
vfs_posix_file.o \
vfs_reader.o \
@ -555,13 +562,13 @@ ifeq ($(MICROPY_PY_ML_TFLM), 1)
OMV_CFLAGS += -I$(BUILD)/$(TENSORFLOW_DIR)/
FIRM_OBJ += $(addprefix $(BUILD)/$(TENSORFLOW_DIR)/, \
tflm_backend.o \
tflm_builtin_models.o \
)
LIBS += $(TOP_DIR)/$(TENSORFLOW_DIR)/libtflm/lib/libtflm-$(CPU)+fp-release.a
endif
###################################################
all: $(OPENMV)
all: $(FIRMWARE) .WAIT $(ROMFS_IMAGE)
$(SIZE) $(FW_DIR)/$(FIRMWARE).elf
$(BUILD):
$(MKDIR) -p $@
@ -572,9 +579,6 @@ $(FW_DIR):
FIRMWARE_OBJS: | $(BUILD) $(FW_DIR)
$(MAKE) -C $(CMSIS_DIR) BUILD=$(BUILD)/$(CMSIS_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(HAL_DIR) BUILD=$(BUILD)/$(HAL_DIR) CFLAGS="$(CFLAGS) -MMD"
ifeq ($(MICROPY_PY_ML_TFLM), 1)
$(MAKE) -C $(TENSORFLOW_DIR) BUILD=$(BUILD)/$(TENSORFLOW_DIR) CFLAGS="$(CFLAGS) -MMD" headers
endif
$(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) BUILD=$(BUILD)/$(MICROPY_DIR) $(MPY_MKARGS)
$(MAKE) -C $(GENX320_DIR) BUILD=$(BUILD)/$(GENX320_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(BOSON_DIR) BUILD=$(BUILD)/$(BOSON_DIR) CFLAGS="$(CFLAGS) -MMD"
@ -589,10 +593,16 @@ endif
$(MAKE) -C $(VL53L5CX_DIR) BUILD=$(BUILD)/$(VL53L5CX_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(PIXART_DIR) BUILD=$(BUILD)/$(PIXART_DIR) CFLAGS="$(CFLAGS) -MMD"
ifeq ($(MICROPY_PY_ML_TFLM), 1)
$(MAKE) -C $(TENSORFLOW_DIR) BUILD=$(BUILD)/$(TENSORFLOW_DIR) CFLAGS="$(CFLAGS) -MMD" all
$(MAKE) -C $(TENSORFLOW_DIR) BUILD=$(BUILD)/$(TENSORFLOW_DIR) CFLAGS="$(CFLAGS) -MMD"
endif
$(MAKE) -C $(OMV_DIR) BUILD=$(BUILD)/$(OMV_DIR) CFLAGS="$(CFLAGS) -MMD"
$(ROMFS_IMAGE): $(ROMFS_CONFIG)
$(ECHO) "GEN romfs image"
$(PYTHON) $(TOOLS)/$(MKROMFS) --top-dir $(TOP_DIR) --out-dir $(FW_DIR) \
--build-dir $(BUILD) --config $(ROMFS_CONFIG)
touch $@
# This target generates the main/app firmware image located at 0x08010000
$(FIRMWARE): FIRMWARE_OBJS
$(CPP) -P -E -DLINKER_SCRIPT -I$(OMV_COMMON_DIR) -I$(OMV_BOARD_CONFIG_DIR) \
@ -600,10 +610,6 @@ $(FIRMWARE): FIRMWARE_OBJS
$(CC) $(LDFLAGS) $(FIRM_OBJ) -o $(FW_DIR)/$(FIRMWARE).elf $(LIBS) -lm
$(OBJCOPY) -Obinary -R .big_const* $(FW_DIR)/$(FIRMWARE).elf $(FW_DIR)/$(FIRMWARE).bin
# This target generates the firmware image.
$(OPENMV): $(FIRMWARE)
$(SIZE) $(FW_DIR)/$(FIRMWARE).elf
size:
$(SIZE) --format=SysV $(FW_DIR)/$(FIRMWARE).elf

View File

@ -49,9 +49,10 @@
#include "i2c.h"
#include "uart.h"
#include "dac.h"
#include "can.h"
#include "pyb_can.h"
#include "extint.h"
#include "servo.h"
#include "storage.h"
#include "sdcard.h"
#include "modmachine.h"
#include "extmod/modmachine.h"
@ -157,6 +158,10 @@ int main(void) {
sdram_test(false);
#endif
#if MICROPY_HW_ENABLE_STORAGE
storage_init();
#endif
// Basic sub-system init
led_init();
pendsv_init();
@ -199,7 +204,7 @@ soft_reset:
extint_init0();
timer_init0();
#if MICROPY_HW_ENABLE_CAN
can_init0();
pyb_can_init0();
#endif
i2c_init0();
spi_init0();
@ -355,11 +360,11 @@ soft_reset_exit:
cyw43_deinit(&cyw43_state);
#endif
timer_deinit();
i2c_deinit_all();
pyb_i2c_deinit_all();
spi_deinit_all();
uart_deinit_all();
#if MICROPY_HW_ENABLE_CAN
can_deinit_all();
pyb_can_deinit_all();
#endif
#if MICROPY_PY_THREAD
pyb_thread_deinit();

View File

@ -33,6 +33,9 @@ SIGN_TOOL = $(TOOLS)/st/cubeprog/bin/STM32MP_SigningTool_CLI
PROG_TOOL = $(TOOLS)/st/cubeprog/bin/STM32_Programmer.sh
STLDR_DIR = $(TOOLS)/st/cubeprog/bin/ExternalLoader/
ROMFS_IMAGE := $(FW_DIR)/romfs.stamp
ROMFS_CONFIG := $(OMV_BOARD_CONFIG_DIR)/romfs.json
# Compiler Flags
CFLAGS += -std=gnu99 \
-Wall \
@ -332,6 +335,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/,\
mphalport.o \
sdcard.o \
sdram.o \
vfs_rom_ioctl.o \
fatfs_port.o \
extint.o \
modpyb.o \
@ -436,6 +440,8 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(MICROPY_DIR)/extmod/,\
vfs_fat_diskio.o \
vfs_fat_file.o \
vfs_lfs.o \
vfs_rom.o \
vfs_rom_file.o \
vfs_posix.o \
vfs_posix_file.o \
vfs_reader.o \
@ -674,7 +680,6 @@ ifeq ($(MICROPY_PY_ML_TFLM), 1)
OMV_CFLAGS += -I$(BUILD)/$(TENSORFLOW_DIR)/
FIRM_OBJ += $(addprefix $(BUILD)/$(TENSORFLOW_DIR)/, \
tflm_backend.o \
tflm_builtin_models.o \
)
LIBS += $(TOP_DIR)/$(TENSORFLOW_DIR)/libtflm/lib/libtflm-$(CPU)+fp-release.a
endif
@ -691,9 +696,6 @@ $(FW_DIR):
FIRMWARE_OBJS: | $(BUILD) $(FW_DIR)
$(MAKE) -C $(CMSIS_DIR) BUILD=$(BUILD)/$(CMSIS_DIR) CFLAGS="$(CFLAGS) -fno-strict-aliasing -MMD"
$(MAKE) -C $(HAL_DIR) BUILD=$(BUILD)/$(HAL_DIR) CFLAGS="$(CFLAGS) -MMD"
ifeq ($(MICROPY_PY_ML_TFLM), 1)
$(MAKE) -C $(TENSORFLOW_DIR) BUILD=$(BUILD)/$(TENSORFLOW_DIR) CFLAGS="$(CFLAGS) -MMD" headers
endif
$(MAKE) -C $(MICROPY_DIR)/ports/$(PORT) BUILD=$(BUILD)/$(MICROPY_DIR) $(MPY_MKARGS)
$(MAKE) -C $(GENX320_DIR) BUILD=$(BUILD)/$(GENX320_DIR) CFLAGS="$(CFLAGS) -MMD"
$(MAKE) -C $(BOSON_DIR) BUILD=$(BUILD)/$(BOSON_DIR) CFLAGS="$(CFLAGS) -MMD"
@ -748,6 +750,12 @@ endif
$(PYTHON) $(MKDFU) -D $(DFU_DEVICE) -b $(OMV_BOOT_ADDR):$(FW_DIR)/$(BOOTLOADER).bin $(FW_DIR)/$(BOOTLOADER).dfu
endif
$(ROMFS_IMAGE): $(ROMFS_CONFIG)
$(ECHO) "GEN romfs image"
$(PYTHON) $(TOOLS)/$(MKROMFS) --top-dir $(TOP_DIR) --out-dir $(FW_DIR) \
--build-dir $(BUILD) --config $(ROMFS_CONFIG)
touch $@
# This target builds the main/app firmware image.
$(FIRMWARE): FIRMWARE_OBJS
$(CPP) -P -E -I$(OMV_COMMON_DIR) -I$(OMV_BOARD_CONFIG_DIR) \
@ -757,7 +765,7 @@ $(FIRMWARE): FIRMWARE_OBJS
$(PYTHON) $(MKDFU) -D $(DFU_DEVICE) -b $(OMV_FIRM_ADDR):$(FW_DIR)/$(FIRMWARE).bin $(FW_DIR)/$(FIRMWARE).dfu
# This target builds a contiguous firmware image.
$(OPENMV): $(BOOTLOADER) $(UVC) $(FIRMWARE)
$(OPENMV): $(BOOTLOADER) $(UVC) $(FIRMWARE) .WAIT $(ROMFS_IMAGE)
ifeq ($(OMV_ENABLE_BL), 1)
# Pad the bootloader binary with 0xFF up to the firmware start.
$(OBJCOPY) -I binary -O binary --pad-to $$(($(OMV_FIRM_ADDR) - $(OMV_FIRM_BASE))) \

View File

@ -170,6 +170,10 @@ def cascade_binary(path, n_stages, name):
for s in stages:
fout.write(struct.pack('B', s)) # uint8_t
padding = (4 - ((12 + len(stages)) % 4)) % 4
if padding:
fout.write(b"\x00"*padding)
# write stages thresholds
for t in stage_threshold:
fout.write(struct.pack('h', int(float(t.childNodes[0].nodeValue)*256))) #int16_t
@ -266,6 +270,10 @@ def cascade_binary_old(path, n_stages, name):
for s in stages:
fout.write(struct.pack('B', s)) # uint8_t
padding = (4 - ((12 + len(stages)) % 4)) % 4
if padding:
fout.write(b"\x00"*padding)
# write stages thresholds
for t in stage_threshold:
fout.write(struct.pack('h', int(float(t.childNodes[0].nodeValue)*256))) #int16_t

172
tools/mkromfs.py Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env python3
# This file is part of the OpenMV project.
#
# Copyright (c) 2013-2024 Ibrahim Abdelkader <iabdalkader@openmv.io>
# Copyright (c) 2013-2024 Kwabena W. Agyeman <kwagyeman@openmv.io>
#
# This work is licensed under the MIT license, see the file LICENSE for details.
#
# This script creates a romfs image.
import sys
import os
import json
import argparse
import struct
from tflite2c import vela_compile
from haar2c import cascade_binary_universal
CG = '\033[92m'
CR = '\033[91m'
CB = '\033[94m'
CN = '\033[0m'
ROMFS_HEADER = 0x14a6b1
ROMFS_HEADER_ALIGN = 16
ROMFS_FILEREC_ALIGN = 8
ROMFS_RECORD_KIND_PADDING = 1
ROMFS_RECORD_KIND_DATA = 2
ROMFS_RECORD_KIND_FILE = 5
def encode_vint(value):
encoded = [value & 0x7F]
value >>= 7
while value != 0:
encoded.insert(0, 0x80 | (value & 0x7F))
value >>= 7
return bytes(encoded)
def encode_record(kind, payload, align=0, offset=0, padding=0):
if align:
# Set offset to where the payload starts to align the payload.
offset += len(encode_vint(kind) + encode_vint(len(payload)))
padding = ((offset + (align - 1)) & ~(align - 1)) - offset
kind = encode_vint(kind) if kind else b""
return kind + (b"\x80" * padding) + encode_vint(len(payload)) + payload
def encode_file(name, data, align, offset):
# file record: <FILE_KIND>, record_length, name_length, name, [<DATA_KIND>, data_length, data]
# Note that the file record's length is rounded up to a fixed size, by aligning it
# from offset 0, to ensure that the record length remains unchanged after alignment.
name_rec = encode_record(0, name)
# Data record offset = file offset + 1 (type) + (align - 1) + name record length.
offset = offset + 1 + (ROMFS_FILEREC_ALIGN - 1) + len(name_rec)
# Align the data record's payload.
data_rec = encode_record(ROMFS_RECORD_KIND_DATA, data, align, offset)
# Align the file record's payload.
file_rec = encode_record(ROMFS_RECORD_KIND_FILE, name_rec + data_rec, ROMFS_FILEREC_ALIGN)
return file_rec
def romfs_build(romfs_cfg, p, args):
romfs_cfg = romfs_cfg[p]
# To replace variables in the path
variables = {
"TOP" : args.top_dir,
"BUILD" : args.build_dir
}
# Build/convert files if needed.
index = 0
while index < len(romfs_cfg["entries"]):
entry = romfs_cfg["entries"][index]
if not entry.get("enabled", True):
romfs_cfg["entries"].pop(index)
continue
file_path = entry['path'].format(**variables)
file_name = os.path.basename(os.path.splitext(file_path)[0])
file_size = "%.2f KiB"%(os.path.getsize(file_path) / 1024)
if entry['type'] == 'haar':
# Convert Haar cascade
output_path = os.path.join(args.build_dir, file_name)
cascade_binary_universal(file_path, entry["stages"], output_path)
file_path = os.path.join(args.build_dir, file_name + ".cascade")
elif entry['type'] == 'tflite':
_file_path = file_path # to get labels
if args.vela_args:
# Compile the model using Vela.
vela_args = args.vela_args + " --optimise " + entry["optimize"]
vela_compile(file_path, args.build_dir, vela_args.split())
file_path = os.path.join(args.build_dir, file_name + ".tflite")
# If tflite has a labels file add it as a new entry
labels_path = os.path.splitext(_file_path)[0] + ".txt"
if os.path.exists(labels_path):
romfs_cfg["entries"].insert(index + 1, { "type" : "txt", "path" : labels_path })
index += 1
entry['path'] = file_path
# Build romfs image.
romfs_data = bytearray()
romfs_offset = ROMFS_HEADER_ALIGN
romfs_size = int(romfs_cfg["size"], 16)
for entry in romfs_cfg["entries"]:
file_path = entry['path']
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path)
file_align = entry.get("alignment", 4)
with open(file_path, "rb") as file:
file_data = file.read()
record = encode_file(bytes(file_name, "ascii"), file_data, file_align, romfs_offset)
romfs_offset += len(record)
romfs_data += record
# Write the romfs image.
with open(os.path.join(args.out_dir, f"romfs{p}.img"), "wb") as romfs_file:
# Pad the ROMFS header to ensure a fixed offset from the start of the file.
romfs_data = encode_record(ROMFS_HEADER, romfs_data, ROMFS_HEADER_ALIGN)
if len(romfs_data) > romfs_size:
print(f"{CR}romfs partition overflow "
f"{CR}{len(romfs_data)/1024:.1f}KiB / {CR}{romfs_size/1024:.1f}KiB "
f"({CR}{(len(romfs_data) / romfs_size) * 100:.1f}%){CN}")
print(
f"Partition size: {romfs_size/1024:.1f} KiB"
f"ROMFS Size: {len(romfs_data)/1024:.1f} KiB{CN}")
raise Exception("{CR}romfs partition overflow{CN}")
romfs_file.write(romfs_data)
print(f"{CB}romfs image: {CR}\"romfs{p}.img\" {CB}usage: "
f"{CR}{len(romfs_data)/1024:.1f}KiB / {CR}{romfs_size/1024:.1f}KiB "
f"({CR}{(len(romfs_data) / romfs_size) * 100:.1f}%){CN}")
for entry in romfs_cfg["entries"]:
file_path = entry['path']
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path)
file_align = entry.get("alignment", 4)
print(f" {CB}-size: {CR}{file_size:<8} {CB}alignment: {CR}{file_align:<4} {CB}path: {CG}/rom/{file_name}{CN}");
print("")
def main():
# Set up argument parser
parser = argparse.ArgumentParser(description='Create a romfs image from json file.')
parser.add_argument('--config', action = 'store', help = 'Input romfs json config file.', required=True)
parser.add_argument('--top-dir', action = 'store', help='Top directory', required=True)
parser.add_argument('--out-dir', action = 'store', help='Output directory', required=True)
parser.add_argument('--build-dir', action = 'store', help='Build directory', required=True)
parser.add_argument('--vela-args', action = 'store', help='Vela compiler args', default='')
parser.add_argument('--partition', action = 'store', help = 'romfs partition to build. Default=all.', default=None)
# Parse arguments
args = parser.parse_args()
# Load romfs config from the JSON file
try:
with open(args.config, 'r') as file:
romfs_cfg = json.loads(file.read())
except Exception as e:
print(f"Error: Unable to read the file '{path}'. {str(e)}")
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON format in '{path}'. {str(e)}")
sys.exit(1)
if args.partition is None:
for p in romfs_cfg:
romfs_build(romfs_cfg, p, args)
else:
romfs_build(romfs_cfg, args.partition, args)
if __name__ == '__main__':
main()