Skip to content

Commit

Permalink
🔄 refactor: Replace image with resize and zune-jpeg to reduce p…
Browse files Browse the repository at this point in the history
…ackage size

🔧 chore: Update version in Cargo.toml to 0.4.1

🔧 chore: Update CHANGELOG.md with new version details

🔧 chore: Replace `jpeg-decoder` and `image` dependencies with `rgb`, `zune-jpeg`, and `resize`

🔧 chore: Update `classifier.rs` to use `zune-jpeg` and `resize` for image processing

🔧 chore: Update `lib.rs` and `main.rs` to use new `ModelChannels` and `ResizeParam` types

The changes were made to reduce the package size by replacing the `image` library with `resize` and `zune-jpeg`. This also involved updating the code to use these new libraries for image processing. The version was updated in `Cargo.toml` and `CHANGELOG.md` to reflect these changes.
  • Loading branch information
wenxuanjun committed May 11, 2024
1 parent 3763b5b commit cc37367
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 113 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [0.4.1] - 2024-05-12

-`image` 替换成 `resize``zune-jpeg` 以减小包体积

## [0.4.0] - 2024-05-11

- 新增支持多个架构(`x86_64``aarch64`)(`Windows``Linux``macOS`
Expand All @@ -22,6 +26,7 @@
- Initial release
- 在 Windows 和 Linux 上通过测试

[0.4.1]: https://github.com/ShanghaitechGeekPie/net-loginer/releases/tag/v0.4.1
[0.4.0]: https://github.com/ShanghaitechGeekPie/net-loginer/releases/tag/v0.4.0
[0.3.1]: https://github.com/ShanghaitechGeekPie/net-loginer/releases/tag/v0.3.1
[0.3.0]: https://github.com/ShanghaitechGeekPie/net-loginer/releases/tag/v0.3.0
Expand Down
80 changes: 16 additions & 64 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 16 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "net-loginer"
version = "0.1.0"
version = "0.4.1"
edition = "2021"

[profile.release]
Expand All @@ -19,12 +19,7 @@ serde_json = "1.0.116"
thiserror = "1.0.59"
anyhow = "1.0.83"
url = "2.5.0"
jpeg-decoder = "0.3.1"

[dependencies.image]
version = "0.25.1"
features = ["jpeg"]
default-features = false
rgb = "0.8.37"

[dependencies.native-tls]
version = "0.2.8"
Expand All @@ -34,14 +29,24 @@ optional = true
version = "5.0.0"
features = ["colors", "timestamps"]

[dependencies.onnxruntime]
git = "https://github.com/VOICEVOX/onnxruntime-rs.git"
branch = "master"

[dependencies.ureq]
version = "2.9.7"
default-features = false

[dependencies.zune-jpeg]
version = "0.4.11"
features = ["std"]
default-features = false

[dependencies.resize]
version = "0.8.4"
features = ["std"]
default-features = false

[dependencies.onnxruntime]
git = "https://github.com/VOICEVOX/onnxruntime-rs.git"
branch = "master"

[features]
default = ["native-tls"]
native-tls = ["ureq/native-tls", "dep:native-tls"]
Expand Down
119 changes: 84 additions & 35 deletions src/classifier.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,64 @@
use anyhow::Result;
use image::imageops::FilterType;
use image::EncodableLayout;
use once_cell::sync::Lazy;
use onnxruntime::environment::Environment;
use onnxruntime::session::NdArray;
use onnxruntime::{ndarray::Array, session::Session};
use resize::Pixel::RGB8;
use resize::Type::Lanczos3;
use rgb::FromSlice;
use std::sync::Mutex;
use zune_jpeg::JpegDecoder;

static ENVIRONMENT: Lazy<Environment> = Lazy::new(|| {
Environment::builder()
.build()
.expect("environment initialization exception!")
});

#[derive(PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum ModelChannels {
Gray = 1,
RGB = 3,
}

pub enum ResizeParam {
FixedWidth(usize),
FixedHeight(usize),
FixedSize(usize, usize),
}

