rust 实现图像绕中心点旋转任意角度
use env_logger::Env; use image::RgbaImage; use log::{info, LevelFilter}; use nalgebra as na; use std::env; use std::fs::File; use std::path::Path; use std::thread::sleep; use std::time::Duration; fn generate_matrix(theta: f64, pos: (f64, f64)) -> na::Matrix3<f64> { let (x0, y0) = pos; let c = f64::cos(theta.to_radians()); let s = f64::sin(theta.to_radians()); let mut matrix = na::Matrix3::zeros(); matrix[(0, 0)] = c; matrix[(0, 1)] = -s; matrix[(1, 0)] = s; matrix[(1, 1)] = c; matrix[(0, 2)] = -c * x0 + s * y0 + x0; matrix[(1, 2)] = -c * y0 - s * x0 + y0; matrix[(2, 2)] = 1.0; matrix } fn main() { // env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); let target = Box::new(File::create("log.txt").expect("Can't create file")); env_logger::Builder::new() .filter_level(LevelFilter::Info) .write_style(env_logger::fmt::WriteStyle::Always) .target(env_logger::Target::Pipe(target)) .init(); // 获取命令行参数 let args: Vec<String> = env::args().collect(); // 检查参数数量 if args.len() != 4 { info!( "Usage: {} <image_path> <rotation_angle> <output_path>", args[0] ); return; } // 解析参数 let image_path = &args[1]; let output_path = &args[2]; let rotation_angle: f64 = match args[3].parse() { Ok(angle) => angle, Err(_) => { info!("Error: Invalid rotation angle"); return; } }; // 加载图像 let img = match image::open(&Path::new(image_path)) { Ok(img) => img.to_rgba8(), // Ensure the image is in RGBA format Err(err) => { info!("Error: {}", err); return; } }; info!("Image width {}, height{}", img.width(), img.height()); // 获取图像的中心点 let center = na::Point2::new((img.width() / 2) as f32, (img.height() / 2) as f32); info!("Image center {}", center); info!("rotation_angle {}", rotation_angle); let mut x_min = 0; let mut x_max = 0; let mut y_min = 0; let mut y_max = 0; // 计算旋转矩阵 let rotation_matrix = generate_matrix(rotation_angle, (center.x.into(), center.y.into())); // 遍历旋转后的图像像素,找到最小的x和y for y in 0..img.height() { for x in 0..img.width() { info!("-----------"); info!("point to trans x:{:.2}, y:{:.2}", x, y); let point_after_rotate = rotation_matrix.transform_point(&na::Point2::new(x as f64, y as f64)); info!( "point_after_rotate x:{:.2}, y:{:.2}", point_after_rotate.x, point_after_rotate.y ); if point_after_rotate.x < x_min as f64 { x_min = point_after_rotate.x as i32; } if point_after_rotate.y < y_min as f64 { y_min = point_after_rotate.y as i32; } if (point_after_rotate.x as i32) > x_max { x_max = point_after_rotate.x as i32; } if (point_after_rotate.y as i32) > y_max { y_max = point_after_rotate.y as i32; } } } let new_img_width = (x_max - x_min).try_into().unwrap(); let new_img_height = (y_max - y_min).try_into().unwrap(); info!( "new_img_width {}, new_img_height{}", new_img_width, new_img_height ); // 创建一个新的空白图像用于存储旋转后的图像 let mut rotated_img = RgbaImage::new(new_img_width, new_img_height); let rotation_matrix_inv = rotation_matrix.try_inverse().unwrap(); // 计算旋转后的图像像素点在原图像中的位置 for y in y_min..y_max { for x in x_min..x_max { let point_in_origin_img = rotation_matrix_inv.transform_point(&na::Point2::new(x.into(), y.into())); info!( "point_in_origin_img x:{:.2}, y:{:.2}", point_in_origin_img.x, point_in_origin_img.y ); if point_in_origin_img.x >= 0.0 && point_in_origin_img.x < (img.width() as f32).into() && point_in_origin_img.y >= 0.0 && point_in_origin_img.y < (img.height() as f32).into() { rotated_img.put_pixel( (x + x_min.abs()) as u32, // 图像的坐标从0开始,所以要加上x_min的绝对值 (y + y_min.abs()) as u32, *img.get_pixel(point_in_origin_img.x as u32, point_in_origin_img.y as u32), ); } } } // 保存旋转后的图像 if let Err(err) = image::DynamicImage::ImageRgba8(rotated_img).save(&Path::new(output_path)) { info!("Error: {}", err); return; } info!("Image rotated successfully and saved to {}", output_path); }
使用:
.\image_rotate.exe C:\Users\xxx\Desktop\a.png C:\Users\itfanr\xxx\b.png 30
转载请注明原文链接:https://www.cnblogs.com/itfanr/p/17894182.html
公众号:小弧光黑板报
标签:
rust
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战