Let's write β

プログラミング中にできたことか、思ったこととか

Rustで画像回転

Rust言語で画像の回転をしてみようと思いまして,
ライブラリを探したところ,

https://crates.io/crates/image

というライブラリがあったのですが,画像を中心を軸に自由回転させるものがなかったので自作してみました.

アルゴリズム

C言語による画像回転処理について

様を参考にさせていただきました.

まだ線形補間などは実装していないので回転画像は荒いので線形補間などを実装していきたいと思っています.

extern crate image;

use image::{
    GenericImage,
    ImageBuffer,
    Pixel,
    DynamicImage,
};

use std::fs::File;
use std::path::Path;

fn rotate<I: GenericImage + 'static>(image:  &I, deg: f32) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>> where I::Pixel: 'static, <I::Pixel as Pixel>::Subpixel: 'static {
    let (width, height) = image.dimensions();

    let rad = deg * std::f32::consts::PI / 180.0;
    let val_sin = rad.sin();
    let val_cos = rad.cos();

    let dst_width: i32 = (((width as f32) * val_cos).abs() + ((height as f32) * val_sin).abs() + 0.5) as i32;
    let dst_height: i32 = (((width as f32) * val_sin).abs() + ((height as f32) * val_cos).abs() + 0.5) as i32;

    let src_cx: i32 = (width / 2) as i32;
    let src_cy: i32 = (height / 2) as i32;
    let dst_cx: i32 = dst_width / 2;
    let dst_cy: i32 = dst_height / 2;

    let mut out = ImageBuffer::new(dst_width as u32, dst_height as u32);

    let int_sin: i32 = (val_sin * 1024.0) as i32;
    let int_cos: i32 = (val_cos * 1024.0) as i32;
    println!("int_sin: {}, int_cos: {}", int_sin, int_cos);

    for y2 in (0..dst_height) {
        for x2 in (0..dst_width) {
            let hoge = (((x2 - dst_cx) * int_cos - (y2 - dst_cy) * int_sin) >> 10) + src_cx;
            let x1: i32 = (((x2 - dst_cx) * int_cos - (y2 - dst_cy) * int_sin) >> 10) + src_cx;
            let y1: i32 = (((x2 - dst_cx) * int_sin + (y2 - dst_cy) * int_cos) >> 10) + src_cy;
            if x1 >= 0 && x1 < width as i32 && y1 >= 0 && y1 < height as i32 {
                let p = image.get_pixel(x1 as u32, y1 as u32);
                out.put_pixel(x2 as u32, y2 as u32, p);
            }
        }
    }

    out
}

fn main() {
    let img = image::open(&Path::new("test.png")).unwrap();
    let rotated_image = match img {
        DynamicImage::ImageLuma8(ref image) => DynamicImage::ImageLuma8(rotate(image, 45.0)),
        DynamicImage::ImageLumaA8(ref image) => DynamicImage::ImageLumaA8(rotate(image, 45.0)),
        DynamicImage::ImageRgb8(ref image) => DynamicImage::ImageRgb8(rotate(image, 45.0)),
        DynamicImage::ImageRgba8(ref image) => DynamicImage::ImageRgba8(rotate(image, 45.0)),
    };
    let ref mut fout = File::create(&Path::new("rotated-test.png")).unwrap();
    let _ = rotated_image.save(fout, image::PNG).unwrap();
}