pub struct AnchorGrid {
pub cx: Vec<f32>,
pub cy: Vec<f32>,
pub strides: Vec<f32>,
pub n_anchors: usize,
}
impl AnchorGrid {
pub fn yolo26(img_h: usize, img_w: usize) -> Self {
Self::new(img_h, img_w, &[8, 16, 32])
}
pub fn new(img_h: usize, img_w: usize, strides: &[usize]) -> Self {
let total: usize = strides.iter().map(|&s| (img_h / s) * (img_w / s)).sum();
let mut cx = Vec::with_capacity(total);
let mut cy = Vec::with_capacity(total);
let mut stride_v = Vec::with_capacity(total);
for &s in strides {
let fh = img_h / s;
let fw = img_w / s;
for gy in 0..fh {
for gx in 0..fw {
cx.push((gx as f32 + 0.5) * s as f32);
cy.push((gy as f32 + 0.5) * s as f32);
stride_v.push(s as f32);
}
}
}
AnchorGrid { n_anchors: total, cx, cy, strides: stride_v }
}
pub fn decode_ltrb_to_xywh(&self, ltrb: &[f32]) -> Vec<f32> {
let a = self.n_anchors;
assert_eq!(ltrb.len(), 4 * a);
let mut out = vec![0.0f32; 4 * a];
for i in 0..a {
let l = ltrb[i];
let t = ltrb[a + i];
let r = ltrb[2 * a + i];
let b = ltrb[3 * a + i];
let s = self.strides[i];
out[i] = self.cx[i] + s * (r - l) * 0.5; out[a + i] = self.cy[i] + s * (b - t) * 0.5; out[2 * a + i] = s * (l + r); out[3 * a + i] = s * (t + b); }
out
}
pub fn decode_backward(&self, d_xywh: &[f32]) -> Vec<f32> {
let a = self.n_anchors;
assert_eq!(d_xywh.len(), 4 * a);
let mut d_ltrb = vec![0.0f32; 4 * a];
for i in 0..a {
let d_cx = d_xywh[i];
let d_cy = d_xywh[a + i];
let d_w = d_xywh[2 * a + i];
let d_h = d_xywh[3 * a + i];
let s = self.strides[i];
d_ltrb[i] = d_cx * (-s * 0.5) + d_w * s; d_ltrb[a + i] = d_cy * (-s * 0.5) + d_h * s; d_ltrb[2 * a + i] = d_cx * ( s * 0.5) + d_w * s; d_ltrb[3 * a + i] = d_cy * ( s * 0.5) + d_h * s; }
d_ltrb
}
}