pub use chess_corners_core::ResponseMap;
pub use chess_corners_core::chess_response_u8;
pub use crate::radon::radon_heatmap_u8;
#[cfg(feature = "image")]
pub use crate::radon::radon_heatmap_image;
use crate::error::ChessError;
use crate::Detector;
pub struct DetectorDiagnostics<'a> {
detector: &'a Detector,
}
impl<'a> DetectorDiagnostics<'a> {
pub(crate) fn new(detector: &'a Detector) -> Self {
Self { detector }
}
pub fn chess_response_u8(
&self,
img: &[u8],
width: u32,
height: u32,
) -> Result<ResponseMap, ChessError> {
let w = width as usize;
let h = height as usize;
let expected = w * h;
if img.len() != expected {
return Err(ChessError::DimensionMismatch {
expected,
actual: img.len(),
});
}
let params = self.detector.config().chess_params();
Ok(chess_response_u8(img, w, h, ¶ms))
}
pub fn radon_heatmap_u8(
&self,
img: &[u8],
width: u32,
height: u32,
) -> Result<ResponseMap, ChessError> {
crate::radon::radon_heatmap_u8(img, width, height, self.detector.config())
}
#[cfg(feature = "image")]
pub fn radon_heatmap(&self, img: &image::GrayImage) -> Result<ResponseMap, ChessError> {
self.radon_heatmap_u8(img.as_raw(), img.width(), img.height())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Detector, DetectorConfig};
use chess_corners_testutil::aa_chessboard;
fn synthetic_board(size: usize) -> Vec<u8> {
aa_chessboard(size, 12, (0.0, 0.0), 20, 220)
}
#[test]
fn chess_response_map_is_plausibly_shaped_for_chess_strategy() {
let size = 96usize;
let img = synthetic_board(size);
let det = Detector::new(DetectorConfig::chess()).unwrap();
let map = det
.diagnostics()
.chess_response_u8(&img, size as u32, size as u32)
.unwrap();
assert_eq!(map.width(), size);
assert_eq!(map.height(), size);
assert_eq!(map.data().len(), size * size);
let max = map.data().iter().copied().fold(f32::NEG_INFINITY, f32::max);
assert!(
max > 0.0,
"expected a positive ChESS response somewhere on a synthetic board"
);
}
#[test]
fn radon_heatmap_is_plausibly_shaped_for_radon_strategy() {
let size = 96usize;
let img = synthetic_board(size);
let det = Detector::new(DetectorConfig::radon()).unwrap();
let map = det
.diagnostics()
.radon_heatmap_u8(&img, size as u32, size as u32)
.unwrap();
assert!(map.width() > 0 && map.height() > 0);
assert_eq!(map.data().len(), map.width() * map.height());
let max = map.data().iter().copied().fold(f32::NEG_INFINITY, f32::max);
assert!(
max > 0.0,
"expected a positive Radon response somewhere on a synthetic board"
);
}
#[test]
fn chess_response_u8_reports_dimension_mismatch() {
let det = Detector::with_default();
let img = vec![0u8; 10];
let err = det.diagnostics().chess_response_u8(&img, 8, 8).unwrap_err();
match err {
ChessError::DimensionMismatch { expected, actual } => {
assert_eq!(expected, 64);
assert_eq!(actual, 10);
}
other => panic!("expected ChessError::DimensionMismatch, got {other:?}"),
}
}
}