impl ResizeParam {
pub fn get_param(&self, image_info: (usize, usize)) -> (usize, usize) {
let (origin_width, origin_height) = (image_info.0 as f32, image_info.1 as f32);

match self {
ResizeParam::FixedWidth(width) => {
let height = (origin_height * *width as f32 / origin_width).round() as usize;
(*width, height)
}
ResizeParam::FixedHeight(height) => {
let width = (origin_width * *height as f32 / origin_height).round() as usize;
(width, *height)
}
ResizeParam::FixedSize(width, height) => (*width, *height),
}
}
}

pub struct Classifier {
session: Mutex<Session<'static>>,
charset: Vec<String>,
resize_param: [i64; 2],
channels: usize,
resize_param: ResizeParam,
channels: ModelChannels,
}

impl Classifier {
pub fn new<M: AsRef<[u8]>>(
model: M,
charset: Vec<String>,
resize_param: [i64; 2],
channels: usize,
resize_param: ResizeParam,
channels: ModelChannels,
) -> Result<Self> {
let session = Mutex::new(
ENVIRONMENT
Expand All @@ -42,45 +75,37 @@ impl Classifier {
}

pub fn classification<I: AsRef<[u8]>>(&self, image: I) -> Result<String> {
let image = {
let image = image::load_from_memory(image.as_ref())?;
let resize_width = if self.resize_param[0] == -1 {
image.width() * self.resize_param[1] as u32 / image.height()
} else {
self.resize_param[0] as u32
};
image.resize(
resize_width,
self.resize_param[1] as u32,
FilterType::Lanczos3,
)
};
let (image, width, height) = self.resize_image(image)?;

let image_bytes = if self.channels == 1 {
EncodableLayout::as_bytes(image.to_luma8().as_ref()).to_vec()
} else {
image.to_rgb8().to_vec()
let image_bytes = match self.channels {
ModelChannels::Gray => {
let mut gray_image = vec![0; image.len() / 3];
for (i, pixels) in image.chunks(3).enumerate() {
let gray = 0.2989 * pixels[0] as f32
+ 0.5870 * pixels[1] as f32
+ 0.1140 * pixels[2] as f32;
gray_image[i] = gray as u8;
}
gray_image
}
ModelChannels::RGB => image,
};

let width = image.width() as usize;
let height = image.height() as usize;

let image_vec = Array::from_shape_vec((self.channels, height, width), image_bytes)?;

let tensor = Array::from_shape_fn(
(1, self.channels as usize, height, width),
|(_, c, i, j)| {
let now = image_vec[[c as usize, i, j]] as f32;
if self.channels == 1 {
((now / 255f32) - 0.456f32) / 0.224f32
let now = image_bytes[(i * width + j) * self.channels as usize + c] as f32;
let (mean, std) = if self.channels == ModelChannels::Gray {
(0.456f32, 0.224f32)
} else {
match c {
0 => ((now / 255f32) - 0.485f32) / 0.229f32,
1 => ((now / 255f32) - 0.456f32) / 0.224f32,
2 => ((now / 255f32) - 0.406f32) / 0.225f32,
0 => (0.485f32, 0.229f32),
1 => (0.456f32, 0.224f32),
2 => (0.406f32, 0.225f32),
_ => unreachable!(),
}
}
};
((now / 255f32) - mean) / std
},
);

Expand All @@ -102,4 +127,28 @@ impl Classifier {

Ok(classification)
}

fn resize_image<I: AsRef<[u8]>>(&self, image: I) -> Result<(Vec<u8>, usize, usize)> {
let mut decoder = JpegDecoder::new(image.as_ref());
let image = decoder.decode()?;
let image_info = decoder.info().unwrap();

let (resize_width, resize_height) = self
.resize_param
.get_param((image_info.width as usize, image_info.height as usize));

let mut resizer = resize::new(
image_info.width as usize,
image_info.height as usize,
resize_width,
resize_height,
RGB8,
Lanczos3,
)?;

let mut resized_image = vec![0; resize_width * resize_height as usize * 3];
resizer.resize(&image.as_rgb(), resized_image.as_rgb_mut())?;

Ok((resized_image, resize_width, resize_height as usize))
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ mod auth;
mod classifier;

pub use auth::Authenticator;
pub use classifier::Classifier;
pub use classifier::{Classifier, ModelChannels, ResizeParam};
Loading

0 comments on commit cc37367

Please sign in to comment.