effc88c6d7
新增 core/src/decoder/ 模块(9 文件,~1500 行): - bch.rs: BCH(15,5)+BCH(18,6) 查表解码(32+64 有效码字,t≤3) - format.rs: 从矩阵读取格式信息(EC+掩码)+版本信息(2 副本容错) - extract.rs: 逆向蛇形排列提取数据码字 - deinterleave.rs: 逆向 RS 数据交错 - rs_decode.rs: RS 纠错流水线(伴随式→BM→Chien→Forney) - mode_decode.rs: 逆向 4 种编码模式(数字/字母/字节/汉字 Shift JIS) - detect.rs: 定位图案检测(1:1:3:1:1 比例+交叉验证+聚类) - image.rs: 图像加载+灰度二值化(PNG/JPEG/WebP) - mod.rs: 顶层 API(decode_image + decode_matrix) 修改已有文件: - core: galois.rs 表 pub(crate), 新增 poly_eval(); reed_solomon 公开内部函数 - cli: 新增 --decode <file> 解码模式 - web: 新增 POST /api/decode(multipart file upload) 测试: 72 passed (58 原有 + 14 新增 decoder 测试)
32 lines
1.0 KiB
Rust
32 lines
1.0 KiB
Rust
//! 图像加载与二值化
|
|
//!
|
|
//! 使用 `image` crate 加载 PNG/JPEG/WebP,转为灰度再二值化为布尔矩阵。
|
|
|
|
/// 从图像字节加载并二值化
|
|
///
|
|
/// 步骤:解码 → 灰度 → 按中位数阈值二值化
|
|
pub(crate) fn load_and_binarize(bytes: &[u8]) -> Result<Vec<Vec<bool>>, String> {
|
|
let img = image::load_from_memory(bytes).map_err(|e| format!("图像解码失败: {e}"))?;
|
|
let gray = img.to_luma8();
|
|
|
|
let (w, h) = gray.dimensions();
|
|
let width = w as usize;
|
|
let height = h as usize;
|
|
|
|
// 计算中位数阈值
|
|
let mut all_pixels: Vec<u8> = gray.iter().copied().collect();
|
|
all_pixels.sort_unstable();
|
|
let threshold = all_pixels[all_pixels.len() / 2];
|
|
|
|
// 二值化:像素 < 阈值 → true(暗模块),否则 false(亮模块)
|
|
let matrix: Vec<Vec<bool>> = (0..height)
|
|
.map(|y| {
|
|
(0..width)
|
|
.map(|x| gray.get_pixel(x as u32, y as u32).0[0] < threshold)
|
|
.collect()
|
|
})
|
|
.collect();
|
|
|
|
Ok(matrix)
|
|
}
|