Skip to content

Commit be16ec8

Browse files
committed
Rotation and data compression
1 parent abe2232 commit be16ec8

File tree

5 files changed

+77
-22
lines changed

5 files changed

+77
-22
lines changed

Cargo.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,20 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
image = "0.25.4"
10-
anyhow = "1.0.92"
11-
thiserror = "1.0.67"
9+
image = "0.25.5"
10+
anyhow = "1.0.93"
11+
thiserror = "2.0.1"
1212
rayon = {version = "1.10.0", features = []}
1313
clap = {version = "4.5.20", features = ["default"]}
1414
simple_logger = "5.0.0"
1515
log = "0.4.22"
1616
rand = {version = "0.8.5", features = ["default"]}
17-
imageproc = "0.25.0"
17+
imageproc = {version = "0.25.0", features = ["default", "rayon"]}
1818
serde = {version = "1.0.210", features = ["derive"]}
1919
serde_json = "1.0.68"
2020
strum = {version = "0.26.3", features = ["derive"]}
2121
chrono = "0.4.38"
2222
moka = {version = "0.12.8", features = ["default", "sync"] }
23-
imagequant = {version = "4.3.3", features = ["default"]}
2423

2524
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
2625
[profile.release]

src/generator/config.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ pub struct TargetGeneratorConfig {
1515
pub permit_collisions: bool,
1616
pub cache_size: u8, // TODO: currently only used for initial size, can't be changed
1717
pub worker_threads: u8,
18-
pub compress: bool
18+
pub compress: bool,
19+
pub do_random_rotation: bool,
1920
}
2021

2122
impl Default for TargetGeneratorConfig {
@@ -27,7 +28,8 @@ impl Default for TargetGeneratorConfig {
2728
permit_collisions: false,
2829
cache_size: 10,
2930
worker_threads: 15,
30-
compress: true
31+
compress: true,
32+
do_random_rotation: true
3133
}
3234
}
3335
}

src/generator/mod.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1+
use crate::backgrounds::BackgroundLoader;
2+
use crate::generator::coco::{BoundingBox, CocoCategoryInfo, CocoGenerator};
3+
use crate::generator::config::TargetGeneratorConfig;
4+
use crate::objects::ObjectManager;
5+
use error::GenerationError;
6+
use image::codecs::png::{CompressionType, PngEncoder};
7+
use image::imageops::FilterType;
8+
use image::{DynamicImage, ExtendedColorType, ImageEncoder, Rgba, RgbaImage};
9+
use log::{debug, trace, LevelFilter};
10+
use moka::sync::{Cache, CacheBuilder};
11+
use rand::{thread_rng, Rng};
112
use rayon::iter::ParallelIterator;
13+
use rayon::iter::IntoParallelIterator;
14+
use simple_logger::SimpleLogger;
215
use std::ops::RangeTo;
316
use std::path::{Path, PathBuf};
417
use std::sync::{Arc, Mutex};
518
use std::time::Instant;
6-
use image::{DynamicImage, ExtendedColorType, ImageEncoder, Rgba, RgbaImage};
7-
use image::codecs::png::{CompressionType, PngEncoder};
8-
use image::imageops::FilterType;
9-
use log::{debug, trace, LevelFilter};
10-
use rand::{thread_rng, Rng};
11-
use error::GenerationError;
1219
use util::STANDARD_PPM;
13-
use crate::backgrounds::BackgroundLoader;
14-
use crate::generator::coco::{BoundingBox, CocoCategoryInfo, CocoGenerator};
15-
use crate::generator::config::TargetGeneratorConfig;
16-
use crate::objects::{ObjectManager};
17-
use moka::sync::{Cache, CacheBuilder};
18-
use rayon::iter::{IntoParallelIterator};
19-
use simple_logger::SimpleLogger;
2020

