1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! voc-perturb -- Create new annotated image dataset via perturbation of existing ones.
//!
//! Annotation of image data is time-consuming, this crate is a lazy person's tool for generating more annotated data
//! with as little effort as possible. Basically, all you need to do is
//!
//! ```
//! voc-perturb input_dataset_path output_dataset_name
//! ```
//!
extern crate quick_xml;
extern crate image;
extern crate imageproc;
extern crate rand;


use quick_xml::events::BytesText;
use std::error::Error;
use std::path::Path;
use quick_xml::writer::Writer;
use quick_xml::reader::Reader;
use quick_xml::events::Event;
use std::io::Cursor;
use std::fs::File;
use std::io::Write;
use parser_state::{ParserState};

pub mod parser_state;
pub mod file_mapping;

/// Modify an input xml annotation via a custom modifier function, write to the output xml file.
pub fn bbox_modify<F>(input_xml: &Path, output_xml: &Path, modifier: F) -> Result<(), Box<Error>>
    where F: Fn(&ParserState, i32) -> i32
{
    let mut writer = Writer::new(Cursor::new(Vec::new()));
    let mut reader = Reader::from_file(input_xml)
        .expect(&format!("Failed to read xml file"));
    reader.trim_text(true);
    let mut parser_state = ParserState::new();
    let mut buf = Vec::new();
    // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
    loop {
        if parser_state.is_interesting() {
            match reader.read_event(&mut buf) {
                Ok(Event::Text(bytes_text)) => {
                    let text = bytes_text
                        .unescape_and_decode(&reader)
                        .expect("Failed to convert bytes to string");
                    let coordinate: i32 = text
                        .parse()
                        .expect(&format!("Failed to parse this: {}, are you sure it's a number?", &text));
                    let new_value_string = format!("{}", modifier(&parser_state, coordinate));
                    let text_event = Event::Text(BytesText::borrowed(new_value_string.as_bytes()));
                    writer.write_event(text_event).expect("Failed to write xml event.");
                    parser_state.set_no_interest();
                    continue;
                }
                _ => (),
            }
        }
        match reader.read_event(&mut buf) {
            Err(error) => return Err(Box::new(error)),
            Ok(Event::Eof) => break,
            Ok(Event::Start(elem)) => {
                parser_state.mutate_by_tag_name(elem.name());
                writer.write_event(Event::Start(elem)).expect("Failed to write xml event.");
            }
            Ok(event) => {
                writer.write_event(event).expect("Failed to write xml event.");
            }
        }
        buf.clear();
    }
    let result = writer.into_inner().into_inner();
    #[cfg(feature = "debug")]
        println!("{:?}", output_xml);
    let mut file = File::create(output_xml).expect("Failed to create output.xml");
    file.write_all(&result).expect("Failed to write xml output.");
    Ok(())
}


pub fn translation_lambda(delta_x: i32, delta_y: i32) -> Box<Fn(&ParserState, i32) -> i32> {
    Box::new(move|ps, v| {
        match ps {
            &ParserState::Xmin => v + delta_x,
            &ParserState::Ymin => v + delta_y,
            &ParserState::Xmax => v + delta_x,
            &ParserState::Ymax => v + delta_y,
            _ => v,
        }
    })
}