用Rust和OpenCV打造ASCII圖片
使用Rust和OpenCV的動(dòng)態(tài)組合,將任何舊圖片變成一個(gè)炙手可熱的ASCII藝術(shù)圖片。想象文字像像素一樣跳舞,在純文本的基礎(chǔ)上捕捉圖像的本質(zhì)。
圖片
OpenCV下載地址:https://opencv.org/releases/.
創(chuàng)建一個(gè)Rust項(xiàng)目:
cargo new img-to-ascii
在Cargo.toml文件中,加入以下依賴項(xiàng):
[dependencies]
opencv = "0.88.5"
將下面的圖片存儲(chǔ)在項(xiàng)目的根目錄下:
圖片
第一步,讀取圖片,然后灰度化
use opencv::core;
use opencv::imgcodecs;
use opencv::imgproc;
use opencv::prelude::*;
use std::env;
use std::fs::File;
use std::io::Write;
fn main() {
// 解析命令行參數(shù)
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Usage: {} <image>", args[0]);
return;
}
// 讀取圖像文件
let image = imgcodecs::imread(args[1].as_str(), imgcodecs::IMREAD_COLOR).unwrap();
// 轉(zhuǎn)換為灰度
let mut gray_image = Mat::default();
imgproc::cvt_color(&image, &mut gray_image, imgproc::COLOR_BGR2GRAY, 0).unwrap();
}
這段代碼使用OpenCV讀取圖像并將其轉(zhuǎn)換為灰度,為我們的ASCII藝術(shù)創(chuàng)作奠定了基礎(chǔ)。
第二步,縮放和調(diào)整大小。
use opencv::core;
use opencv::imgcodecs;
use opencv::imgproc;
use opencv::prelude::*;
use std::env;
use std::fs::File;
use std::io::Write;
fn main() {
......
// 設(shè)置所需寬度或高度
let desired_width = 150;
let desired_height = 150;
// 在保持長(zhǎng)寬比的同時(shí)計(jì)算比例因子
let scale_w = desired_width as f64 / image.cols() as f64;
let scale_h = desired_height as f64 / image.rows() as f64;
let scale = scale_w.min(scale_h);
let new_width = (image.cols() as f64 * scale) as i32;
let new_height = (image.rows() as f64 * scale) as i32;
// 調(diào)整圖像大小
let mut resized = Mat::default();
imgproc::resize(
&gray_image,
&mut resized,
core::Size::new(new_width, new_height),
0.0,
0.0,
imgproc::INTER_LINEAR,
)
.unwrap();
}
在這里,我們要確保我們的ASCII圖片不會(huì)太壓扁或拉伸,通過(guò)代碼計(jì)算最佳比例因子并相應(yīng)地調(diào)整圖像的大小。
第三步,ASCII轉(zhuǎn)換。
use opencv::core;
use opencv::imgcodecs;
use opencv::imgproc;
use opencv::prelude::*;
use std::env;
use std::fs::File;
use std::io::Write;
fn main() {
......
// ASCII轉(zhuǎn)換
// 更多的字符表示更精細(xì)的細(xì)節(jié)
// <$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. >
let ascii_chars = " .,:;i1tfLCG08@";
let mut ascii_art = String::new();
for i in 0..resized.rows() {
for j in 0..resized.cols() {
let pixel = resized.at_2d::<u8>(i, j).unwrap();
let ascii_index = *pixel as usize * ascii_chars.len() / 256;
ascii_art.push(ascii_chars.chars().nth(ascii_index).unwrap_or(' '));
}
ascii_art.push('\n');
}
}
我們定義了一個(gè)ASCII字符的調(diào)色板,并將每個(gè)像素的強(qiáng)度映射到一個(gè)字符,從而創(chuàng)建了基于文本的圖像。
第四步,生成ASCII圖片。
use opencv::core;
use opencv::imgcodecs;
use opencv::imgproc;
use opencv::prelude::*;
use std::env;
use std::fs::File;
use std::io::Write;
fn main() {
......
// 保存ASCII圖像文件
let mut file = File::create(format!(
"{}.txt",
args[1].split('.').collect::<Vec<&str>>()[0]
))
.unwrap();
file.write_all(ascii_art.as_bytes()).unwrap();
// 打印ASCII圖像到控制臺(tái)
println!("{}", ascii_art);
println!("Done!");
}
執(zhí)行以下命令運(yùn)行程序:
cargo run R.png
最后,呈現(xiàn)了我們的ASCII美術(shù)作品,既將其保存為文本文件以供分享,也將其直接打印到控制臺(tái)以獲得即時(shí)滿足感。