rust 实现图像绕中心点旋转任意角度

发布时间 2023-12-11 13:30:10作者: 小弧光

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