Repository navigation
v0.37.0
This release breaks the API: the preprocessing types move to edgefirst-tensor, "letterbox" now only means a fit with a pad colour, interpolation becomes a convert option, and several old APIs are removed. Consumers must move as a set; the C ABI versions are bumped.
Added
- Model configuration discovery (
edgefirst-decodermodel_config, EDGEAI-2357).resolve_model_config(path, signals, overrides)returns aResolvedModelConfig: schema, labels, model family, task, semantic decode mode, aPreprocessSpec, and where each value came from (provenance,describe()).- Sources, highest first, each filling only unset fields:
- embedded
edgefirst.json, then its sidecar pluslabels.txt(the legacyvalidation.normalization/validation.preprocessingnow backinput.preprocessing); anedgefirst.jsonwithout outputs leaves the schema to a later source; - embedded, then sidecar, Hugging Face
config.json+preprocessor_config.json; - Ultralytics metadata;
- Hugging Face tensor names (
pixel_values→logits), as guesses; - defaults.
- embedded
- Containers are read without a runtime. ONNX
metadata_props(edgefirst, legacyedgefirst.json,labels,hf_config,hf_preprocessor_config) are read by a protobuf field walk that skips the graph. ZIP trailers (TFLite associated files, HEF, DVM, TensorRT) are read behind the opt-inmodel-filesfeature, which the C library and Python wheel enable; only the file's tail, the central directory and the text entries are read. - A
config.jsonis used only when it is a Hugging Face config.*ForSemanticSegmentationarchitectures map to the semantic decoder; other architectures areUnsupportedArchitecture. ModelOverrides(task,normalize,resize,decode,labels) parse one grammar built on the shared vocabulary names (normalize=unsigned|signed|raw|imagenet|R,G,B/R,G,B,resize=stretch|letterbox|letterbox-center|letterbox-topleft), anddescribe()prints those keys in it. A bareletterboxfollows the model family's convention.- Class names from every source (
edgefirst.json,labels.txt, ONNXlabels, Hugging Faceid2label/label2id, Ultralyticsnames, thelabelsoverride) have leading and trailing whitespace trimmed, so ADE20K's"bed "resolves to"bed". A discovered source whose class names are unusable (a name empty after trimming, a malformedid2label, or a count that disagrees withnum_labelsor with the class count the outputs state or imply) is ignored with a warning and a note naming the source and index (e.g.id2label[7]), and the next source supplies the labels; when none does, the labels are empty with a warning. The count is the one the decoder builder derives, for every model type whose outputs carry one (semantic, Ultralytics and ModelPack detection and segmentation); a ModelPack segmentation output counts its channels less the trailing background channel, and end-to-end detections and class maps carry none. Alabelsoverride whose count disagrees is aModelConfigError::LabelCountMismatch { expected, found }for every such model type, no longer only for semantic models; in Python it is aLabelCountMismatchError(anOverrideErrorwithexpectedandfound), and in Cef_model_config_resolvesetsERANGE. End-to-end detections and class maps state no class count, so there an override of any length is accepted and the caller checks it. Ultralyticsnameswith the wrong count no longer stop resolution: the schema is laid out from thelabelsoverride's count, or from the one output whose class count fits, and the names are ignored with a note; when two outputs could hold the detections, resolution fails with an ambiguous-layout error naming those two remedies. Names repeated ignoring case add a note. ModelSources::new().with_embedded(..).with_sidecar(..).with_signals(..)feedsresolve_sourcesfrom already-read files.- Python:
resolve_model_config,ModelSignals,ModelOverrides,ResolvedModelConfig,PreprocessSpec,ConfigSource,ModelFamily,ModelTask,ConfigField, and theModelConfigError(ValueError) exceptionsOverrideError,UnresolvedConfigErrorandUnsupportedModelError(alsoNotImplementedError). C:ef_model_config_*,ef_model_overrides_*,ef_preprocess_specandef_preprocess_spec_default();ef_model_config_resolvesetsENODATAwhen nothing supplies a required piece.
- Sources, highest first, each filling only unset fields:
- Shared preprocessing values (
edgefirst-tensor).PreprocessSpec,ContentRegion, theContentRegionSourcetrait,letterbox_rect,broadcast_rgb,Normalization::unit_mean_std,PadSpaceandInterpolation::{Bicubic, Area}.ConvertOptions::from_spec/with_specbuild convert options from a spec, interpolation included. Python:ConvertOptions.from_spec,Interpolation,PadSpace. C:ef_convert_options_from_spec,EF_INTERPOLATION_*,EF_PAD_SPACE_*. - Per-convert interpolation.
ConvertOptions::interpolationoverrides the processor's setting for one convert, so models sharing a processor keep their own resampling. Bicubic and area log one warning per mode and run bilinear. Python:ConvertOptions(interpolation=). C:ef_convert_options_set_interpolation. - Content region.
ConvertOptions::content_regionreports where a convert puts the image, computed by the code that paints it, andSemanticOptions::with_converttakes it for semantic decode. Python:ConvertOptions.content_region,ContentRegion. C:ef_convert_options_content_region. - Tiling with preprocessing.
TilingConfig::with_optionsconverts every tile with the given options. Python:TilingConfig(options=). C:plan_tiles,tile_intoandtile_onetake anef_convert_options *.
Changed
- Preprocessing types live in
edgefirst-tensor.Normalization,NormalizationPreset,LetterboxPlacement,Fit,FitModeandInterpolationmoved there;edgefirst-imagere-exports them at the same paths. They are#[non_exhaustive], likeConfigSource,ModelFamily,ModelTask,ConfigFieldandDecodeMode.Normalization::mean_stdreturns the tensor error and requires a positivestd. - Decoder schema.
schema::Normalizationis renamedNormalizationConfig;schema::ResizeModeis replaced by the tensorFitMode;DecodeModegainsas_str/from_str_code. The schema uses the sharedNormalizationPreset,LetterboxPlacement,InterpolationandPadSpace. - "Letterbox" means the fit and its pad; the image rectangle is a content region.
ConvertOptions::letterbox(pad)andef_convert_options_set_letterboxkeep their names and select the fit.- Rust:
SemanticOptions::with_letterbox→with_content_region;MaskOverlay::letterbox,TilePlacement::letterboxand thematerialize_masksargument →content_region. - Python:
decode_semantic, the mask-drawing APIs andTilePlacementtakecontent_region=; the oldletterbox=keyword is not accepted there (convert(letterbox=<pad colour>)is unchanged). - C:
ef_semantic_options_set_content_region,ef_tile_placement.has_content_region/content_region, and the draw APIs'content_regionparameter.
- Rust:
- C ABI versions.
ef_decoder_abi_version4,ef_image_abi_version4.ef_tiling_configis now{tile_w, tile_h, overlap_ratio}; callers movefit,padand placement into anef_convert_optionspassed toplan_tiles,tile_intoandtile_one. - Letterbox placement is spelled
topleft.LetterboxPlacement::TopLeftreads and writes astopleftinedgefirst.json(input.preprocessing.letterbox.placement), theresizeoverride (letterbox-topleft) and Python string arguments.top_leftis no longer accepted, soedgefirst.jsonfiles written by 0.36.0 with a top-left placement must be updated, and files written by this release do not load in 0.36.0. Numeric codes and the CEF_LETTERBOX_PLACEMENT_TOP_LEFTconstant are unchanged. - Python placements. Placement arguments accept
"center"/"topleft"and their codes, andset_interpolationaccepts all four interpolations.
Removed
ConvertOptions::with_preprocessing(featuredecode); useConvertOptions::from_specwith aPreprocessSpec.TilingConfig::fit,padandwith_fit(PythonTilingConfig(fit=, pad=), Cef_tiling_config.fit/pad); usewith_options.- Python
edgefirst.image.Normalization.Tensor.normalize_to_numpytakes aNormalizationPreset, andConvertOptions(normalization=)andconvert(normalization=)take aNormalizationPreset, its name, or(mean, std).
Fixed
- Tiling lost the content region and ignored placement. A letterboxed tile away from the frame origin had no content region recorded, because its crop was checked against the tile size instead of the frame, so its boxes lifted to the wrong place. Tile content regions were also always computed centred.
- V4L2 H.264 encoder ignored the requested profile on the i.MX 8M Plus.
edgefirst-codecnow applies the encoder controls before setting the CAPTURE (coded) format, because thevsi_v4l2driver reset the profile to Constrained Baseline when that format was set. The profile and level are read back after the format is set and applied again where a driver changed them. The encoder also turns on frame- and macroblock-level rate control alongside constant bitrate;vsi_v4l2left both off and encoded every frame at a fixed QP, so the requested bitrate was not held.Bitrate::Auto, the default, now targets 0.16 bits per pixel within 1 to 100 Mbps (about 10 Mbps at 1080p30) with the same rate control, where it used to leave the device's defaults;EncoderConfig::target_bitrate()returns the target either variant resolves to. An unsetprofilenow selects High, and an unsetlevelthe lowest level of ITU-T H.264 Annex A that covers the frame size, each frame dimension, macroblock rate and target bitrate, where the device used its own defaults (Constrained Baseline onvsi_v4l2); both are best effort, so a device without those controls keeps its defaults.EncoderConfig::target_profile(),EncoderConfig::target_level()andH264Level::lowest_for()expose the choice.