Move the panorama keypoint detector onto the engine, and probe with a detector
XFeat's two exports are a Keypoints role now; the crate no longer names tract, and the app compiles TensorRT engines for both ahead of the first merge. The probe picks the smallest *detector* rather than the smallest file: the tablet's first run chose the 112 KB eye classifier, which has no int8 form, and reported the Hexagon as failed for want of one.
This commit is contained in:
@@ -63,3 +63,13 @@ pub enum PanoError {
|
||||
#[error("inference: {0}")]
|
||||
Inference(#[source] ort::Error),
|
||||
}
|
||||
|
||||
#[cfg(feature = "xfeat")]
|
||||
impl From<dr_inference_engine::Error> for PanoError {
|
||||
fn from(e: dr_inference_engine::Error) -> Self {
|
||||
match e {
|
||||
dr_inference_engine::Error::Inference(e) => PanoError::Inference(e),
|
||||
dr_inference_engine::Error::Io(e) => PanoError::ModelRead(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-28
@@ -2,10 +2,11 @@
|
||||
//! The XFeat detector — the network under tract, and the decoder after it.
|
||||
//!
|
||||
//! Apache-2.0 weights (`models/LICENCE.md`), exported at a fixed shape by
|
||||
//! `tools/export-xfeat.sh` and loaded through the same `ort`-over-tract
|
||||
//! backend `dr-segment` and `dr-face` use, so this adds no runtime and no C
|
||||
//! to the tree. ~300 ms per frame on the reference desktop, ~400 ms on the
|
||||
//! tablet (S15.2, S15.4).
|
||||
//! `tools/export-xfeat.sh` and loaded through the same `dr-inference-engine`
|
||||
//! `dr-segment` and `dr-face` use, so this adds no runtime and no C to the
|
||||
//! tree; what runs it is the device's business (docs/inference.md). ~300 ms
|
||||
//! per frame on tract on the reference desktop, ~400 ms on the tablet
|
||||
//! (S15.2, S15.4).
|
||||
|
||||
use crate::features::{decode_xfeat, DecodeOptions, Features, XFeatMaps, DESCRIPTOR_LEN};
|
||||
use crate::image::Gray;
|
||||
@@ -30,11 +31,18 @@ const EMBEDDED_PORTRAIT: &[u8] = include_bytes!("../../../models/keypoints/xfeat
|
||||
|
||||
/// A loaded detector: the network at both shapes.
|
||||
pub struct XFeat {
|
||||
landscape: ort::session::Session,
|
||||
portrait: ort::session::Session,
|
||||
landscape: dr_inference_engine::Model,
|
||||
portrait: dr_inference_engine::Model,
|
||||
pub options: DecodeOptions,
|
||||
}
|
||||
|
||||
/// The bytes of both exports compiled into the binary, for whoever compiles
|
||||
/// engines ahead of the first request (docs/inference.md §6).
|
||||
#[cfg(feature = "embedded-model")]
|
||||
pub fn embedded_model_bytes() -> [&'static [u8]; 2] {
|
||||
[EMBEDDED_LANDSCAPE, EMBEDDED_PORTRAIT]
|
||||
}
|
||||
|
||||
impl XFeat {
|
||||
/// The weights compiled into the binary.
|
||||
#[cfg(feature = "embedded-model")]
|
||||
@@ -53,16 +61,10 @@ impl XFeat {
|
||||
}
|
||||
|
||||
pub fn from_bytes(landscape: &[u8], portrait: &[u8]) -> Result<Self, PanoError> {
|
||||
install_backend();
|
||||
let session = |bytes: &[u8]| {
|
||||
ort::session::Session::builder()
|
||||
.map_err(PanoError::Inference)?
|
||||
.commit_from_memory(bytes)
|
||||
.map_err(PanoError::Inference)
|
||||
};
|
||||
use dr_inference_engine::{Form, Role};
|
||||
Ok(XFeat {
|
||||
landscape: session(landscape)?,
|
||||
portrait: session(portrait)?,
|
||||
landscape: dr_inference_engine::open(Role::Keypoints, Form::F32, landscape)?,
|
||||
portrait: dr_inference_engine::open(Role::Keypoints, Form::F32, portrait)?,
|
||||
options: DecodeOptions::default(),
|
||||
})
|
||||
}
|
||||
@@ -75,11 +77,13 @@ impl XFeat {
|
||||
/// so a caller that already scaled a frame to a proxy maps them on with
|
||||
/// the scale it used and nothing else.
|
||||
pub fn detect(&mut self, image: &Gray) -> Result<Features, PanoError> {
|
||||
let ((in_w, in_h), session) = if image.height > image.width {
|
||||
(INPUT_PORTRAIT, &mut self.portrait)
|
||||
let ((in_w, in_h), model) = if image.height > image.width {
|
||||
(INPUT_PORTRAIT, &self.portrait)
|
||||
} else {
|
||||
(INPUT_LANDSCAPE, &mut self.landscape)
|
||||
(INPUT_LANDSCAPE, &self.landscape)
|
||||
};
|
||||
let acquired = model.acquire()?;
|
||||
let mut session = acquired.lock();
|
||||
let (fitted, scale) = image.fitted(in_w, in_h);
|
||||
let padded = fitted.padded(in_w, in_h);
|
||||
|
||||
@@ -145,13 +149,3 @@ impl XFeat {
|
||||
Ok(features)
|
||||
}
|
||||
}
|
||||
|
||||
fn install_backend() {
|
||||
use std::sync::Once;
|
||||
static ONCE: Once = Once::new();
|
||||
ONCE.call_once(|| {
|
||||
// False if another crate installed it first, which is fine: there is
|
||||
// one backend compiled in for it to have chosen.
|
||||
let _ = ort::set_api(ort_tract::api());
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user