@@ -8,9 +8,11 @@ use imageproc::drawing::draw_text_mut;
88use log:: { debug, trace} ;
99use rand:: { Rng , thread_rng} ;
1010use simple_logger:: SimpleLogger ;
11+ use strum:: Display ;
12+ use thiserror:: Error ;
1113use crate :: backgrounds:: BackgroundLoader ;
12- use crate :: generator:: coco:: CocoGenerator ;
13- use crate :: objects:: ObjectManager ;
14+ use crate :: generator:: coco:: { CocoCategoryInfo , CocoGenerator } ;
15+ use crate :: objects:: { ObjectClass , ObjectManager } ;
1416
1517pub mod coco;
1618
@@ -33,31 +35,48 @@ impl TargetGenerator {
3335 backgrounds_path : background_path. as_ref ( ) . to_path_buf ( ) ,
3436 object_manager,
3537 background_loader : BackgroundLoader :: new ( background_path) ?,
36- coco_generator : CocoGenerator :: new ( annotations_path)
38+ coco_generator : CocoGenerator :: new ( annotations_path, ObjectClass :: categories ( ) )
3739 } )
3840 }
3941
40- pub fn generate_target ( & self , altitude : f32 , fov : f32 , iteration : u32 , pixels_per_meter : f32 ) -> Result < RgbaImage > {
42+ pub fn generate_target ( & mut self , pixels_per_meter : f32 ) -> Result < RgbaImage > {
4143 trace ! ( "Beginning to generate a target..." ) ;
4244
43- let mut background = self . background_loader . random ( ) . unwrap ( ) . clone ( ) ;
44- let ( w, h) = ( background. width ( ) , background. height ( ) ) ;
45+ let background = self . background_loader . random ( ) . unwrap ( ) ;
46+ let mut image = background. image . clone ( ) ;
47+ let ( w, h) = ( image. width ( ) , image. height ( ) ) ;
4548 let set = self . object_manager . generate_set ( 1 ) ?;
4649
50+ // add background image to coco here
51+ self . coco_generator . add_image ( w, h, background. filename . clone ( ) , background. date_captured . clone ( ) ) ;
52+
4753 for obj in set {
4854 let clone = & obj. dynamic_image . clone ( ) ;
4955 let ( obj_w, obj_h) = ( obj. dynamic_image . width ( ) , obj. dynamic_image . height ( ) ) ;
5056 let ( x, y) = ( thread_rng ( ) . gen_range ( 0 ..w - obj_w) , thread_rng ( ) . gen_range ( 0 ..h - obj_h) ) ;
5157 trace ! ( "Placing object at {}, {}" , x, y) ;
5258
53- let ( obj_w, obj_h) = new_sizes ( obj_w, obj_h, pixels_per_meter, obj. object_width_meters ) ;
59+ let ( obj_w, obj_h) = new_sizes ( obj_w, obj_h, pixels_per_meter, obj. object_width_meters ) ? ;
5460 debug ! ( "Resizing object to {}x{}" , obj_w, obj_h) ;
5561
5662 // overlay respects transparent pixels unlike copy_from
57- image:: imageops:: overlay ( & mut background, & clone. resize ( obj_w, obj_h, FilterType :: Gaussian ) , x as i64 , y as i64 ) ;
63+ image:: imageops:: overlay ( & mut image, & clone. resize ( obj_w, obj_h, FilterType :: Gaussian ) , x as i64 , y as i64 ) ;
64+
65+ // TODO: remove, both are top left
66+ //imageproc::drawing::draw_filled_circle_mut(&mut image, (x as i32, y as i32), 4, Rgba([255, 0, 0, 255]));
67+ //imageproc::drawing::draw_filled_circle_mut(&mut image, (0i32, 0i32), 8, Rgba([255, 0, 255, 255]));
68+ imageproc:: drawing:: draw_hollow_rect_mut ( & mut image, imageproc:: rect:: Rect :: at ( x as i32 , y as i32 ) . of_size ( obj_w, obj_h) , Rgba ( [ 0 , 255 , 0 , 255 ] ) ) ;
69+
70+ // add annotation to coco here
71+ self . coco_generator . add_annotation ( 0 , obj. object_class as u32 , 0 , vec ! [ ] , ( obj_w * obj_h) as f64 , coco:: BoundingBox {
72+ x,
73+ y,
74+ width : obj_w,
75+ height : obj_h,
76+ } ) ;
5877 }
5978
60- Ok ( background )
79+ Ok ( image )
6180 }
6281
6382 pub fn generate_targets < A : AsRef < Path > > ( & self , amount : u32 , range_to : RangeTo < u32 > , path : A ) -> Result < ( ) > {
@@ -69,6 +88,10 @@ impl TargetGenerator {
6988
7089 Ok ( ( ) )
7190 }
91+
92+ pub fn close ( & self ) {
93+ self . coco_generator . save ( ) ;
94+ }
7295}
7396
7497const STANDARD_PPM : f32 = 35.0 ;
@@ -84,47 +107,39 @@ fn resize_ratio(object_real_size: f32, pixels_per_meter: f32) -> f32 {
84107/// 1. Calculate the aspect ratio
85108/// 2. Calculate the width of the object in pixels that we expect based on the real width and the Pixels Per Meter value
86109/// 3. Calculate the height from this new width using the previously calculated aspect ratio
87- fn new_sizes ( object_width : u32 , object_height : u32 , pixels_per_meter : f32 , real_width : f32 ) -> ( u32 , u32 ) {
110+ fn new_sizes ( object_width : u32 , object_height : u32 , pixels_per_meter : f32 , real_width : f32 ) -> Result < ( u32 , u32 ) , GenerationError > {
88111 let ( w, h) = ( object_width as f32 , object_height as f32 ) ;
89112 let aspect_ratio = w / h;
90113 let new_width = resize_ratio ( real_width, pixels_per_meter) as u32 ;
91114 let new_height = ( new_width as f32 / aspect_ratio) as u32 ;
92115
93- ( new_width, new_height)
94- }
95-
96- fn degrees_to_radians ( degrees : f32 ) -> f32 {
97- degrees * std:: f32:: consts:: PI / 180.0
98- }
99-
100- // Calculate the fov in radians based on the image width, height and focal length
101- fn calculate_fov ( image_width : u32 , image_height : u32 , focal_length : f32 ) -> f32 {
102- 2.0 * ( 0.5 * image_width as f32 / focal_length) . atan ( )
103- }
104-
105- /// Calculate the width of the ground in meters based on camera position and field of view
106- fn calculate_ground_width ( altitude : f32 , fov : f32 ) -> f32 {
107- 2.0 * altitude * ( fov. to_radians ( ) / 2.0 ) . tan ( )
108- }
109-
110- fn meters_per_pixel ( image_width : u32 , ground_width : f32 ) -> f32 {
111- ground_width / image_width as f32
116+ if new_height == 0 || new_width == 0 {
117+ return Err ( GenerationError :: SizeError ) ;
118+ }
119+
120+ Ok ( ( new_width, new_height) )
112121}
113122
114- /// This gives you the expected size of an object in pixels, use this to calculate a ratio between
115- /// the expected and actual values. Then use that to scale up/down the object to the expected size
116- fn expected_object_size_pixels ( real_size : f32 , meters_per_pixel : f32 ) -> f32 {
117- real_size / meters_per_pixel
123+ #[ derive( Debug , Error ) ]
124+ pub enum GenerationError {
125+ #[ error( "Serde decoding or encoding error" ) ]
126+ SerdeError ( #[ from] serde_json:: Error ) ,
127+ #[ error( "IO error occurred while generating target" ) ]
128+ IOError ( #[ from] std:: io:: Error ) ,
129+ #[ error( "Calculated new sizes provided an invalid size" ) ]
130+ SizeError
118131}
119132
120133#[ test]
121134#[ ignore]
122135pub fn test_generate_target ( ) {
123136 SimpleLogger :: new ( ) . init ( ) . unwrap ( ) ;
124137
125- let tg = TargetGenerator :: new ( "output" , "backgrounds" , "objects" , "output" ) . unwrap ( ) ;
126- let b = tg. generate_target ( 22.8 , degrees_to_radians ( 35.0 ) , 1 , STANDARD_PPM ) . unwrap ( ) ;
138+ let mut tg = TargetGenerator :: new ( "output" , "backgrounds" , "objects" , "output/annotations.json " ) . unwrap ( ) ;
139+ let b = tg. generate_target ( STANDARD_PPM ) . unwrap ( ) ;
127140
128141 b. save ( "output_1.png" . to_string ( ) ) . unwrap ( ) ;
129142 debug ! ( "Saved generated target to output_1.png" ) ;
143+
144+ tg. close ( ) ;
130145}
0 commit comments