Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/core/src/ar/labeling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ pub enum ImageProcMode {
/// ImageProcMode::FrameImage, &mut label_info, false).unwrap();
/// arlog_i!("{} regions found", label_info.label_num);
/// ```
// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (arLabeling); struct-grouping is a breaking change deferred to a pre-1.0
// API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar_labeling(
image: &[u8],
Expand Down
6 changes: 6 additions & 0 deletions crates/core/src/ar/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,9 @@ pub(crate) fn history_resurrect(ar_handle: &mut crate::types::ARHandle) {
/// - `label_info` — labeling output produced by [`crate::labeling::ar_labeling`].
/// - `marker_info2` — output slice (length ≥ `AR_SQUARE_MAX`) to write candidates into.
/// - `marker2_num` — number of candidates written on return.
// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (arDetectMarker2); struct-grouping is a breaking change deferred to a
// pre-1.0 API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar_detect_marker2(
xsize: i32,
Expand Down Expand Up @@ -1175,6 +1178,9 @@ pub fn ar_get_line(
/// - `patt_handle_opt` — loaded pattern database (required for template modes;
/// pass `None` for pure matrix-code mode).
/// - `matrix_code_type` — dimension/ECC variant used by [`crate::matrix::ar_matrix_code_get_id`].
// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (arGetMarkerInfo); struct-grouping is a breaking change deferred to a
// pre-1.0 API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar_get_marker_info(
image: &[u8],
Expand Down
66 changes: 41 additions & 25 deletions crates/core/src/ar/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,15 @@ pub fn ar_matrix_code_get_id(
let mut bits = vec![0u8; (grid_size * grid_size) as usize];

sample_grid(
image,
xsize,
ysize,
vertex,
grid_size,
pixel_format,
patt_ratio,
&GridSample {
image,
xsize,
ysize,
vertex,
grid_size,
pixel_format,
patt_ratio,
},
&mut bits,
)
.map_err(|_| MatchError::PatternExtraction)?;
Expand Down Expand Up @@ -379,6 +381,19 @@ pub fn ar_get_barcode_marker(
Ok(marker_info)
}

/// Inputs to [`sample_grid`]: the source image plus the geometry of the
/// square to project onto a regular grid. Grouped into a struct to keep the
/// sampler within clippy's argument limit (#83).
struct GridSample<'a> {
image: &'a [u8],
xsize: i32,
ysize: i32,
vertex: &'a [[ARdouble; 2]; 4],
grid_size: i32,
pixel_format: crate::types::ARPixelFormat,
patt_ratio: f64,
}

/// Project image pixels onto a regular grid using a homography.
///
/// Samples `grid_size × grid_size` evenly-spaced points inside the square
Expand All @@ -395,17 +410,16 @@ pub fn ar_get_barcode_marker(
/// equal to `dim + 2` where `dim = code_type & 0xFF`.
/// - `patt_ratio` — fraction of the square covered by data cells (0.5–0.9).
/// - `bits` — output: `grid_size * grid_size` raw intensity values.
#[allow(clippy::too_many_arguments)]
fn sample_grid(
image: &[u8],
xsize: i32,
ysize: i32,
vertex: &[[ARdouble; 2]; 4],
grid_size: i32,
pixel_format: crate::types::ARPixelFormat,
patt_ratio: f64,
bits: &mut [u8],
) -> Result<(), &'static str> {
fn sample_grid(g: &GridSample<'_>, bits: &mut [u8]) -> Result<(), &'static str> {
let GridSample {
image,
xsize,
ysize,
vertex,
grid_size,
pixel_format,
patt_ratio,
} = *g;
let nc = match pixel_format {
crate::types::ARPixelFormat::MONO => 1,
crate::types::ARPixelFormat::RGB | crate::types::ARPixelFormat::BGR => 3,
Expand Down Expand Up @@ -568,13 +582,15 @@ fn ar_matrix_code_get_id_global(
let mut grid = vec![0u8; AR_GLOBAL_ID_OUTER_SIZE * AR_GLOBAL_ID_OUTER_SIZE];
let patt_ratio = AR_GLOBAL_ID_OUTER_SIZE as f64 / (AR_GLOBAL_ID_OUTER_SIZE as f64 + 2.0);
sample_grid(
image,
xsize,
ysize,
vertex,
AR_GLOBAL_ID_OUTER_SIZE as i32,
pixel_format,
patt_ratio,
&GridSample {
image,
xsize,
ysize,
vertex,
grid_size: AR_GLOBAL_ID_OUTER_SIZE as i32,
pixel_format,
patt_ratio,
},
&mut grid,
)
.map_err(|_| {
Expand Down
9 changes: 9 additions & 0 deletions crates/core/src/ar/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ pub fn ar_patt_load(patt_handle: &mut ARPattHandle, filename: &str) -> Result<i3
/// * `patt_ratio` - Ratio of the pattern relative to the marker size.
/// * `patt_size` - Size of the pattern grid.
/// * `filename` - Destination path for the saved pattern file.
// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (arPattSave); struct-grouping is a breaking change deferred to a pre-1.0
// API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments, clippy::needless_range_loop)]
pub fn ar_patt_save(
image: &[u8],
Expand Down Expand Up @@ -567,6 +570,9 @@ pub fn get_cpara(
/// * `vertex` - Array of 4 indices pointing to the corners in the coord arrays.
/// * `patt_ratio` - Ratio of the pattern relative to the marker size.
/// * `ext_patt` - Output buffer where the extracted pattern will be written.
// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (arPattGetImage); struct-grouping is a breaking change deferred to a
// pre-1.0 API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar_patt_get_image(
image_proc_mode: i32,
Expand Down Expand Up @@ -806,6 +812,9 @@ pub fn ar_patt_get_image(
/// * `vertex` - 4 corners of the detected marker.
/// * `patt_ratio` - Ratio of the pattern relative to the marker size.
/// * `ext_patt` - Output buffer where the extracted pattern will be written.
// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (arPattGetImage2); struct-grouping is a breaking change deferred to a
// pre-1.0 API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar_patt_get_image2(
image_proc_mode: i32,
Expand Down
143 changes: 107 additions & 36 deletions crates/core/src/ar2/feature_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,35 @@ fn extraction_params(level: u8) -> ExtractionParams {
// Template helpers (ported from featureMap.c static functions)
// ---------------------------------------------------------------------------

/// Create a zero-mean template patch centred at `(cx, cy)`.
///
/// Returns `Some(vlen)` on success, `None` if the patch is out of bounds or
/// has insufficient variance.
#[allow(clippy::too_many_arguments)]
fn make_template(
image: &[u8],
/// The source image plus the centre and radii describing a template patch.
/// Grouped into a struct to keep [`make_template`] within clippy's argument
/// limit (#83).
struct TemplatePatch<'a> {
image: &'a [u8],
xsize: i32,
ysize: i32,
cx: i32,
cy: i32,
ts1: i32,
ts2: i32,
sd_thresh: f32,
template: &mut [f32],
) -> Option<f32> {
}

/// Create a zero-mean template patch centred at `(cx, cy)`.
///
/// Returns `Some(vlen)` on success, `None` if the patch is out of bounds or
/// has insufficient variance.
fn make_template(p: &TemplatePatch<'_>, template: &mut [f32]) -> Option<f32> {
let TemplatePatch {
image,
xsize,
ysize,
cx,
cy,
ts1,
ts2,
sd_thresh,
} = *p;
if cy - ts1 < 0 || cy + ts2 >= ysize || cx - ts1 < 0 || cx + ts2 >= xsize {
return None;
}
Expand Down Expand Up @@ -175,6 +188,9 @@ fn make_template(
/// `sx` (sum of u8 values) and `sxx` (sum of squared u8 values) are
/// accumulated as `u64` integers in all paths — no FP drift on those.
#[inline]
// rationale: runtime dispatcher whose signature is locked to match
// get_similarity_scalar and the SIMD variants (get_similarity_sse41/avx2)
// for is_x86_feature_detected! dispatch (#83).
#[allow(clippy::too_many_arguments)]
fn get_similarity(
image: &[u8],
Expand Down Expand Up @@ -211,6 +227,8 @@ fn get_similarity(
/// `sx`/`sxx` use `u64` integer accumulation to avoid f32 rounding past
/// 2^24. `sxy` is accumulated left-to-right in row-major order.
#[inline]
// rationale: scalar fallback whose signature is locked to match the SIMD
// variants (get_similarity_sse41/avx2) for runtime dispatch (#83).
#[allow(clippy::too_many_arguments)]
fn get_similarity_scalar(
image: &[u8],
Expand Down Expand Up @@ -615,11 +633,22 @@ fn gen_feature_map_for_level(
let ci = i as i32;
let cj = j as i32;

let vlen =
match make_template(image, xsize, ysize, ci, cj, ts1, ts2, sd_thresh, &mut tmpl) {
Some(v) => v,
None => continue,
};
let vlen = match make_template(
&TemplatePatch {
image,
xsize,
ysize,
cx: ci,
cy: cj,
ts1,
ts2,
sd_thresh,
},
&mut tmpl,
) {
Some(v) => v,
None => continue,
};

let mut max = -1.0f32;
let mut early_exit = false;
Expand Down Expand Up @@ -655,22 +684,39 @@ fn gen_feature_map_for_level(
// Feature selection
// ---------------------------------------------------------------------------

/// Greedily select features from a feature map.
///
/// Ported from `ar2SelectFeature` in the C source.
#[allow(clippy::too_many_arguments, clippy::needless_range_loop)]
fn select_features(
image: &[u8],
/// Inputs to [`select_features`]: the source image, its feature map, and the
/// selection thresholds. Grouped into a struct to keep the selector within
/// clippy's argument limit (#83).
struct FeatureSelection<'a> {
image: &'a [u8],
xsize: i32,
ysize: i32,
dpi: f32,
fmap: &[f32],
fmap: &'a [f32],
max_feature_num: i32,
max_sim_thresh: f32,
min_sim_thresh: f32,
sd_thresh: f32,
occ_size: i32,
) -> Vec<AR2FeatureCoordT> {
}

/// Greedily select features from a feature map.
///
/// Ported from `ar2SelectFeature` in the C source.
#[allow(clippy::needless_range_loop)]
fn select_features(s: &FeatureSelection<'_>) -> Vec<AR2FeatureCoordT> {
let FeatureSelection {
image,
xsize,
ysize,
dpi,
fmap,
max_feature_num,
max_sim_thresh,
min_sim_thresh,
sd_thresh,
occ_size,
} = *s;
let w = xsize as usize;
let h = ysize as usize;
let ts1 = AR2_DEFAULT_TS1;
Expand Down Expand Up @@ -704,7 +750,19 @@ fn select_features(
}

// Validate: re-create template and check variance
let vlen = match make_template(image, xsize, ysize, cx, cy, ts1, ts2, 0.0, &mut tmpl) {
let vlen = match make_template(
&TemplatePatch {
image,
xsize,
ysize,
cx,
cy,
ts1,
ts2,
sd_thresh: 0.0,
},
&mut tmpl,
) {
Some(v) => v,
None => {
work[(cy as usize) * w + (cx as usize)] = 1.0;
Expand Down Expand Up @@ -838,18 +896,18 @@ pub fn ar2_gen_feature_map(
);

// Greedily select features using level-dependent thresholds.
let coords = select_features(
&img.img_bw,
img.xsize,
img.ysize,
img.dpi,
&fmap,
search_feature_num,
params.max_sim_thresh,
params.min_sim_thresh,
params.sd_thresh,
params.occ_size,
);
let coords = select_features(&FeatureSelection {
image: &img.img_bw,
xsize: img.xsize,
ysize: img.ysize,
dpi: img.dpi,
fmap: &fmap,
max_feature_num: search_feature_num,
max_sim_thresh: params.max_sim_thresh,
min_sim_thresh: params.min_sim_thresh,
sd_thresh: params.sd_thresh,
occ_size: params.occ_size,
});

// Compute mindpi: next lower DPI in the set, or current × 0.5.
// Ports the scale1 loop in markerCreator.cpp.
Expand Down Expand Up @@ -995,7 +1053,20 @@ mod tests {
let data = vec![100u8; 10 * 10];
let mut tmpl = vec![0.0f32; 529]; // (11+11+1)^2 = 529
// Centre at (0,0) with ts1=11 → out of bounds
assert!(make_template(&data, 10, 10, 0, 0, 11, 11, 0.0, &mut tmpl).is_none());
assert!(make_template(
&TemplatePatch {
image: &data,
xsize: 10,
ysize: 10,
cx: 0,
cy: 0,
ts1: 11,
ts2: 11,
sd_thresh: 0.0,
},
&mut tmpl
)
.is_none());
}

/// Helper: build a deterministic 64×64 pseudo-random image and template
Expand Down
9 changes: 9 additions & 0 deletions crates/core/src/ar2/tracking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,9 @@ pub struct AR2Tracking2DResult {
pub pos3d: [f32; 3],
}

// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (ar2Tracking internals); struct-grouping is a breaking change deferred to
// a pre-1.0 API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar2_tracking_2d_sub(
cparam_lt: Option<&ARParamLT>,
Expand Down Expand Up @@ -1426,6 +1429,9 @@ pub fn ar2_get_trans_mat(
pub const KEEP_NUM: usize = 3;
pub const SKIP_INTERVAL: i32 = 3;

// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (ar2GetBestMatching); struct-grouping is a breaking change deferred to a
// pre-1.0 API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar2_get_best_matching(
img: &[u8],
Expand Down Expand Up @@ -1554,6 +1560,9 @@ pub fn ar2_get_best_matching(
final_ret
}

// rationale: public C-faithful API — mirrors the flat ARToolKit signature
// (ar2GetBestMatchingSubFine); struct-grouping is a breaking change deferred
// to a pre-1.0 API pass (#83, docs/design/issue-83-too-many-args-audit.md).
#[allow(clippy::too_many_arguments)]
pub fn ar2_get_best_matching_sub_fine(
img: &[u8],
Expand Down
Loading
Loading