2121
pub mod coco;
2222
pub mod error;
@@ -98,7 +98,18 @@ impl TargetGenerator {
9898
self.resized_cache.insert(format!("{}x{}_{}", obj_w, obj_h, obj.object_class), resized.clone());
9999
resized
100100
};
101+
102+
let resized = if self.config.do_random_rotation {
103+
let angle = thread_rng().gen_range(0.0..720.0); // random rotation including upside down
104+
// let rotated = util::rotate_image(&resized, angle);
105+
let rotated = util::rotate_90s(&resized, angle);
106+
rotated
107+
} else {
108+
resized // return as is if random rotation is not performed
109+
};
101110

111+
let (obj_w, obj_h) = (resized.width(), resized.height());
112+
102113
image::imageops::overlay(&mut image, &resized, x as i64, y as i64);
103114

104115
if self.config.visualize_bboxes {
@@ -208,7 +219,7 @@ pub fn test_generate_target() {
208219
#[test]
209220
#[ignore]
210221
pub fn test_generate_targets() {
211-
SimpleLogger::new().init().unwrap();
222+
SimpleLogger::new().with_level(LevelFilter::Debug).init().unwrap();
212223

213224
let mut tg = TargetGenerator::new("output", "backgrounds", "objects", "output/annotations.json").unwrap();
214225
tg.config.permit_duplicates = true;

src/generator/util.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
use crate::generator::error::GenerationError;
2+
use image::metadata::Orientation;
3+
use image::DynamicImage;
4+
use imageproc::drawing::Canvas;
5+
use imageproc::geometric_transformations::Interpolation;
6+
use std::cmp::max;
27

38
/// The standard Pixels Per Meter value that is used to calculate the size of objects in pixels.
49
/// In reality this value is dependent on the altitude of the drone and various properties of the
@@ -28,6 +33,37 @@ pub fn new_sizes(object_width: u32, object_height: u32, pixels_per_meter: f32, r
2833
Ok((new_width, new_height))
2934
}
3035

36+
pub fn rotate_90s(image: &DynamicImage, angle: f32) -> DynamicImage {
37+
let mut i = image.clone();
38+
39+
match (angle % 90.0) as i32 {
40+
1 => i.apply_orientation(Orientation::Rotate90),
41+
2 => i.apply_orientation(Orientation::Rotate180),
42+
3 => i.apply_orientation(Orientation::Rotate270),
43+
_ => (),
44+
}
45+
46+
i
47+
}
48+
49+
pub fn post_rotate_dimension(width: u32, height: u32, angle: f32) -> (u32, u32) {
50+
let (width, height) = (width as f32, height as f32);
51+
let angle = angle.to_radians();
52+
let (sin, cos) = angle.sin_cos();
53+
54+
let new_width = (width * cos + height * sin).abs() as u32;
55+
let new_height = (width * sin + height * cos).abs() as u32;
56+
57+
(new_width, new_height)
58+
}
59+
60+
// TODO: various problems with this at present. Cuts off the image mostly in multiple ways
61+
pub fn rotate_image(image: &DynamicImage, angle: f32) -> DynamicImage {
62+
//
63+
64+
todo!()
65+
}
66+
3167
pub fn is_image_type(path: &str) -> bool {
3268
path.ends_with(".png") || path.ends_with(".jpg") || path.ends_with(".jpeg")
3369
}
@@ -38,4 +74,11 @@ fn test_is_image_type() {
3874
assert_eq!(is_image_type("test.jpg"), true);
3975
assert_eq!(is_image_type("test.jpeg"), true);
4076
assert_eq!(is_image_type("test.txt"), false);
77+
}
78+
79+
#[test]
80+
fn test_resize_ratio() {
81+
assert_eq!(resize_ratio(1.0, 35.0), 35.0);
82+
assert_eq!(resize_ratio(1.0, 70.0), 70.0);
83+
assert_eq!(resize_ratio(1.0, 105.0), 105.0);
4184
}

src/objects/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl ObjectManager {
3535

3636
let object_details_file: ObjectDetailsFile = serde_json::from_str(&file)?;
3737

38-
let mut id = 0;
38+
let mut id = 1;
3939

4040
for entry in entries {
4141
let entry = entry?;

0 commit comments

Comments
 (0)