# rust_photo_checker **Repository Path**: dcren/rust_photo_checker ## Basic Information - **Project Name**: rust_photo_checker - **Description**: 使用rust写的证件照检查 - **Primary Language**: Rust - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-09-03 - **Last Updated**: 2026-07-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 证件照检测工具实现方案 ## 技术栈选型 ### 核心依赖 - **图像处理**:`image` (0.24) - 轻量级图像加载与像素操作 - **人脸检测**:`rustface` (0.1.3) - SeetaFace移植版,无外部依赖 - **清晰度评估**:`imageproc` (0.24) - 提供Sobel算子等计算机视觉算法 - **命令行解析**:`clap` (4.4) - 处理输入参数 ### 依赖体积分析 | 依赖 | 体积 | 功能 | |------|------|------| | image | ~2MB | 图像IO与像素操作 | | rustface | ~1.5MB | 人脸检测 | | imageproc | ~3MB | 边缘检测与清晰度评估 | | 总计 | ~6.5MB | 核心功能模块 | ## 功能实现方案 ### 1. 图像加载与预处理 ```rust use image::{DynamicImage, ImageBuffer, RgbImage}; /// 加载图像并转换为RGB格式 fn load_image(path: &str) -> Result { let img = image::open(path)?; Ok(img.to_rgb8()) } ``` ### 2. 背景颜色检测 #### HSV颜色空间转换 ```rust /// RGB转HSV颜色空间 fn rgb_to_hsv(r: u8, g: u8, b: u8) -> (f32, f32, f32) { let r = r as f32 / 255.0; let g = g as f32 / 255.0; let b = b as f32 / 255.0; let max = r.max(g).max(b); let min = r.min(g).min(b); let delta = max - min; let h = match max { _ if delta == 0.0 => 0.0, _ if max == r => 60.0 * ((g - b) / delta % 6.0), _ if max == g => 60.0 * ((b - r) / delta + 2.0), _ => 60.0 * ((r - g) / delta + 4.0), }; let s = if max == 0.0 { 0.0 } else { delta / max }; let v = max; (h, s * 100.0, v * 100.0) } ``` #### 背景颜色判断 ```rust /// 判断背景是否为白色或蓝色 fn check_background(img: &RgbImage) -> Result { // 采样边缘像素(排除中心区域避免衣物干扰) let (width, height) = (img.width(), img.height()); let mut samples = Vec::new(); // 采集边缘10%区域像素 for y in 0..height { for x in 0..width { if x < width / 10 || x > width * 9 / 10 || y < height / 10 || y > height * 9 / 10 { let pixel = img.get_pixel(x, y); samples.push(rgb_to_hsv(pixel.0[0], pixel.0[1], pixel.0[2])); } } } // 判断蓝色背景 (H:100-130, S:43-255, V:46-255) let blue_count = samples.iter() .filter(|&&(h, s, v)| h >= 100.0 && h <= 130.0 && s >= 43.0 && v >= 46.0) .count(); // 判断白色背景 (H:0-180, S:0-30, V:221-255) let white_count = samples.iter() .filter(|&&(h, s, v)| s <= 30.0 && v >= 85.0) .count(); match (blue_count > samples.len() * 3 / 4, white_count > samples.len() * 3 / 4) { (true, _) => Ok("蓝色背景".to_string()), (_, true) => Ok("白色背景".to_string()), _ => Err("背景颜色不符合要求".to_string()), } } ``` ### 3. 人脸检测与比例验证 ```rust use rustface::{Detector, ImageData}; /// 检测人脸并验证比例 fn check_face(img: &RgbImage) -> Result<(), String> { let detector = Detector::new()?; let (width, height) = (img.width() as i32, img.height() as i32); // 转换为灰度图像 let gray_img = image::DynamicImage::ImageRgb8(img.clone()).to_luma8(); let image_data = ImageData::new(gray_img.as_raw(), width, height); // 检测人脸 let faces = detector.detect(&image_data); if faces.is_empty() { return Err("未检测到人脸".to_string()); } // 验证人脸比例(宽度占照片宽度的1/2至2/3) let face = &faces[0]; let face_width = face.width() as f32; let photo_width = width as f32; let ratio = face_width / photo_width; if ratio < 0.4 || ratio > 0.7 { return Err(format!("人脸比例不符合要求(当前: {:.2},建议: 0.4-0.7)", ratio)); } Ok(()) } ``` ### 4. 清晰度评估 ```rust use imageproc::edges::sobel_edges; use imageproc::gradients::gradient_magnitude; /// 使用Tenengrad算法评估清晰度 fn check_clarity(img: &image::DynamicImage) -> Result { let gray_img = img.to_luma8(); let (grad_x, grad_y) = sobel_edges(&gray_img); let magnitude = gradient_magnitude(&grad_x, &grad_y); let mean_magnitude = magnitude.iter().sum::() / (magnitude.len() as f32); // 阈值设为500(需根据样本调整) if mean_magnitude < 500.0 { Err(format!("照片清晰度不足(当前: {:.2},阈值: 500.0)", mean_magnitude)) } else { Ok(mean_magnitude) } } ``` ## 测试与优化 1. **测试用例**: - 正常证件照(白色背景、正面人脸、300DPI) - 异常Case:侧脸、模糊图像、非纯色背景 2. **优化方向**: - 添加人像姿态检测(如是否正面) - 优化背景检测算法,处理光照不均情况 - 增加眼睛间距、头顶留白等细节检测 ## 最终程序结构 ``` src/ ├── main.rs # 命令行入口 ├── background.rs # 背景颜色检测 ├── face.rs # 人脸检测与比例验证 ├── clarity.rs # 清晰度评估 └── utils.rs # 图像处理工具函数 ```