diff --git a/src/pipeline/debug_utils.rs b/src/pipeline/debug_utils.rs index 9cb04c8..348715b 100644 --- a/src/pipeline/debug_utils.rs +++ b/src/pipeline/debug_utils.rs @@ -105,11 +105,116 @@ fn get_char_pattern(ch: char) -> [u8; 7] { '°' => [ 0b00110, 0b01001, 0b01001, 0b00110, 0b00000, 0b00000, 0b00000, ], + 'C' => [ + 0b01110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b01110, + ], + 'D' => [ + 0b11100, 0b10010, 0b10001, 0b10001, 0b10001, 0b10010, 0b11100, + ], + 'F' => [ + 0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000, + ], + 'G' => [ + 0b01110, 0b10001, 0b10000, 0b10111, 0b10001, 0b10001, 0b01110, + ], + 'I' => [ + 0b01110, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110, + ], + 'M' => [ + 0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001, + ], + 'N' => [ + 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001, 0b10001, + ], + 'O' => [ + 0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110, + ], + 'S' => [ + 0b01110, 0b10001, 0b10000, 0b01110, 0b00001, 0b10001, 0b01110, + ], + 'T' => [ + 0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, + ], + 'a' => [ + 0b00000, 0b00000, 0b01110, 0b00001, 0b01111, 0b10001, 0b01111, + ], + 'b' => [ + 0b10000, 0b10000, 0b10110, 0b11001, 0b10001, 0b10001, 0b11110, + ], + 'c' => [ + 0b00000, 0b00000, 0b01110, 0b10000, 0b10000, 0b10001, 0b01110, + ], + 'd' => [ + 0b00001, 0b00001, 0b01101, 0b10011, 0b10001, 0b10001, 0b01111, + ], + 'e' => [ + 0b00000, 0b00000, 0b01110, 0b10001, 0b11111, 0b10000, 0b01110, + ], + 'f' => [ + 0b00110, 0b01001, 0b01000, 0b11100, 0b01000, 0b01000, 0b01000, + ], + 'g' => [ + 0b00000, 0b01111, 0b10001, 0b10001, 0b01111, 0b00001, 0b01110, + ], + 'h' => [ + 0b10000, 0b10000, 0b10110, 0b11001, 0b10001, 0b10001, 0b10001, + ], + 'i' => [ + 0b00100, 0b00000, 0b01100, 0b00100, 0b00100, 0b00100, 0b01110, + ], + 'k' => [ + 0b10000, 0b10000, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, + ], + 'l' => [ + 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110, + ], + 'm' => [ + 0b00000, 0b00000, 0b11010, 0b10101, 0b10101, 0b10001, 0b10001, + ], + 'n' => [ + 0b00000, 0b00000, 0b10110, 0b11001, 0b10001, 0b10001, 0b10001, + ], + 'o' => [ + 0b00000, 0b00000, 0b01110, 0b10001, 0b10001, 0b10001, 0b01110, + ], + 'p' => [ + 0b00000, 0b00000, 0b11110, 0b10001, 0b11110, 0b10000, 0b10000, + ], + 'r' => [ + 0b00000, 0b00000, 0b10110, 0b11001, 0b10000, 0b10000, 0b10000, + ], + 's' => [ + 0b00000, 0b00000, 0b01110, 0b10000, 0b01110, 0b00001, 0b11110, + ], + 't' => [ + 0b01000, 0b01000, 0b11100, 0b01000, 0b01000, 0b01001, 0b00110, + ], + 'u' => [ + 0b00000, 0b00000, 0b10001, 0b10001, 0b10001, 0b10011, 0b01101, + ], + 'v' => [ + 0b00000, 0b00000, 0b10001, 0b10001, 0b10001, 0b01010, 0b00100, + ], + 'w' => [ + 0b00000, 0b00000, 0b10001, 0b10001, 0b10101, 0b10101, 0b01010, + ], + 'x' => [ + 0b00000, 0b00000, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, + ], + 'y' => [ + 0b00000, 0b00000, 0b10001, 0b10001, 0b01111, 0b00001, 0b01110, + ], + 'z' => [ + 0b00000, 0b00000, 0b11111, 0b00010, 0b00100, 0b01000, 0b11111, + ], + '+' => [ + 0b00000, 0b00100, 0b00100, 0b11111, 0b00100, 0b00100, 0b00000, + ], ' ' => [ 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, ], _ => [ - 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, + 0b01010, 0b00000, 0b01010, 0b00000, 0b01010, 0b00000, 0b01010, ], } } diff --git a/src/pipeline/steps/eye_filter.rs b/src/pipeline/steps/eye_filter.rs index 16ee8e7..7d06c45 100644 --- a/src/pipeline/steps/eye_filter.rs +++ b/src/pipeline/steps/eye_filter.rs @@ -81,68 +81,99 @@ impl ProcessingStep for EyeFilterStep { // Get the current image to draw on let image = ctx.image.as_ref()?; let rgb = image.to_rgb8(); - let (width, height) = (rgb.width(), rgb.height()); + let (img_w, img_h) = (rgb.width(), rgb.height()); - // Create a copy for visualization - let mut debug_img = rgb.clone(); - - // Draw eye landmarks (points 36-47) - let points = landmarks.points(); - - // Left eye (points 36-41) - yellow or red depending on EAR - let left_color = if ear.left >= 0.2 { - Rgb([0, 255, 0]) // Green - open - } else { - Rgb([255, 0, 0]) // Red - closed - }; - - for point in points.iter().skip(36).take(6) { - draw_cross(&mut debug_img, point.x as u32, point.y as u32, left_color); - } - - // Right eye (points 42-47) - let right_color = if ear.right >= 0.2 { - Rgb([0, 255, 0]) // Green - open - } else { - Rgb([255, 0, 0]) // Red - closed - }; - - for point in points.iter().skip(42).take(6) { - draw_cross(&mut debug_img, point.x as u32, point.y as u32, right_color); - } - - // Draw eye centers + // Compute eye centers and bounding box for cropping let left_eye = landmarks.left_eye_center(); let right_eye = landmarks.right_eye_center(); - draw_marker( - &mut debug_img, - left_eye.x as u32, - left_eye.y as u32, - Rgb([0, 255, 255]), - ); - draw_marker( - &mut debug_img, - right_eye.x as u32, - right_eye.y as u32, - Rgb([0, 255, 255]), - ); + let eye_dist = + ((right_eye.x - left_eye.x).powi(2) + (right_eye.y - left_eye.y).powi(2)).sqrt(); + let padding = eye_dist * 0.8; + let center_x = (left_eye.x + right_eye.x) / 2.0; + let center_y = (left_eye.y + right_eye.y) / 2.0; + + let crop_x = (center_x - eye_dist / 2.0 - padding).max(0.0) as u32; + let crop_y = (center_y - padding).max(0.0) as u32; + let crop_w = ((eye_dist + padding * 2.0) as u32).min(img_w.saturating_sub(crop_x)); + let crop_h = ((padding * 2.0) as u32).min(img_h.saturating_sub(crop_y)); + + if crop_w == 0 || crop_h == 0 { + return Some(DynamicImage::ImageRgb8(rgb)); + } + + // Crop first, then scale up + let cropped = DynamicImage::ImageRgb8(rgb).crop_imm(crop_x, crop_y, crop_w, crop_h); + + let scale = img_w as f64 / crop_w as f64; + let scaled_w = img_w; + let scaled_h = (crop_h as f64 * scale) as u32; + let mut zoomed = cropped + .resize_exact(scaled_w, scaled_h, image::imageops::FilterType::Lanczos3) + .to_rgb8(); + + // Draw landmarks on the zoomed image (coordinates transformed to zoomed space) + let points = landmarks.points(); + + let left_color = if ear.left >= 0.2 { + Rgb([0, 255, 0]) + } else { + Rgb([255, 0, 0]) + }; + let right_color = if ear.right >= 0.2 { + Rgb([0, 255, 0]) + } else { + Rgb([255, 0, 0]) + }; + + // Left eye landmarks (points 36-41) + for point in points.iter().skip(36).take(6) { + let x = ((point.x as f64 - crop_x as f64) * scale) as u32; + let y = ((point.y as f64 - crop_y as f64) * scale) as u32; + draw_cross(&mut zoomed, x, y, left_color); + } + + // Right eye landmarks (points 42-47) + for point in points.iter().skip(42).take(6) { + let x = ((point.x as f64 - crop_x as f64) * scale) as u32; + let y = ((point.y as f64 - crop_y as f64) * scale) as u32; + draw_cross(&mut zoomed, x, y, right_color); + } + + // Eye centers + let lx = ((left_eye.x as f64 - crop_x as f64) * scale) as u32; + let ly = ((left_eye.y as f64 - crop_y as f64) * scale) as u32; + let rx = ((right_eye.x as f64 - crop_x as f64) * scale) as u32; + let ry = ((right_eye.y as f64 - crop_y as f64) * scale) as u32; + draw_marker(&mut zoomed, lx, ly, Rgb([0, 255, 255])); + draw_marker(&mut zoomed, rx, ry, Rgb([0, 255, 255])); // Draw info bar at bottom let bar_height = 20u32; - let bar_y = height.saturating_sub(bar_height); + let total_h = scaled_h + bar_height; + let mut final_img = RgbImage::new(scaled_w, total_h); - // Draw background - for y in bar_y..height { - for x in 0..width { - debug_img.put_pixel(x, y, Rgb([0, 0, 0])); + // Copy zoomed image + for y in 0..scaled_h { + for x in 0..scaled_w { + final_img.put_pixel(x, y, *zoomed.get_pixel(x, y)); + } + } + + // Draw black bar + for y in scaled_h..total_h { + for x in 0..scaled_w { + final_img.put_pixel(x, y, Rgb([0, 0, 0])); } } // Draw EAR values - let text = format!("L:{:.2} R:{:.2} Avg:{:.2}", ear.left, ear.right, avg_ear); - draw_simple_text(&mut debug_img, 5, bar_y + 6, &text, Rgb([255, 255, 255])); + let text = format!( + "Left:{:.2} Right:{:.2} Average:{:.2}", + ear.left, ear.right, avg_ear + ); + draw_simple_text(&mut final_img, 5, scaled_h + 6, &text, Rgb([255, 255, 255])); - Some(DynamicImage::ImageRgb8(debug_img)) + Some(DynamicImage::ImageRgb8(final_img)) } }