Fixes compilation, horizontal flip for DCT. Adds PR calculation.
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
DCT is now somewhat invariant to horizontal flips. First version of precision recall variable is calculated.
This commit is contained in:
+100
-4
@@ -3,6 +3,7 @@
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use crate::descriptors::Descriptor;
|
||||
use crate::mutators::get_all_mutators;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::fmt;
|
||||
@@ -16,10 +17,19 @@ pub enum SaveError {
|
||||
File,
|
||||
}
|
||||
|
||||
/// Struct for calculating Recall-Precision per mutation
|
||||
struct PRStats {
|
||||
true_positives: u64,
|
||||
false_positives: u64,
|
||||
false_negatives: u64,
|
||||
tag: String,
|
||||
name: String
|
||||
}
|
||||
|
||||
/// Uses a hashmap to map descriptors to buckets of files.
|
||||
/// Also keeps a BK-tree for quick distance ranking
|
||||
pub struct DescriptorStore {
|
||||
descriptor: Box<dyn Descriptor>,
|
||||
pub descriptor: Box<dyn Descriptor>,
|
||||
/// Main hashmap that maps descriptors to buckets of filenames
|
||||
map: HashMap<u64, Vec<String>>,
|
||||
|
||||
@@ -71,6 +81,22 @@ impl DescriptorStore {
|
||||
self
|
||||
}
|
||||
|
||||
/// Stores non-mutated images in a hashset for quick membership checks
|
||||
pub fn see(&mut self, value: String) {
|
||||
if !value.starts_with("mut.") {
|
||||
match &mut self.seen {
|
||||
Some(set) => {
|
||||
set.insert(value);
|
||||
},
|
||||
None => {
|
||||
let mut seen: HashSet<String> = HashSet::new();
|
||||
seen.insert(value);
|
||||
self.seen = Some(seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&self) -> Result<(), SaveError> {
|
||||
let serialized: Vec<u8> = match rmp_serde::to_vec(&self.map) {
|
||||
Ok(value) => value,
|
||||
@@ -111,13 +137,14 @@ impl DescriptorStore {
|
||||
Some(b) => {
|
||||
let mut n = b.clone();
|
||||
if !n.contains(&value) {
|
||||
n.push(value);
|
||||
n.push(value.clone());
|
||||
}
|
||||
n
|
||||
},
|
||||
None => vec![value],
|
||||
None => vec![value.clone()],
|
||||
};
|
||||
self.map.insert(*key, bucket);
|
||||
self.see(value);
|
||||
self.bktree.insert(*key);
|
||||
}
|
||||
|
||||
@@ -152,7 +179,7 @@ impl DescriptorStore {
|
||||
self.save().expect("error");
|
||||
}
|
||||
// We have done our bulk loading, so we can unset our hashset cache:
|
||||
self.seen = None;
|
||||
//self.seen = None;
|
||||
}
|
||||
|
||||
pub fn store(&mut self, img: &DynamicImage, name: String) {
|
||||
@@ -230,6 +257,75 @@ impl DescriptorStore {
|
||||
}
|
||||
print!("DescriptorStore:\n{}Total: {}", output, self.map.len())
|
||||
}
|
||||
|
||||
pub fn print_stats(&self) {
|
||||
let mut mutator_stats = Vec::new();
|
||||
for mutator in get_all_mutators() {
|
||||
mutator_stats.push(
|
||||
PRStats {
|
||||
true_positives: 0,
|
||||
false_positives: 0,
|
||||
false_negatives: 0,
|
||||
tag: "mut".to_string() + &mutator.tag(),
|
||||
name: mutator.info(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let set = self.seen.clone().unwrap();
|
||||
|
||||
for image in set.iter() {
|
||||
debug!("Checking {}", image);
|
||||
|
||||
// find the bucket this image is in
|
||||
for (key, bucket) in self.map.iter() {
|
||||
if bucket.contains(&image) {
|
||||
debug!("{} found in bucket {}", image, key);
|
||||
for value in bucket {
|
||||
if value != image && value.ends_with(image) {
|
||||
// Mutated version of image in same bucket
|
||||
for mutator in &mut mutator_stats {
|
||||
mutator.false_negatives += 1;
|
||||
if value.starts_with(&mutator.tag) {
|
||||
mutator.true_positives += 1;
|
||||
mutator.false_negatives -= 1;
|
||||
}
|
||||
}
|
||||
debug!("We matched {} to {}!", value, image);
|
||||
} else if value != image {
|
||||
// Other image in same bucket
|
||||
//false_positives += 1;
|
||||
for mutator in &mut mutator_stats {
|
||||
if value.starts_with(&mutator.tag) {
|
||||
mutator.false_positives += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
for mutator in &mut mutator_stats {
|
||||
// println!("\t{} true positives: {}", mutator.name, mutator.true_positives);
|
||||
// println!("\t{} false positives: {}", mutator.name, mutator.false_positives);
|
||||
println!(
|
||||
"\t{} Precision: {:.3}", mutator.name,
|
||||
mutator.true_positives as f64 /
|
||||
(mutator.true_positives + mutator.false_positives) as f64
|
||||
);
|
||||
println!(
|
||||
"\t{} Recall: {:.3}", mutator.name,
|
||||
mutator.true_positives as f64 /
|
||||
//(mutator.true_positives + mutator.false_negatives) as f64
|
||||
set.len() as f64
|
||||
);
|
||||
}
|
||||
//println!("Images processed: {}", set.len())
|
||||
// println!("{} true positives", true_positives);
|
||||
// println!("{} false positives", false_positives);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DescriptorStore {
|
||||
|
||||
Reference in New Issue
Block a user