Skip to content

Commit 6635fa0

Browse files
committed
Decent object size adjuster
1 parent 94cebe1 commit 6635fa0

File tree

3 files changed

+79
-21
lines changed

3 files changed

+79
-21
lines changed
File renamed without changes.

src/generator/mod.rs

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use std::ops::RangeTo;
22
use std::path::{Path, PathBuf};
33
use std::time::Instant;
44
use anyhow::Result;
5-
use image::{ImageBuffer, Rgba, RgbaImage};
5+
use image::{GenericImage, ImageBuffer, Rgba, RgbaImage};
6+
use image::imageops::FilterType;
67
use imageproc::drawing::draw_text_mut;
78
use log::{debug, trace};
89
use rand::{Rng, thread_rng};
@@ -13,33 +14,59 @@ use crate::objects::ObjectManager;
1314
pub struct TargetGenerator {
1415
output: PathBuf,
1516
backgrounds_path: PathBuf,
16-
pub shape_manager: ObjectManager,
17+
pub object_manager: ObjectManager,
1718
background_loader: BackgroundLoader,
1819
}
1920

2021
impl TargetGenerator {
2122
pub fn new<Q: AsRef<Path>>(output: Q, background_path: Q, objects_path: Q) -> Result<Self> {
2223

24+
let mut object_manager = ObjectManager::new(objects_path);
25+
object_manager.load_objects()?;
26+
2327
Ok(Self {
2428
output: output.as_ref().to_path_buf(),
2529
backgrounds_path: background_path.as_ref().to_path_buf(),
26-
shape_manager: ObjectManager::new(objects_path),
30+
object_manager,
2731
background_loader: BackgroundLoader::new(background_path)?,
2832
})
2933
}
3034

31-
pub fn generate_target(&self, altitude: f32) -> Result<()> {
32-
33-
debug!("Beginning to generate a target...");
35+
pub fn generate_target(&self, altitude: f32, fov: f32, iteration: u32) -> Result<()> {
36+
trace!("Beginning to generate a target...");
3437

3538
let mut background = self.background_loader.random().unwrap().clone();
3639
let (w, h) = (background.width(), background.height());
37-
38-
39-
40-
41-
42-
background.save("output.png")?;
40+
let set = self.object_manager.generate_set(1)?;
41+
42+
let ground_width = calculate_ground_width(altitude, fov);
43+
let meters_per_pixel = meters_per_pixel(w, ground_width);
44+
45+
for obj in set {
46+
let clone = &obj.dynamic_image.clone();
47+
let (obj_w, obj_h) = (obj.dynamic_image.width(), obj.dynamic_image.height());
48+
let (x, y) = (thread_rng().gen_range(0..w - obj_w), thread_rng().gen_range(0..h - obj_h));
49+
trace!("Placing object at {}, {}", x, y);
50+
/*let expected_size = expected_object_size_pixels(obj.object_width_meters, meters_per_pixel);
51+
52+
let aspect_ratio = obj_w as f32 / obj_h as f32;
53+
54+
debug!("Resizing object to {}x{}", expected_size as u32, (expected_size / aspect_ratio) as u32); //TODO: too big
55+
56+
background.copy_from(&clone.resize(expected_size as u32, (expected_size / aspect_ratio) as u32, FilterType::Gaussian), x, y)?;*/
57+
58+
let adjusted = resize_ratio(obj.object_width_meters, METER_CONST);
59+
debug!("Width: {}, Height: {}", obj_w, obj_h);
60+
let aspect_ratio = obj_w as f32 / obj_h as f32;
61+
let (obj_w, obj_h) = (adjusted as u32, (adjusted / aspect_ratio) as u32);
62+
63+
debug!("Resizing object to {}x{}", obj_w, obj_h); //TODO: too big
64+
65+
background.copy_from(&clone.resize(obj_w, obj_h, FilterType::Gaussian), x, y)?;
66+
}
67+
68+
background.save(format!("output_{iteration}.png"))?;
69+
debug!("Saved generated target to output_{iteration}.png");
4370

4471
Ok(())
4572
}
@@ -55,6 +82,26 @@ impl TargetGenerator {
5582
}
5683
}
5784

85+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
86+
pub struct BoundingBox {
87+
pub x: u32,
88+
pub y: u32,
89+
pub width: u32,
90+
pub height: u32,
91+
}
92+
93+
const METER_CONST: f32 = 35.0;
94+
95+
fn resize_ratio(object_real_size: f32, pixels_per_meter: f32) -> f32 {
96+
debug!("Real size: {}, Pixels per meter: {}", object_real_size, pixels_per_meter);
97+
object_real_size * pixels_per_meter
98+
}
99+
100+
fn degrees_to_radians(degrees: f32) -> f32 {
101+
degrees * std::f32::consts::PI / 180.0
102+
}
103+
104+
// Calculate the fov in radians based on the image width, height and focal length
58105
fn calculate_fov(image_width: u32, image_height: u32, focal_length: f32) -> f32 {
59106
2.0 * (0.5 * image_width as f32 / focal_length).atan()
60107
}
@@ -79,6 +126,6 @@ fn expected_object_size_pixels(real_size: f32, meters_per_pixel: f32) -> f32 {
79126
pub fn test_generate_target() {
80127
SimpleLogger::new().init().unwrap();
81128

82-
let tg = TargetGenerator::new("output", "backgrounds", "shapes").unwrap();
83-
tg.generate_target( 22.8).unwrap();
129+
let tg = TargetGenerator::new("output", "backgrounds", "objects").unwrap();
130+
tg.generate_target( 22.8, degrees_to_radians(35.0), 1).unwrap();
84131
}

src/objects/mod.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use serde::{Deserialize, Serialize};
1010
pub struct ObjectManager {
1111
path_buf: PathBuf,
1212
objects: Vec<Object>,
13-
1413
}
1514

1615
impl ObjectManager {
@@ -21,9 +20,11 @@ impl ObjectManager {
2120
}
2221
}
2322

23+
/// Load training objects into the buffer
2424
pub fn load_objects(&mut self) -> Result<()> {
2525
let mut entries = std::fs::read_dir(&self.path_buf)?;
2626

27+
// retrieve objects.json file that holds all info about our training objects
2728
let out = entries.find(|entry| {
2829
let entry = entry.as_ref().unwrap().path();
2930

@@ -66,6 +67,9 @@ impl ObjectManager {
6667
Ok(())
6768
}
6869

70+
/// Generate a set of training objects a random that could be used to generate a target
71+
/// [amount] is the maximum number of objects to return
72+
/// Returns a set of objects that will contain no duplicates
6973
pub fn generate_set(&self, amount: u32) -> Result<HashSet<&Object>> {
7074
let mut rng = rand::thread_rng();
7175
let mut set = HashSet::new();
@@ -74,21 +78,26 @@ impl ObjectManager {
7478
return Err(anyhow!("Amount of objects requested is greater than the amount of objects available"));
7579
}
7680

77-
while set.len() < amount as usize {
78-
let object = self.objects.choose(&mut rng).unwrap();
81+
self.objects.choose_multiple(&mut rng, amount as usize).for_each(|object| {
7982
set.insert(object);
80-
}
83+
});
8184

8285
Ok(set)
8386
}
8487
}
8588

86-
#[derive(Debug)]
89+
#[derive(Debug, Clone)]
8790
pub struct Object {
8891
object_class: ObjectClass,
8992
id: u16,
90-
dynamic_image: DynamicImage,
91-
object_width_meters: f32,
93+
pub(crate) dynamic_image: DynamicImage,
94+
pub(crate) object_width_meters: f32,
95+
}
96+
97+
impl Object {
98+
pub fn to_rgba_image(&self) -> RgbaImage {
99+
self.dynamic_image.to_rgba8()
100+
}
92101
}
93102

94103
impl PartialEq for Object {
@@ -122,11 +131,13 @@ impl ObjectClass {
122131
}
123132
}
124133

134+
/// Represents the object details file that holds all the information about the training objects
125135
#[derive(Debug, PartialEq, Serialize, Deserialize)]
126136
pub struct ObjectDetailsFile {
127137
map: HashMap<String, ObjectDetails>
128138
}
129139

140+
/// All details about a training object
130141
#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)]
131142
pub struct ObjectDetails {
132143
ground_width: f32

0 commit comments

Comments
 (0)