-
Notifications
You must be signed in to change notification settings - Fork 35
/
image_demo.rs
121 lines (101 loc) · 3.72 KB
/
image_demo.rs
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// This file is part of the open-source port of SeetaFace engine, which originally includes three modules:
// SeetaFace Detection, SeetaFace Alignment, and SeetaFace Identification.
//
// This file is part of the SeetaFace Detection module, containing codes implementing the face detection method described in the following paper:
//
// Funnel-structured cascade for multi-view face detection with alignment awareness,
// Shuzhe Wu, Meina Kan, Zhenliang He, Shiguang Shan, Xilin Chen.
// In Neurocomputing (under review)
//
// Copyright (C) 2016, Visual Information Processing and Learning (VIPL) group,
// Institute of Computing Technology, Chinese Academy of Sciences, Beijing, China.
//
// As an open-source face recognition engine: you can redistribute SeetaFace source codes
// and/or modify it under the terms of the BSD 2-Clause License.
//
// You should have received a copy of the BSD 2-Clause License along with the software.
// If not, see < https://opensource.org/licenses/BSD-2-Clause>.
use std::env::Args;
use std::time::{Duration, Instant};
use image::{DynamicImage, GrayImage, Rgb};
use imageproc::drawing::draw_hollow_rect_mut;
use imageproc::rect::Rect;
use rustface::{Detector, FaceInfo, ImageData};
const OUTPUT_FILE: &str = "test.png";
fn main() {
let options = match Options::parse(std::env::args()) {
Ok(options) => options,
Err(message) => {
println!("Failed to parse program arguments: {}", message);
std::process::exit(1)
}
};
let mut detector = match rustface::create_detector(options.model_path()) {
Ok(detector) => detector,
Err(error) => {
println!("Failed to create detector: {}", error);
std::process::exit(1)
}
};
detector.set_min_face_size(20);
detector.set_score_thresh(2.0);
detector.set_pyramid_scale_factor(0.8);
detector.set_slide_window_step(4, 4);
let image: DynamicImage = match image::open(options.image_path()) {
Ok(image) => image,
Err(message) => {
println!("Failed to read image: {}", message);
std::process::exit(1)
}
};
let mut rgb = image.to_rgb8();
let faces = detect_faces(&mut *detector, &image.to_luma8());
for face in faces {
let bbox = face.bbox();
let rect = Rect::at(bbox.x(), bbox.y()).of_size(bbox.width(), bbox.height());
draw_hollow_rect_mut(&mut rgb, rect, Rgb([255, 0, 0]));
}
match rgb.save(OUTPUT_FILE) {
Ok(_) => println!("Saved result to {}", OUTPUT_FILE),
Err(message) => println!("Failed to save result to a file. Reason: {}", message),
}
}
fn detect_faces(detector: &mut dyn Detector, gray: &GrayImage) -> Vec<FaceInfo> {
let (width, height) = gray.dimensions();
let image = ImageData::new(gray, width, height);
let now = Instant::now();
let faces = detector.detect(&image);
println!(
"Found {} faces in {} ms",
faces.len(),
get_millis(now.elapsed())
);
faces
}
fn get_millis(duration: Duration) -> u64 {
duration.as_secs() * 1000u64 + u64::from(duration.subsec_millis())
}
struct Options {
image_path: String,
model_path: String,
}
impl Options {
fn parse(args: Args) -> Result<Self, String> {
let args: Vec<String> = args.into_iter().collect();
if args.len() != 3 {
return Err(format!("Usage: {} <model-path> <image-path>", args[0]));
}
let model_path = args[1].clone();
let image_path = args[2].clone();
Ok(Options {
image_path,
model_path,
})
}
fn image_path(&self) -> &str {
&self.image_path[..]
}
fn model_path(&self) -> &str {
&self.model_path[..]
}
}